排序算法-整理归档
来源:互联网 发布:管家婆软件哪里买 编辑:程序博客网 时间:2024/06/16 09:05
我觉的冒泡什么的就不说了,只是会提一下。
稳定性的定义:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。
简单理解就是,对于相同的元素,不能因为排序,而改变他们的相对位置,不然就肯定做了无用功了(相对而言)。
1、插入排序-直接插入排序
是一个稳定的算法,不会改变相同元素的相对位置。复杂度 O(n)
2、插入排序-希尔排序
是一个修改的冒泡排序,首先将所有元素分成d组,然后组内进行插入排序,然后将d进行减小,分的组会越来越多,最后d=1时就基本有序了。不稳定
void ShellInsertSort(int a[], int n, int dk) { for(int i= dk; i<n; ++i){ if(a[i] < a[i-dk]){ //若第i个元素大于i-1元素,直接插入。小于的话,移动有序表后插入 int j = i-dk; int x = a[i]; //复制为哨兵,即存储待排序元素 a[i] = a[i-dk]; //首先后移一个元素 while(x < a[j]){ //查找在有序表的插入位置 a[j+dk] = a[j]; j -= dk; //元素后移 } a[j+dk] = x; //插入到正确位置 } print(a, n,i ); } }
void shellSort(int a[], int n){ int dk = n/2; while( dk >= 1 ){ ShellInsertSort(a, n, dk); dk = dk/2; } }3、选择排序-直接选择排序
是将一个剩下的所有元素中选择一个最小的与第一个交换,重复这个过程,我一直觉得这个和冒泡排序很像,存在不相邻元素的互换。不稳定
4、选择排序-堆排序,是对直接选择排序的改进。
堆排序是一个树形结构,堆对应一个完全二叉树。
(1)ki<=k(2i)且ki<=k(2i+1)(1≤i≤ n/2),小顶堆,完全二叉树。堆排序是一个不稳定的算算法
由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。
堆排序是就地排序,辅助空间为O(1)
/** * 已知H[s…m]除了H[s] 外均满足堆的定义 * 调整H[s],使其成为大顶堆.即将对第s个结点为根的子树筛选, * * @param H是待调整的堆数组 * @param s是待调整的数组元素的位置 * @param length是数组的长度 * */ void HeapAdjust(int H[],int s, int length) { int tmp = H[s]; int child = 2*s+1; //左孩子结点的位置。(i+1 为当前调整结点的右孩子结点的位置) while (child < length) { if(child+1 <length && H[child]<H[child+1]) { // 如果右孩子大于左孩子(找到比当前待调整结点大的孩子结点) ++child ; } if(H[s]<H[child]) { // 如果较大的子结点大于父结点 H[s] = H[child]; // 那么把较大的子结点往上移动,替换它的父结点 s = child; // 重新设置s ,即待调整的下一个结点的位置 child = 2*s+1; } else { // 如果当前待调整结点大于它的左右孩子,则不需要调整,直接退出 break; } H[s] = tmp; // 当前待调整的结点放到比其大的孩子结点位置上 } print(H,length); } /** * 初始堆进行调整 * 将H[0..length-1]建成堆 * 调整完之后第一个元素是序列的最小的元素 */ void BuildingHeap(int H[], int length) { //最后一个有孩子的节点的位置 i= (length -1) / 2 for (int i = (length -1) / 2 ; i >= 0; --i) HeapAdjust(H,i,length); } /** * 堆排序算法 */ void HeapSort(int H[],int length) { //初始堆 BuildingHeap(H, length); //从最后一个元素开始对序列进行调整 for (int i = length - 1; i > 0; --i) { //交换堆顶元素H[0]和堆中最后一个元素 int temp = H[i]; H[i] = H[0]; H[0] = temp; //每次交换堆顶元素和堆中最后一个元素之后,都要对堆进行调整 HeapAdjust(H,0,i); } }
5、冒泡排序
是最简单的,就是一个一个往上移动,最坏时间n^2,最好n,平均是O(n^2),是一个稳定算法。
6、快排
快排是不稳定的,从他的原理就可以看出来,需要进行交换。
递归的
void swap(int *a, int *b) { int tmp = *a; *a = *b; *b = tmp; } int partition(int a[], int low, int high) { int privotKey = a[low]; //基准元素 while(low < high){ //从表的两端交替地向中间扫描 while(low < high && a[high] >= privotKey) --high; //从high 所指位置向前搜索,至多到low+1 位置。将比基准元素小的交换到低端 swap(&a[low], &a[high]); while(low < high && a[low] <= privotKey ) ++low; swap(&a[low], &a[high]); } print(a,10); return low; } void quickSort(int a[], int low, int high){ if(low < high){ int privotLoc = partition(a, low, high); //将表一分为二 quickSort(a, low, privotLoc -1); //递归对低子表递归排序 quickSort(a, privotLoc + 1, high); //递归对高子表递归排序 } }
另外一个面试经常考的算法出来了,归并排序
7、归并排序
归并排序是稳定的排序算法,主要是因为归并排序不存在将相同元素变换相对位置的操作。
//将r[i…m]和r[m +1 …n]归并到辅助数组rf[i…n] void Merge(ElemType *r,ElemType *rf, int i, int m, int n) { int j,k; for(j=m+1,k=i; i<=m && j <=n ; ++k){ if(r[j] < r[i]) rf[k] = r[j++]; else rf[k] = r[i++]; } while(i <= m) rf[k++] = r[i++]; while(j <= n) rf[k++] = r[j++]; }
merge是公有的,至于是递归去实现还是利用堆栈,是另外一个函数所做的事情。
void MSort(ElemType *r, ElemType *rf,int s, int t) { ElemType *rf2; if(s==t) r[s] = rf[s]; else { int m=(s+t)/2; /*平分*p 表*/ MSort(r, rf2, s, m); /*递归地将p[s…m]归并为有序的p2[s…m]*/ MSort(r, rf2, m+1, t); /*递归地将p[m+1…t]归并为有序的p2[m+1…t]*/ Merge(rf2, rf, s, m+1,t); /*将p2[s…m]和p2[m+1…t]归并到p1[s…t]*/ } }这一个归并排序是,单路的,主要原理是从0序列开始,先归并1个元素,然后归并2个元素,4,8。。。
void MergeSort(ElemType *r, ElemType *rf, int lenght) { int len = 1; ElemType *q = r ; ElemType *tmp ; while(len < lenght) { int s = len; len = 2 * s ; int i = 0; while(i+ len <lenght){ Merge(q, rf, i, i+ s-1, i+ len-1 ); //对等长的两个子表合并 i = i+ len; } if(i + s < lenght){ Merge(q, rf, i, i+ s -1, lenght -1); //对不等长的两个子表合并 } tmp = q; q = rf; rf = tmp; //交换q,rf,以保证下一趟归并时,仍从q 归并到rf } }
记住,快排和归并,都是递归的实现最简单。
8、桶排序/基数排序
桶排序是稳定的
把数据分组,放在一个个的桶中,然后对每个桶里面的在进行排序。
例如要对大小为[1..1000]范围内的n个整数A[1..n]排序
首先,可以把桶设为大小为10的范围,具体而言,设集合B[1]存储[1..10]的整数,集合B[2]存储 (10..20]的整数,……集合B[i]存储( (i-1)*10, i*10]的整数,i = 1,2,..100。总共有 100个桶。
然后,对A[1..n]从头到尾扫描一遍,把每个A[i]放入对应的桶B[j]中。 再对这100个桶中每个桶里的数字排序,这时可用冒泡,选择,乃至快排,一般来说任 何排序法都可以。
缺点也很明显
1、空间复杂度
2、要求,数据必须要在一定范围内
基数排序,可以想一下扑克牌,先根据花色进行排序,然后根据数字,是稳定的
基数排序过程无须比较关键字,而是通过“分配”和“收集”过程来实现排序。它们的时间复杂度可达到线性阶:O(n)。
总的比较
分为两种,一种是高位优先MSD,一种是低位优先LSD。
排序类别时间空间稳定插入 O(n^2)1√希尔O(n^2)1×冒泡O(n^2)
1√
选择O(n^2)
1×
快速O(nlogn)
O(nlogn)
×
堆排序O(nlogn)
1×
归并排序O(nlogn)
O(n)
√
- 排序算法-整理归档
- 归档整理
- 排序算法整理
- 排序算法整理
- 排序算法整理
- 整理几个排序算法
- 排序算法整理
- 排序算法整理
- java排序算法整理
- 外部排序算法整理
- 各种排序算法整理
- 排序算法整理
- 常见排序算法整理
- 排序算法 整理
- 常用排序算法整理
- 排序算法收集整理
- 排序算法整理
- Java:排序算法整理
- 黑马程序员_iOS开发C语言基础之二进制内存存储解析与字符操作
- 第二周周工作总结及计划表
- 【Android面试】Assets文件夹和/res/raw
- 计算物体密度
- C++函数指针实例详解(篇三)
- 排序算法-整理归档
- 第一章数据结构(思维导图)
- Linux下(网络流量分析)sar工具
- 深入理解递归函数的调用过程
- Contours轮廓
- 安卓学习之路-隐式跳转注意事项
- play junit 单元测试
- 输出随机数1到511*511序列
- BEGINNING SHAREPOINT® 2013 DEVELOPMENT 第6章节--在SharePoint2013中开发、集成和构建应用程序 总结