下面我们介绍一下时间复杂度为O(nlogn)的时间复杂度:希尔排序、归并排序、堆排序、快速排序
堆排序
将0~(n-1)的无序列表,映射为大根堆,根据大根堆的特性,堆顶为最大值;
将堆顶与堆的最后一个元素交换位置,并将其脱离堆结构,放在数组n-1位置上;
重新调整大根堆,重复步骤2,得到第n-2的数
直到堆元素个数为1,即整个堆排序完成。
图解流程访问下面链接中的 Data Structure Visualizations
希尔排序 希尔排序是插入排序的进化版,插入排序的每次迁移步长为1,而希尔排序则通过动态调整步长,进而提高排序效率。假如选定步长为3下面说一下排序过程
在0~(N-1)的无序序列中,数组中位置0、1、2三个数将被直接跳过。取3位置的数(a)和0位置上的数(b)比较。如果b>a,则结束比较;如果b<a,则交换b和a的位置,继续使用b和-3位置上的数比较,发现-3数组越界,结束比较;
取位置4上的数和位置1上的数比较,重复上面过程;
一直到最后一个位置n与n-3比较后结束步长为3的排序过程;
让步长减1继续完成上面1、2、3的步骤,知道步长=0,结束整个希尔排序过程;
图解流程访问下面链接中的Shell Sort Data Structure Visualizations
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public void sort (Comparable[] a) { int len = a.length; int w = 1 ; while (w < len / 3 ) { w = 3 *w + 1 ; } while (w >= 1 ){ for (int i = w ; i < len ; i ++){ for (int j = i ; j >= w && less(a[j],a[j-w]) ; j -=w ){ exch(a,j,j-w); } } w = w / 3 ; } }
归并排序
在0~(n-1)的无序列表中,将大小为1的有序区间,合并为大小为2的有序区间;
将大小为2的有序区间合并为大小为4的有序区间;
直到有序区间大小容纳所有的数,归并排序完成;
图解流程访问下面链接中的Merge Sort Data Structure Visualizations
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public static Comparable[] aux;public void sort (Comparable[] a) { aux = new Comparable [a.length]; sort(a,0 ,a.length-1 ); }public void sort (Comparable[] a,int lo,int hi) { if (hi <= lo) { return ; } int mid = lo + (hi - lo)/2 ; sort(a,lo,mid); sort(a,mid+1 ,hi); merge(a,lo,mid,hi); }public void merge (Comparable[] a, int lo, int mid, int hi) { int i = lo; int j = mid + 1 ; for (int k = lo; k <= hi; k++) { aux[k] = a[k]; } for (int k = lo; k <= hi; k++) { if (j > hi){ a[k] = aux[i++]; }else if (i > mid){ a[k] = aux[j++]; }else if (less(aux[j],aux[i])){ a[k] = aux[j++]; }else { a[k] = aux[i++]; } } }
快速排序 利用分治的思想,要对大小为N的无序序列排序,将其分为a[lo]-a[j-1],a[j],a[j+1]-a[hi]三部分,保证a[lo]-a[j-1]中的数永远小于等于a[j];a[j+1]-a[hi]中的数永远大于a[j];
在分别递归的对a[lo]-a[j-1]和a[j+1]-a[hi]重复上面的步骤。
下面我们说一下什么叫划分过程,划分过程就是怎么将小于等于a[j]的数放到a[j]的左边,大于a[j]的数放在了a[j]的右边:
选择一个数a[lo],初始化左指针 i = lo ,右指针 j = hi;
i指针往右移,找到大于等于a[lo]的数(a);j指针往左移,找到小于a[lo]的数b。交换a和b的位置,然后i继续往右移,j继续往左移,直到两者交汇。
将a[lo]与a[j]交换位置
图解流程访问下面链接中的Quick Sort Data Structure Visualizations
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public void sort (Comparable[] a) { sort(a,0 ,a.length-1 ); }public void sort (Comparable[] a,int lo ,int hi) { if (hi <= lo) { return ; } int j = partition(a,lo,hi); sort(a,lo,j-1 ); sort(a,j+1 ,hi); }public int partition (Comparable[] a, int lo, int hi) { int i = lo; int j = hi + 1 ; Comparable v = a[lo]; while (true ){ while (less(a[++i],v))if (i == hi)break ; while (less(v,a[--j]) )if (j == lo)break ; if (i >= j) break ; exch(a,i,j); } exch(a,lo,j); return j; }