《算法4》排序算法总结
来源:互联网 发布:禅道 linux 启动 编辑:程序博客网 时间:2024/05/23 11:17
最近在学算法,就以排序算法的总结作为第一篇博客
- 选择排序
- 插入排序
- 希尔排序
- 归并排序
- 快速排序
- 三向切分快速排序
- 总结
选择排序
选择排序的思路很简单 ,不断遍历整个数组,将未排序数组中最小的数放到左边,直到整个数组排序完成。选择排序速度较慢,每次都必须遍历整个数组未排序的部分,所以总的比较次数为
交换的次数为
这对于较大的数据集来说基本是不能忍的。
插入排序
插入排序可以用数学归纳法的方式来描述,首先
插入排序的性能:最坏的情况下,是排序一个反序(降序)的数组,那么每次都要将元素移到数组最左边,总的比较次数和交换次数都是
但是插入排序在小数组的情况下是很适合的,尤其是数组已经部分有序的情况下,它可以很快,并且可以作为高级排序算法的中间过程。
希尔排序
插入排序在数组较大的情况下很慢,因为它只能一步步地移动到正确的位置,同时上面也提到了,对于部分有序数组,插入排序是比较快的。所以希尔排序先对数组进行排序使之成为“h-有序”的,所谓“h-有序”就是数组中任意相距h的元素都是有序的。之后减小h的值再次排序,直到h减小到1,就退化成插入排序,但是此时整个数组已经是部分有序的,所以速度会提高很多。
对于h的取值可以采用Knuth提出的序列
排序的代码如下所示。
希尔排序的准确性能是不知道的,根据Sedgewick的《算法4》所说,下面的Shell Sort 算法的性能在最坏条件下是
//Shell Sortpackage first;import edu.princeton.cs.algs4.StdOut;public class Shell { public static void sort(Comparable[] a){ int N=a.length; int h=1; while(h<N/3) h=3*h+1;//找出最大的h while(h>=1){//相当于是对间隔为h的子数组进行插入排序,直到h=1 for(int i=h;i<a.length;i++){ for(int j=i;j>=h&&less(a[j],a[j-h]);j-=h) exch(a,j,j-h); } h=h/3; } } public static boolean less(Comparable v,Comparable w){//比较两个元素 return v.compareTo(w)<0; } public static void exch(Comparable[] a,int i,int j){//交换两个元素 Comparable t=a[i]; a[i]=a[j]; a[j]=t; } public static void show(Comparable[] a){//打印数组 for(int i=0;i<a.length;i++) StdOut.print(a[i]+" "); StdOut.println(); } public static boolean isSorted(Comparable[] a){//判断数组是否有序 for(int i=1;i<a.length;i++) if(less(a[i],a[i-1])) return false; return true; } public static void main(String[] args) { // TODO 自动生成的方法存根 Character[] s={'S','H','E','L','L','S','O','R','T','E','X','A','M','P','L','E'}; for(int i=0;i<s.length;i++) System.out.print(s[i]+" "); sort(s); StdOut.println(); for(int i=0;i<s.length;i++) System.out.print(s[i]+" "); }}
归并排序
归并排序是一种应用较为广泛的排序方法。起源于归并这个操作,即如果我们有两个有序数组如何将其合在一起变成一个更大的有序数组。
归并的思想很简单,首先得有一个辅助数组。比较两个有序数组的最小值,其中更小的那一个一定是将来更大的那个数组中最小的那个,将这个值复制到辅助数组中去。然后排除这个最小值再进行这种比较,直到两个数组都空了,最后得到的辅助数组就是一个有序的大数组。
归并排序就是从上到下,先分割再对子数组进行归并排序
归并排序的优点是不论最好还是最坏一定能够保证
下面是归并的代码片段;
private static void merge(Comparable[] a, int lo, int mid,int hi){ int i=lo,j=mid+1; for (int k=lo;k<=hi;k++){ aux[k] = a[k];//复制要排序的部分到辅助数组 } for (int k=lo;k<=hi;k++){//把两个有序数组归并到辅助数组中 if (i>mid) a[k] = aux[j++]; else if (j>hi) a[k] = aux[i++]; else if (less(aux[j], aux[i])) a[k] = aux[j++]; else a[k] = aux[i++]; } }
下面是排序的代码
private static 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); }
可以对排序予以优化,就是在,不断递归到子数组足够小的时候改成插入排序,比如在长度小于15的时候,这样做能将时间减少10%~15%(来自《算法4》)
快速排序
快速排序是应用最广泛的排序算法了,它所需的平均时间为
快速排序其实也很好理解,我们先选择一个元素v(通常是数组边界上的),然后以v为界对整个数组进行“切分”,“切分”就是将小于v的元素放在数组一边,大于它的放在另一边,然后再把v放到两种元素之间。其实此时元素v的位置就是它最终的位置,所以“切分”一方面得到了两个子数组,一方面确定了这个用于切分的元素的最终位置。将切分递归地对子数组进行下去,一定可以将整个数组排序。
public class QuickSort { private static void sort(Comparable[] a, int lo, int hi){ if (hi<=lo) return ;// 这句话忘记了的话就会栈溢出,主要是单个元素的情况下,会造成hi 比lo 小,如果不直接返回的话,就完了. int j = partition(a, lo, hi); sort(a, lo, j-1); sort(a, j+1, hi); } public static void sort (Comparable[] a){ StdRandom.shuffle(a); sort(a, 0, a.length-1); } private static int partition(Comparable[] a, int lo, int hi){ if (lo==hi ) return lo; Comparable v = a[lo]; int i=lo+1, j=hi; while(i<j){ while(a[i].compareTo(v)<0){//找一个比v大的元素 i++; if (i==hi) break; } while(a[j].compareTo(v)>0){//找一个比v小的元素 j--; if (j==lo) break; } if(i>=j ){break;}//最后停下的条件,j一定挨着i并且j<i exch(a, i, j); } exch(a, j, lo); return j; } private static boolean less(){}//方法同前面Shell Sort private static void exch(){}//方法同前面Shell Sort}
三向切分快速排序
对快速排序的一种改进就是三向切分快速排序,这种排序方式在重复元素较多的情况下甚至有可能达到线性级别。
算法实现过程中,先确定一个元素v,再维护两个指针,lt和gt。在lt左边的都是小于v的,在gt右边的都是大于v的,在数组排序完之后,在lt和gt之间的都应该是等于v的。
之所以能够提高速度,是因为在重复元素较多的时候,能够减少切分的次数。
下面是三向切分排序的排序函数。
private static void sort(Comparable[] a, int lo, int hi){ if (hi<=lo) return ;//单个元素直接返回 int lt=lo, gt = hi, i =lo+1; Comparable v= a[lo]; while(i<=gt){//一直比较到i大于gt int cmp = a[i].compareTo(v); if (cmp<0) exch(a,i++,lt++);//小于v的交换到lt的左边 else if (cmp>0) exch(a, i, gt--);//大于v的交换到gt的右边 else i++;//等于v的扩充lt到i之间的区域 } sort(a, lo, lt-1); sort(a, gt+1, hi);
总结
上图来自于《算法4》网站 ,Java中使用的系统排序函数是三向快速切分排序和归并排序。
- 《算法4》排序算法总结
- 算法--排序算法总结
- 算法:排序算法总结
- 算法:排序算法总结
- 算法-排序算法总结
- 算法-排序算法总结
- 【排序算法】排序算法总结
- 排序算法总结4-堆排序
- 排序算法总结(4)--希尔排序
- 【算法导论】排序算法总结
- 排序算法/查找算法总结
- 【算法总结】快速排序算法
- 算法总结之排序算法
- 算法之排序算法总结
- 排序算法总结
- 排序算法大总结
- 排序算法总结
- 排序算法总结
- js代码学习17--控制字体大小
- 关系型数据库和非关系型数据库的区别
- js代码学习18---选项卡
- 【51NOD】 1079
- 数据结构2-二叉树的最大深度
- 《算法4》排序算法总结
- HTTP请求报文和HTTP响应报文 -- JAVA 基础
- 微信小程序组件(四)text
- bzoj 3381: [Usaco2004 Open]Cave Cows 2 洞穴里的牛之二 RMQ
- js代码学习19---网页换皮肤
- 欢迎使用CSDN-markdown编辑器
- 16:矩阵剪刀石头布
- jdk8配置dubbo2.5.4
- BZOJ 4543: [POI2014]Hotel加强版 长链剖分