排序算法有很多种,包括冒泡排序,选择排序,快速排序,插入排序,希尔排序,堆排序等。它们的时间复杂度和空间复杂度如下表所示:
排序法 | 最差时间分析 | 平均时间复杂度 | 稳定度 | 空间复杂度 |
冒泡排序 | O(n2) | O(n2) | 稳定 | O(1) |
快速排序 | O(n2) | O(n*log2n) | 不稳定 | O(log2n)~O(n) |
选择排序 | O(n2) | O(n2) | 稳定 | O(1) |
二叉树排序 | O(n2) | O(n*log2n) | 不一顶 | O(n) |
插入排序 | O(n2) | O(n2) | 稳定 | O(1) |
堆排序 | O(n*log2n) | O(n*log2n) | 不稳定 | O(1) |
希尔排序 | O | O | 不稳定 | O(1) |
这里着重讨论下冒泡排序,快速排序和插入排序这三种排序算法。
冒泡排序——时间复杂度O ( n2 )
冒泡排序从第一个元素开始,依次与后面的元素比较,每次遇到比当前元素更大(或更小)的值时,则交换数值。每一轮比较后位于当前位置的数值都是最小(或最大)的,总共需要(n-1) + (n-2) + (n-3) + …… + 1 即(n+1)*n/2次比较,时间复杂度为O(n2)。
Java实现代码为:
public static void bubbleSort(int[] nums){ for(int i=0;inums[j]){ int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; } } for(int i=0;i
总结:冒泡排序较为简单,容易理解,效率较低。
快速排序——时间复杂度O(n*log2n)
快速排序的基本思想是,先选择一个基准数。可以选择第一个数,或者将列首、列尾和中间的数字进行比较,选择三者中的中值,也可以随机选择列中的一个数字。然后将列中小于基准数的数值移至左边,大于基准数的数值移至右边。依次类推,再分别对左边的数列和右边数列分别进行相同的操作。该算法采用“分治”的思想,将大的分为小的,小的分为更小的,提高了比较和移动的效率。
Java实现代码为:
public static void sort(int a[], int low, int hight) { int i, j, index; if (low > hight) { return; } i = low; j = hight; index = a[i]; // 用子表的第一个记录做基准 while (i < j) { // 从表的两端交替向中间扫描 while (i < j && a[j] >= index) j--; if (i < j) a[i++] = a[j];// 用比基准小的记录替换低位记录 while (i < j && a[i] < index) i++; if (i < j) // 用比基准大的记录替换高位记录 a[j--] = a[i]; } a[i] = index;// 将基准数值替换回 a[i] sort(a, low, i - 1); // 对低子表进行递归排序 sort(a, i + 1, hight); // 对高子表进行递归排序 }
总结:快速排序是冒泡排序的改进,执行效率与基准数的选择有关,最差的的情况是,每轮比较选择的基准数都为最大(最小)值,此时的时间复杂度为O ( n2 )。最好情况是指每次区间划分的结果都是基准关键字的左右两边长度相等或者相差为1,即选择的基准关键字为待排序的记录的中间值。此时进行比较次数总共为 nlogn,所以最好情况下快速排序的时间复杂度为O (nlogn)。
插入排序——时间复杂度O(n2)
基本思想
每步将一个待排序的对象,按其排序码大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。
分类
根据寻找插入位置方法分为
- 直接插入排序
- 折半(二分)插入排序
- 希尔插入排序
直接插入排序的Java代码实现:
public static int[] insertSort(int[]arr){ if(arr == null || arr.length < 2){ return arr; } for(int i=1;i0;j--){ if(arr[j]
总结:插入排序适合在对已经排好序的数值序列中新增一个数值,使数值序列依然有序的情况下使用,是稳定的排序。其优化形式二分插入和希尔插入排序效率更高。
参考文章 http://blog.csdn.net/jianyuerensheng/article/details/51258374