一、时间复杂度为o(n)的算法
1.1 计数排序
- 思路:设定一个范围的桶,如1~100编号的桶,将数据放到对应编号的桶中,让然后将数据从桶中倒出来。
以下是用二维数组模拟桶,二维数组第一列代表数据,第二列代表数据的个数
public static void sort(int[] array){
int[][] Bucket = new int[15][2];
for (int i = 0; i < Bucket.length; i++) {
Bucket[i][0] = 999999;
Bucket[i][1] = 0;
}
for(int num : array){
Bucket[num][0] = num;
Bucket[num][1] ++;
}
for (int i = 0; i < Bucket.length; i++) {
while (Bucket[i][1] != 0){
System.out.print(Bucket[i][0] + " ");
Bucket[i][1] --;
}
}
}
缺点:
- 耗内存
- 只适合对整数排序
补充:
int[][] arr = new int[4][];
System.out.println(arr.length);
System.out.println(arr[0].length);
第一个输出的是二维数组的行数,第二个输出的是二维数组的列数。
1.2 基数排序
- 思路:将每个数据按照个位数的大小放到对应的桶中,倒出,再将每个数据按照十位数的大小放到对应的桶中,倒出,将每个数据按照百位数的大小放到对应的桶中,倒出…
- 使用队列
- 我们需要手动的调整sort()方法中,调用kind()方法的次数。
public static int[] sort(int[] array){
array = kind(array,1);
array = kind(array,2);
return array;
}
public static int[] kind(int[] array, int n){
int flag = 0;
Queue[] queues = new Queue[10];
for (int i = 0; i < queues.length; i++) {
queues[i] = new LinkedList();
}
//将数据入桶
for(int num : array){
int mid = (num / ((int)Math.pow(10,n-1)) % 10);
queues[mid].offer(num);
}
//将数据倒出
for (int i = 0; i < queues.length; i++) {
while (!queues[i].isEmpty()) {
int remove = (int) queues[i].poll();
array[flag++] = remove;
}
}
return array;
}
二、对排序算法的比较
2.1 空间复杂度
- o(1)
插入排序,选择排序,冒泡排序,堆排序,希尔排序 - o(logN)~o(N)
快速排序 - o(N)
归并排序 - o(M)
计数排序,基数排序(取决于桶的数量)
2.2 排序算法的稳定性
稳定性的概念:
在待排序的记录序列中,存在多个具有相同关键字的记录,若经过排序,这些记录的相对次序保持不变,则这种算法就是稳定的,否则就是不稳定的。
- 不稳定
选择排序,堆排序,希尔排序,快速排序
2.2.1 选择排序不稳定
比如2,2,2,1,选择最小的数放在前面,则第一个2与1次序交换
2.2.2 堆排序不稳定
比如3,3,3,建立好堆结构后,最大值需与最后一个值交换次序
2.2.3 快排不稳定
比如1,2,2,2,4,取中间的2位key,则左右两边的2要么都在左边,要么都在右边。
2.3.4 希尔排序不稳定
比如1,3,3,1 步长为2时,后面的3与第一个1交换,则3的次序发生改变
三、补充
3.1 为什么说快速排序是最优的算法
快速排序的常量系数比较小
3.2 jdk1.8的快排
Java1.8的快排是一种双轴快排
算法步骤
1.对于很小的数组(长度小于27),会使用插入排序。
2.选择两个点P1,P2作为轴心,比如我们可以使用第一个元素和最后一个元素。
3.P1必须比P2要小,否则将这两个元素交换,现在将整个数组分为四部分:
(1)第一部分:比P1小的元素。
(2)第二部分:比P1大但是比P2小的元素。
(3)第三部分:比P2大的元素。
(4)第四部分:尚未比较的部分。
在开始比较前,除了轴点,其余元素几乎都在第四部分,直到比较完之后第四部分没有元素。
4.从第四部分选出一个元素a[K],与两个轴心比较,然后放到第一二三部分中的一个。
5.移动L,K,G指向。
6.重复 4 5 步,直到第四部分没有元素。
7.将P1与第一部分的最后一个元素交换。将P2与第三部分的第一个元素交换。
8.递归的将第一二三部分排序。
3.3 排序算法的选择
元素个数较少,插入排序,冒泡排序,元素个数较大,快排,堆排,元素个数特别大,快排。