一、插入类算法

排序算法的稳定性:两个大小相等的元素排序前后的相对位置不变。{31,32,2} 排序后{2,31,32},则称排序算法稳定

通用类:

public class Common {
public static int[] a = {48,62,35,77,55,14,35,98};
public static void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
public static void print(int[] a) {
for(int num : a) {
System.out.print(num + " ");
}
System.out.println();
}
}

1、插入排序

算法思想:将第i个元素插入到前i-1个已排好序的序列中。即要从i=2开始插入元素,默认第一个元素在已排好序的子集之中。

public static void insertSort(int[] a) {
for(int i = 1; i < a.length; i++) {
for(int j = i - 1; j>=0 ; j--) {
if(a[j+1]<a[j]) Common.swap(a, j+1, j);
else break;
}
}
}

对插入排序就是这么简单,想这么简单的代码面试时是不可能考的,主要理解算法的思想,例如考一个对链表进行插入排序。

时间复杂度:最好的情况待排序序列已经有序O(n),最差的情况O(n2)。

空间复杂度:O(1)

稳定性:稳定

2、希尔排序

算法思想:希尔排序是对插入排序的改进,插入排序在待排序序列基本有序的情况下效率最高,希尔排序会进行组内插入排序,使得待排序数组基本有序,在进行插入排序。先以间隔为d元素划分一组,将集合划分成d组子集,例如{1,2,3,4,5,6},d=2,则第一组{1,3,5},第二组{2,4,6};即下标i+k*d的都是一组。d的值一般取d = n/3 + 1,每次排序d缩小为原来的1/3。

public static void shellSort(int[] a) {
int d = a.length/3 + 1;
while(d >= 1) {
for(int i = d; i < a.length; i++) {
for(int j = i - d; j >=0 ; j = j-d) {
if(a[j+d]<a[j]) Common.swap(a, j+d, j);
else break;
}
}
d = d/3;
}
}

时间复杂度:O(n1.5)

空间复杂度:O(1)

稳定性:不稳定

二、交换类排序

1、冒泡排序

算法思想:每一轮和相邻元素比较,以第一个元素为开始,当前元素大于后一个元素则交换位置,当前元素小于后面元素则不动,这样没一轮都可以上浮一个最大的元素,最多进行n-1轮。

public static void bubbleSort(int[] a) {
boolean flag = true;
for(int i = 1; i <= a.length-1&&flag; i++) {
flag = false;
for(int j = 0; j < a.length - i; j++) {
if(a[j]>a[j+1]) {
Common.swap(a, j, j+1);
flag = true;
}
}
}
}

时间复杂度:最好的情况下,待排序列有序O(n);最坏的情况下,倒序O(n2)

空间复杂度:O(1)

稳定性:稳定

2、快速排序

这个有点重要哦,Java类库里对基本类型的排序基本上都是使用快速排序,对象类型的元素都使用归并排序。

算法思想:基于分治法的思想

首先,进行一趟快排,选择第一个元素作为枢轴元素x,目的将小于x的移到x的左边,大于等于x的移到x的右边。

①low从左向右扫描,直到a[low] >= x,交换a[low]与a[high]

②high从右向左扫描,直到a[high] > x,交换a[low]与a[high]

③将x与a[high]交换

记住low永远指向大于等于x的元素,high永远指向小于x的元素

然后使用分治法,对x左边和右边元素分别进行快排。

public static void sort(int[] a, int low, int high) {
if(low>=high) return;
int l = low+1;
int h = high;
while(l<=h) {
if(a[l]>=a[low]) Common.swap(a, l, h--);
else l++;
}
Common.swap(a, low, h);
sort(a, low, h-1);
sort(a, h+1, high);
}

时间复杂度:一般情况O(nlogn),最坏的情况待排序列有序O(n2)

空间复杂度:使用了递归栈O(logn)

稳定性:不稳定

3、三向切分排序

这是快速排序的演变版本,多了一个指针维护与枢轴相等的元素

public static void sort1(int[] a, int low, int high) {
if(low>=high) return;
int l = low;
int i = low+1;
int h = high;
while(i<=h) {
if(a[i]>a[low]) Common.swap(a, i, h--);
else if(a[i]<a[low]) Common.swap(a, i++, l++);
else i++;
}
sort1(a,low,l-1);
sort1(a,h+1,high);
}

时间复杂度:O(nlogn)

空间复杂度:O(logn)

稳定性:不稳定

4、利用一趟快排寻找第K大或第K小元素

private static int partition(int[] a, int low, int high) {
int l = low+1;
int h = high;
while(l<=h) {
if(a[l]>=a[low]) Common.swap(a, l, h--);
else l++;
}
Common.swap(a, low, h);
return h;
}
public static int select(int[] a, int k) {
int l = 0;
int h = a.length-1;
while(l<h) {
int min = partition(a,l,h);
if(min >= k-1) h = min;
else l = min+1;
}
return a[h];
}

时间复杂度:O(n)排序算法中能够在线性时间复杂度内解决问题的只有切分快速选择和桶排序了。

空间复杂度:O(1)

三、归并排序

这个也重要哦,因为有点难所以就很重要,面试的时候总不是拿几个大家都会的简单题考吧,考的一定是难题。

算法思想:基于分治法的算法思想

合并两个排好序的子集,然后递归调用,看程序啪

public static void sort(int[] a, int low, int high) {
if(low>=high) return;
int mid = (low + high) >>> 1;
int l1 = low;
int l2 = mid + 1;
int i = low;
sort(a,low,mid);
sort(a,mid+1,high);
int[] temp = Arrays.copyOf(a, a.length);
while(l1<=mid&&l2<=high) {
if(temp[l1]<=temp[l2]) a[i++] = temp[l1++];
else a[i++] = temp[l2++];
}
while(l1<=mid) {
a[i++] = temp[l1++];
}
while(l2<=high) {
a[i++] = temp[l2++];
}
}

时间复杂度:O(nlogn)

空间复杂度:O(n)

稳定性:稳定

四、堆排序

堆排序真的是很少用,排序重点应该在排序上面,而堆排序重点在建堆上。

堆排序最主要的操作是重建堆

//重建堆
private static void sift(int[] a, int start, int end) {
int i = start;//始终指向当前根
int j = 2*i;//指向当前根的左孩子
int x = a[start];
while(j<=end) {
//有右孩子,且右孩子值大,搜索右子树
if(j+1<=end&&a[j+1]>a[j]) j++;
if(x>=a[j]) break;
else {
Common.swap(a, i, j);
i = j;
j = 2*i;
}
}
}

创建堆自下而上,从第一个非叶子节点开始创建堆

//创建堆
public static void create(int[] a) {
int i = (a.length-1)/2;
for(; i >= 1; i--) {
sift(a,i,a.length-1);
}
}

堆排序

public static void sort(int[] a) {
create(a);
for(int i = a.length-1; i > 1; i--) {
Common.swap(a, 1, i);
sift(a,1,i-1);
}
}

时间复杂度:O(nlogn)

空间复杂度:O(1)

考察形式:215. 数组中的第K个最大元素

public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> pq = new PriorityQueue<>();
for(int num : nums) {
pq.add(num);
if(pq.size() > k) pq.poll();
}
return pq.peek();
}

使用优先级队列PriorityQueue创建一个小顶堆,确保队列中只有K各元素,每次poll都是去掉小的元素,剩下k就是k个最大的元素,队头就是我们要找的答案。

当然我们也可以使用切分选择算法,但是都没有Java类库中自带的排序算法高效。

五、选择排序

算法思想:从剩下的元素集合A中选取一个最小的和A中的第一个元素交换,直至有序

public static void sort(int[] a) {
for(int i = 0; i < a.length; i++) {
int k = i;
for(int j = i; j < a.length; j++) {
if(a[j]<a[k]) k = j;
}
if(k!=i) Common.swap(a, i, k);
} }

时间复杂度:O(n2)

空间复杂度:O(1)

稳定性:不稳定

六、桶排序

算法思想:用空间换时间,使用了哈希表。

看个题就明白了

347. 前 K 个高频元素

public List<Integer> topKFrequent(int[] nums, int k) {
HashMap<Integer,Integer> hash = new HashMap<>();
LinkedList<Integer> ans = new LinkedList<>();
for(int num : nums) {
int v = hash.containsKey(num) == true ? hash.get(num) + 1 : 1;
hash.put(num,v);
}
LinkedList<Integer>[] buckets = new LinkedList[nums.length+1];
for(Map.Entry e : hash.entrySet()) {
int f = (Integer)e.getValue();
if(buckets[f] == null) buckets[f] = new LinkedList<Integer>();
buckets[f].add((Integer)e.getKey());
}
for(int i = nums.length; i >= 1 ; i--) {
if(buckets[i]==null) continue;
while(k > 0 && buckets[i].size() > 0) {
ans.add(buckets[i].poll());
k--;
}
}
return ans;
}

使用hash表统计频率,以频率为数组下标放入桶中,这样就利用数组按照频率自然的由低到高排序

时间复杂度:只有O(n)哦,要是排序题中出现线性时间复杂度,就妥妥的桶排序。

空间复杂度:O(n)

七、总结

排序算法分析表
类别 算法 稳定性 时间复杂度  空间复杂度      说明    
插入类 插入排序 O(n)~O(n2) O(1)  
希尔排序 × O(n1.5) O(1) 对直接插入排序的改进
 交换类  冒泡排序 O(n)~O(n2) O(1)  
快速排序 × O(nlogn)~O(n2) O(logn)  对冒泡的改进 
三向快排 × O(nlogn) O(logn) 适用于有重复元素的
 选择类  选择排序  ×  O(n2) O(1)   
堆排序  × O(nlogn)  O(1)  对选择排序的改进 
 其他类 归并排序  O(nlogn)   O(n)  
桶排序  × O(n)  O(n)  唯一线性时间 

1、稳定的算法,只有插入排序、冒泡排序、归并排序

2、时间复杂度稳定在O(nlog)常用的就是快排和归并

3、桶排序,唯一的线性时间

排序算法大汇总 Java实现的更多相关文章

  1. 排序算法总结(基于Java实现)

    前言 下面会讲到一些简单的排序算法(均基于java实现),并给出实现和效率分析. 使用的基类如下: 注意:抽象函数应为public的,我就不改代码了 public abstract class Sor ...

  2. 常见排序算法题(java版)

    常见排序算法题(java版) //插入排序:   package org.rut.util.algorithm.support;   import org.rut.util.algorithm.Sor ...

  3. 八大排序算法总结与java实现(转)

    八大排序算法总结与Java实现 原文链接: 八大排序算法总结与java实现 - iTimeTraveler 概述 直接插入排序 希尔排序 简单选择排序 堆排序 冒泡排序 快速排序 归并排序 基数排序 ...

  4. 第二章:排序算法 及其他 Java代码实现

    目录 第二章:排序算法 及其他 Java代码实现 插入排序 归并排序 选择排序算法 冒泡排序 查找算法 习题 2.3.7 第二章:排序算法 及其他 Java代码实现 --算法导论(Introducti ...

  5. 动画展现十大经典排序算法(附Java代码)

    0.算法概述 0.1 算法分类 十种常见排序算法可以分为两大类: 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序. 非比较类排序: ...

  6. 排序算法总结及Java实现

    1. 整体介绍 分类 排序大的分类可以分为两种,内排序和外排序.在排序过程中,全部记录存放在内存,则称为内排序,如果排序过程中需要使用外存,则称为外排序.主要需要理解的都是内排序算法: 内排序可以分为 ...

  7. 常见排序算法总结(java版)

    一.冒泡排序 1.原理:相邻元素两两比较,大的往后放.第一次完毕,最大值在最大索引处. 即使用相邻的两个元素一次比价,依次将最大的数放到最后. 2.代码: public static void bub ...

  8. 排序算法之冒泡排序Java实现

    排序算法之冒泡排序 舞蹈演示排序: 冒泡排序: http://t.cn/hrf58M 希尔排序:http://t.cn/hrosvb  选择排序:http://t.cn/hros6e  插入排序:ht ...

  9. 排序算法代码实现-Java

    前言 为了准备面试,从2月开始将排序算法认认真真得刷了一遍,通过看书看视频,实践打代码,还有一部分的leetcode题,自己感觉也有点进步,将笔记记录总结发出来. 冒泡排序 该排序就是一种像泡泡浮到水 ...

随机推荐

  1. Java 面试题 四

    1.序列化 File 类的介绍:http://www.cnblogs.com/ysocean/p/6851878.html Java IO 流的分类介绍:http://www.cnblogs.com/ ...

  2. 关于Map的问题

    关于Map的问题主要有: (1)什么是散列表? (2)怎么实现一个散列表? (3)java中HashMap实现方式的演进? (4)HashMap的容量有什么特点? (5)HashMap是怎么进行扩容的 ...

  3. [51nod1789] 跑得比谁都快

    题面 题解 设\(f[i]\)为根节点到\(i\)的最小耗时 设\(S\)为\(i\)的祖先集合, 可以得到 \[ f[i] = min(f[j] + (i - j)^p),j \in S \] 对于 ...

  4. C#_实现Hello Word!

    1:代码如下: using System;//using关键字可以引用MIcrosoft.NET框架类库中的现有资源. //System命名空间提供了对构建应用程序所需的所有系统功能的访问,包括本例中 ...

  5. Linux编程之recvmsg和sendmsg函数

    recvmsg 和 sendmsg 函数 #include <sys/types.h> #include <sys/socket.h> ssize_t send(int soc ...

  6. LeetCode 200. 岛屿的个数(Number of Islands)

    题目描述 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量.一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的.你可以假设网格的四个边均被水包围. 示例 1 ...

  7. 括号序列模型--序列dp--U86873 小Y的精灵国机房之旅

    括号序列模型及解法 >Codeforces314E◦给定一个长度为n的仅包含左右括号和问号的字符串,将问号变成左括号或右括号使得该括号序列合法,求方案总数.◦例如(())与()()都是合法的括号 ...

  8. Go项目的测试代码1(基础)

    最近写了测试代码,整理了一下. 先看看简单的测试代码. // add_test.go ==> 文件名 _test.go 结尾的默认为测试代码文件 package models import ( ...

  9. Activity切换动画

    下一页动画 trans_in.xml <?xml version="1.0" encoding="utf-8"?> <translate an ...

  10. 关于Server2008 R2日志的查看

    Server 2008 r2通过 系统事件查看器 分析日志: 查看 系统 事件: 事件ID号: 审计目录服务访问 4934 - Active Directory 对象的属性被复制 4935 -复制失败 ...