各种排序算法实现及总结
来源:互联网 发布:希拉里失败原因 知乎 编辑:程序博客网 时间:2024/06/05 21:55
本文主要比较一下各种排序的性能(平均时间复杂度和最差情况)和基本实现。
这个默认按照从小到大排列,输入的数据可以重复,假设输入的数组为A,下标从0到N-1
注意在比较算法复杂度时,我们会关注键值的比较次数和交换次数。
1、冒泡排序
冒泡排序如果不是因为名字比较好记,没有任何优势。它的思路是一趟又一趟的比较数组(或者链表也可以)中相邻的两个元素,如果前一个比后一个大,则交换。这样,每一轮之后,最大的那个元素被“沉”到数组的最后去。
void Bubble_Sort(int A[], int N){ for(int i = 0; i<=N-2; i ++) for(int j = 0; i<=N-2-i; j++) if(A[j]>A[j+1]) swap(A+j,A+j+1);}
可以发现,在平均情况和最差情况是,键值的比较次数和交换次数都是O(N^2)
在最好情况下,键值的比较次数还是O(n^2),但是代码经过优化后键值的交换次数为O(N)
public void bubbleSort(int arr[]) { boolean didSwap; for(int i = 0, len = arr.length; i < len - 1; i++) { didSwap = false; for(int j = 0; j < len - i - 1; j++) { if(arr[j + 1] < arr[j]) { swap(arr, j, j + 1); didSwap = true; } } if(didSwap == false) return; } }
参见http://www.cnblogs.com/melon-h/archive/2012/09/20/2694941.html
同时,冒泡排序还是一个稳定的算法。
2、插入排序
插入排序的思想是对于一个A[i],我们假设它之前的都已经排序好了,这时关键是向前寻找A[i]的位置,j=i-1~0,比较A[i]和A[j],如果A[j]大,则A[j]向后移,直到A[j]小时,就是A[i]的位置。
void Insertion_Sort(int A[], int N){ int tmp,i,j; for(i = 1; i<N; i++){ tmp = A[i]; //比较i之前的元素和A[i]的大小 for(j = i; j!=0&&A[j-1]>tmp; j--) A[j] = A[j-1]; //移出空位 A[j] = tmp; }}
插入排序是对冒泡排序的改进,也是稳定的算法。
最差的情况是逆序(从大到小排列)时间复杂度是O(N^2)
3、希尔排序
以D间隔进行排序,为了每次不止消除一个逆序对。
D=2^k-1(比较好的 D)
void Shell_Sort(int A[], int N){ int tmp,i,j; for(int D = N/2; D>0; D/=2){//shell增量 for(i = D; i<N; i++){ //插入排序 tmp = A[i]; //比较i之前的元素和A[i]的大小 for(j = i; j!=0&&A[j-D]>tmp; j-=D) A[j] = A[j-D]; //移出空位 A[j] = tmp; } }}
4、选择排序
对当前的下标位置i时,我们要找到i+1到N-1中的最小的下标min_i与i位置的元素交换
void Selection_Sort(int A[], int N){ int i,j,min_i; for(i = 0; i <N-1; i++){ min_i = i; //找最小元交换 for(j = i+1; j<N; j++) if(A[j]<A[min_i]) min_i =j; swap(A+j,A+min_i); }}
5、堆排序
首先构建一个最大堆,这样最大堆的第一个元素就是最大的元素,将它与堆的最后一个元素交换后,堆的规模减一再将剩下的堆重新调整为最大堆,重复操作即可。
先考虑堆的建立,有两种方法
方法1:通过插入操作,将N个元素一一插入到一个初始为空的堆,O(nlgN)
这样,堆排序的操作为一直deleteMin,将最小的元素存起来,
void Heap_Sort(int A[], int N){ BuilDHeap(A); //O(N) for(i = 0; i<N; i++) TmpA[i]=DeleteMin(A); //O(log(N)) for(i =0; i<N; i++) //O(N) A[i]=TmpA[i];}
上面的问题是多使用了一个额外的数组来储存。
另外一个种堆排序,
#define LeftChild(i) (2*(i)+1) //以0为起点的堆void PercDown(int A[], int i, int N){ //从i向左右儿子过滤,建成以i为根的最大堆 int child,parent; int tmp; tmp = A[i]; //寻找tmp需要放的位置 for(parent = i; parent*2<=N-1; parent = child){ child = LeftChild(i); if(child!=N-1&&A[child]<A[child+1])//右儿子较大 child++; if(tmp>A[child]) break; else A[parent]=A[child]; } A[parent]=tmp; }void Heap_Sort(int A[], int N){ int i; for(i=N/2; i>=0; i--) //build heap PercDown(A,i,N); for(i=N-1; i>0;i--){ swap(&A[0],&A[i]); //DeleteMax PercDown(A,0,i); }}
优点,堆排序是一种在位的排序方法,适合数据量非常大的场合。
6、快速排序
在数据量一般的情况下,是性能最好的排序方法。主要的思想是分治,它本身有很多trick,stl里中的sort就是使用快速排序的,它的源码也值得好好研究下。这里主要说下主要的几个trick
1、主元pivot的选择,先使用一个median3的函数,选择出left(0),right(N-1),center三个位置上的中位数,并将中位数放在right-1的位置。(这样只要考虑A[left+1,right-2]事实证明主元的选择对性能有较大影响,这种方式较好。
2、i从left开始,j从right-1开始移动,直到两者相交
3、停止的时候,交换A[i]和A[right-1],递归左右两个子序列
4、当序列的长度小于阈值时,不递归而使用才插入排序 ,这样也能显著调高速度
//Swap two numbers void swap(int *a, int *b){ int tmp; tmp = *a; *a = *b; *b = tmp; } //choose the median of left, center and right int median3(int *A, int left, int right){ int center = (left+right)/2; if(A[left]>A[center]) swap(A+left,A+center); if(A[left]>A[right]) swap(A+left,A+right); if(A[center]>A[right]) swap(A+center,A+right); //put median in right-1 swap(A+center,A+right-1); return A[right-1]; } //Insertion sort ---for small size array and index array void Insertion_Sort(int *A, int N){ int p; int i; int tmp; for(p = 1; p < N; ++p){ tmp = A[p]; for(i = p; i!=0&&A[i-1]>tmp; --i) A[i]=A[i-1]; A[i] = tmp; } } void Quicksort(int *A, int left, int right){ if(right-left>10){ int pivot = median3(A, left, right); int i = left; int j = right-1; for(;;){ while(A[++i]<pivot){} while(A[--j]>pivot){} if(i<j) swap(A+i,A+j); else break; } swap(A+i,A+right-1); Quicksort(A,index_A,left,i-1); Quicksort(A,index_A,i+1,right); } else Insertion_Sort(A+left,right-left+1); }
具体的性能比较可以参考http://blog.sina.com.cn/s/blog_77795cad01011txt.html
7、位排序
还有一个处理大数据的方法,参见之前的一篇文章
海量数据处理
- 各种排序算法实现及总结
- 各种排序算法java实现及总结
- 各种排序算法总结及C#代码实现
- 各种排序算法总结及C#代码实现
- 堆排序及各种排序算法总结
- 各种排序算法总结及代码
- 各种排序算法及其实现总结
- 各种排序算法的总结和实现。
- 各种排序算法总结(C++实现)
- 各种排序算法分析及java实现
- java实现各种排序算法及比较
- java实现各种排序算法及比较
- 各种排序算法及java实现
- java实现各种排序算法及分析
- 各种排序算法的实现及优化
- java各种排序总结及实现
- 排序算法总结及实现
- 各种排序算法的java实现及时间、空间复杂度、稳定程度总结
- wget+webmin+dns+lamp+openwebmail
- 第45讲:Scala中Context Bounds代码实战及其在Spark中的应用源码解析学习笔记
- hdu--2066
- shell编程——if条件判断(转)
- poj1276
- 各种排序算法实现及总结
- OPENCV错误
- android放大镜效果实现
- mfc消息机制
- cernet 2015年会征文
- gdb调试多线程的简单命令
- 算法简介,算法重要性
- 还是畅通工程(2006浙江大学研究生上机复试题目[最小生成树] hdoj 1233)
- 转载 android权限