数据结构——十大排序算法
数据结构——十大排序算法
- 排序分类如下:
- 一、直接插入排序
- 算法思想:
- 代码实现:
- 性能分析:
- 二、折半插入排序
- 算法思想:
- 代码实现:
- 性能分析:
- 三、希尔排序(缩小增量排序)
- 算法思想:
- 代码实现:
- 性能分析:
- 四、冒泡排序
- 算法思想:
- 代码实现:
- 性能分析:
- 五、快速排序
- 算法思想:
- 代码实现:
- 性能分析:
- 六、简单选择排序
- 算法思想:
- 性能分析:
- 七、堆排序
- 算法思想:
- 代码实现:
- 性能分析:
- 八、归并排序
- 算法思想:
- 代码实现:
- 性能分析
- 九、基数排序
- 十、多路归并排序
排序分类如下:
(默认排序结果是非递减有序序列)
(本文章是整理学习笔记,引用自2022王道考研书)
一、直接插入排序
算法思想:
有序序列 L [1……i-1] | L [i] | 无序序列 L [i+1……n] |
---|---|---|
例如:2,3 | 5 | 9,4,1,8,7,6,0 |
- 将待排序的表L从i(初始化i=0)下标位置分为有序表L[1……i]和L[i+1……n];
- 查找L [i] 在有序序列L [1……i-1]中的插入位置下标 k ;
- 将无序表L[i+1……n]中所有元素依次后移一个位置; //将k位置空出来
- 将L[i]复制到L[k];
代码实现:
void InsertSort(ElemType A[],int n){int i,j;for(i=2;i<=n;i++){ //将A[2]~A[n]插入到之前的有序序列之中,下标从1到n;if(A[i]<A[i-1]){ // A[i]比前驱小,进行插入操作;若A[i]大,则不用操作,减少了一次比较次数A[0]=A[i]; //A[0]为哨兵,不存放表内元素,临时存放要进行插入操作的元素for(j=i-1;A[0]<A[j];--j){ //从有序序列的后面往前找插入位置A[j+1]=A[j]; //找的过程将元素挪位置}//A[j]<=A[0]时跳出循环,此时A[j]理应排在A[0]之前//插入位置找到,下标为j+1;A[j+1]=A[0]; //复制A[0]到插入位置}}
}
性能分析:
空间:仅用了常数个辅助单元,因而空间复杂度为O(1) 时间:最好情况:表中元素已经有序,时间复杂度O(n);最坏情况:表中元素刚好逆序,时间复杂度O(n^2); 总比较次数(不包括与哨兵的比较1次)为n*n(n-1)/2;总移动次数为平均情况:时间复杂度O(n^2),总的比较次数和总移动次数约为n^2/4稳定性:稳定适用性:顺序存储和链式存储
二、折半插入排序
算法思想:
- 其实折半插入排序就是直接插入排序的改良版。算法思想一致.
只是将查找插入位置的方法由原来的从后往前顺序查找换成了二分法查找
代码实现:
void InsertSort(ElemType A[], int n){int i,j,low,high,mid;for(i=2;i<=n,i++){ //将A[2]~A[n]插入到之前的有序序列之中,下标从1到n;if(A[i]<A[i-1]){ //为了减少比较,不用这个语句也行A[0]=A[i];low=1;high=i-1; //对1到i-1进行二分查找(默认递增有序)while(low<high){mid=(low+high)/2;if(A[mid]>A[0]) high=mid-1; //查找左半子表else low=mid+1; //查找右半子表}//循环结束,找到插入位置for(j=i-1;j>=high+1;--j){ //后移元素A[j+1]=A[j]; }A[high+1]=A[0]; //复制到插入位置}}
}
性能分析:
时间复杂度与直接插入排序一致;稳定性:稳定;适用顺序存储线性表;数据量不大时,折半插入排序性能很好;比较次数改变,约为O(nlog2(n)),**仅与表中元素个数n有关**;
三、希尔排序(缩小增量排序)
算法思想:
将表中间隔某个“增量”d的元素组成若干个子表
(例如,{2,3,5,9,4,1,8,7,6,0},选定增量为3,得到子表1 {2,9,8,0},子表2 {3,4,7},子表3 {5,1,6}。)
对各个子表分别进行直接插入排序,再对全表L进行一次直接插入排序
希尔提出选择d1=n/2,d(i+1)=d(i)/2(下边界)——3/2取下边界为1,并且最后一个增量为1;
就是增量不断减半取下界,直到d=1
代码实现:
void ShellSort(ElemType A[],int n){for(int dk=n/2;dk>=1;dk=dk/2){ //增量的改变for(int i=dk+1;i<=n;i++){ //对子表的直接插入排序.相当于原来的增量为1现在变为了dk//子表的下标变为了i,i+dk,i+2dk,i+3dk…………if(A[i]<A[i-dk]){ //和其他插入排序一样,减少比较次数A[0]=A[i]; //存放A[i],作用没变for(int j=i-dk;j>0&&A[j]>A[0];j-=dk){A[j+dk]=A[j]; //后移元素}A[j+dk]=A[0]; //复制到插入位置} }}
}
性能分析:
空间复杂度:O(1)时间复杂度:依赖于增量序列的函数。无法分析。当n有特定范围时,最坏时间复杂度为O(n^2)稳定性:不稳定适用性:仅**顺序存储**线性表
四、冒泡排序
算法思想:
为体现冒泡,从后面往前面两两比较相邻的元素,将较小的元素送到无序序列的最前面,
也就是有序序列的最后面
设置i指针指向有序序列的最后一个元素,j指向无序序列的最后一个元素,默认第一个为有序序列
A[j]与A[j-1]比较,若A[j]<A[j-1],交换A[j]与A[j-1]的位置
当j<=i时跳出循环,不发生交换,结束一次冒泡过程。当i指到最后一个元素时结束冒泡排序过程
代码实现:
void BUbbleSort(ElemType A[],int n){for(int i=0;i<n;i++){bool flag=false; //不发生交换的标志for(int j=n-1;j>i;j--){if(A[j]<A[j-1]){swap(A[j],A[j-1]); //交换flag=true;}}if(flag==false)return 0; //不发生交换,说明已然有序}
}
性能分析:
空间复杂度:O(1)初始序列有序时,最好时间复杂度O(n)初始序列逆序时,最坏时间复杂度O(n^2),比较次数n*(n-1)/2,移动次数3n(n-1)/2;平均时间复杂度O(n^2);稳定性:稳定。
五、快速排序
算法思想:
- 基于分治法,在表L中任取一元素pivot将表分为左子表L[1……k-1]和右子表L[k+1……n],L[k]=pivot
- 左子表中所有元素均小于pivot,右子表中所有元素均大于pivot,这个过程为一趟快速排序
- 用同样的方法对左子表和右子表进行快速排序,若待排序列中只有一个元素则结束排序
- 根据严蔚敏版教材《数据结构》,假设每次pivot为当前表的第一个元素,pivot=A[low]
代码实现:
void QuickSort(ElemType A[],int low,int high){if(low<high){ //递归跳出的条件int pivotpos=Partition(A,low,high); //划分点的下标Partition(A,1,pivotpos-1); //对两子表快速排序Partition(A,pivotpos+1,high);}
}int Partition(ElemType A[],int low,int high){ElemType pivot=A[low];while(low<high){while(low<high && A[high] >=pivot) --high;A[low]=A[high]; //high指针左移遇到的小于pivot的值将其放到low的位置上while(low<high && A[low] <=pivot) ++low;A[high]=A[low]; //low指针右移遇到的大于pivot的值将其放到high的位置上}A[low]=pivot; //循环结束,low和high都指向k,左边小,右边大,pivot放到应该的位置return low;
}
性能分析:
空间: 需要一个递归工作栈,其容量与递归调用的最大深度一致。 最好情况是O(log2(n));最坏情况是O(n);平均情况为O(log2(n))时间:最好情况与平均情况为O(nlog2(n));最坏情况为O(n^2);稳定性:不稳定。
六、简单选择排序
算法思想:
- 设置两个指针i和j,i遍历所有元素,刚开始设置A[i]为A[i……n-1]中最小元素;
- j是工作指针,从i+1开始寻找A[i……n-1]序列中最小的元素,记录下标min
- 将A[min]与A[i]交换,i继续往后遍历,当min==i时,到达最后一个,不用交换,结束排序。
代码实现:
void SelectSort(ElemType A[],int n){for(int i=0;i<n,i++){min=i; //min指向A[i……n-1]中最小的元素for(int j=i+1;j<n,j++){if(A[j]<A[min]) min=j;}if(min!=i) swap(A[i],A[min]);}
}
性能分析:
空间:O(1)时间:最好情况移动0次,最坏移动不超过3(n-1);比较次数始终是n(n-1)/2次;时间复杂度始终是O(n^2)稳定性:不稳定。
七、堆排序
算法思想:
建堆过程:从第一个非叶子结点(下标为len/2取下界)从下往上建成大根堆(下标逐渐减一直到0)
调整过程:调整以A[k]为根的子树为大根堆(代码注释有)
排序过程:
1、首先将待排序列建成初始堆。
2、将堆底元素与堆顶元素交换,破坏了以堆顶为根的大堆根(堆顶最大,堆底最小)
3、对堆顶到堆底的堆进行调整
4、设置指针i从len开始不断往上,将以1为堆顶,i为堆底的堆调整为大堆根(重复第2和3步);
5、堆底指针与堆顶重合等于1,结束排序。A[1]到A[len]从大到小;
代码实现:
void BuildMaxHeap(ElemType A[],int len){ //建堆for(int i=len/2;i>0;i--){HeadAdjust(A,i,len);}
}void HeadAdjust(ElemType A[],int k,int len){
//该函数将A[k]为根的子树进行调整为大根堆A[0]=A[k]; //A[0]暂存调整堆的大小for(int i=2*k;i<len;i*=2){if(i<len&&A[i]<A[i+1]) i++; //i指向k左右子结点较大的元素if(A[0]>=A[i]) break; //若根节点比子节点大,则不用调整else{A[k]=A[i];k=i; //方便继续往下调整子树}}A[k]=A[0]; //A[0]存放该调整树的最大值
}void HeapSort(ElemType A[],int len){ //堆排序BuiliMaxHead(A,len); //将待排序列建堆for(i=len;i>1;i--){ //n-1次的交换和建堆过程Swap(A[i],A[1]); //输出堆顶元素(和堆底元素交换)————最小值与最大值的交换HeadAdjust(A,1,i-1); //调整,把剩余i-1个元素整理成堆}
}//此次排序为逆序(从大到小);
性能分析:
堆排序适合关键字较多的情况。例如一亿中选出前100个最大值空间:O(1)时间:建堆时间为O(n);最好、最坏、平均情况都是O(nlog2(n))稳定性:不稳定
这是王道书上的我的理解;堆排序更多解释参考:堆排序
八、归并排序
算法思想:
- 将前后相邻的两个有序表归并为一个有序表
- 递归调用第一步
代码实现:
ElemType *B=(ElemType *)malloc((n+1)*sizeof(ElemType)); //辅助数组B
void Merge(ElemType A[],int low,int mid,int high){//将A表中的两段合并成一段有序表for(int k=low;k<=high;k++){ //将A中内容复制给BB[k]=A[k];}for(int i=low,j=mid+1,k=i;i<=mid&&j<=high;k++){if(B[i]<=B[j]) A[K]=B[i++]; //较小者复制到A中else A[k]=B[j++];}while(i<=mid) A[k++]=B[i++]; //表一未检测完,复制while(j<=high) A[k++]=B[j++]; //表二未检测完,复制
}
void MergeSort(ElemType A[],int low,int high){//归并排序if(low<high){ //递归跳出条件int mid =(low+high)/2;MergeSort(A,low,mid); //左侧表递归排序MergeSort(A,mid+1,high); //右侧表递归排序Merge(A,low,mid,high); //归并}
}
性能分析
空间:O(n)时间:O(nlog2(n))稳定性:稳定。
(后面两个排序较为复杂,需要图解,看链接)
九、基数排序
链接
十、多路归并排序
链接
数据结构——十大排序算法相关推荐
- 数据结构十大排序算法(python)
十大经典排序算法 (java实现看这个)https://program.blog.csdn.net/article/details/83785159 名词解释: 1.冒泡排序 2.选择排序 3.插入排 ...
- 中希尔排序例题代码_【数据结构与算法】这或许是东半球分析十大排序算法最好的一篇文章...
码农有道 历史文章目录(请戳我) 关于码农有道(请戳我) 前言 本文全长 14237 字,配有 70 张图片和动画,和你一起一步步看懂排序算法的运行过程. 预计阅读时间 47 分钟,强烈建议先收藏然后 ...
- 数据结构与算法:十大排序算法之归并排序
数据结构与算法:十大排序算法之归并排序 package TopTenSortingAlgorithms;/*** 归并排序:Java** @author skywang* @date 2014/03/ ...
- 数据结构与算法:十大排序算法之插入排序
数据结构与算法:十大排序算法之插入排序 package TopTenSortingAlgorithms;import java.util.Arrays; import java.util.Scanne ...
- 数据结构与算法:十大排序算法之堆排序
数据结构与算法:十大排序算法之堆排序 堆排序可以说是选择排序的优化 package TopTenSortingAlgorithms;import java.util.Arrays; import ja ...
- 数据结构与算法:十大排序算法之冒泡排序
数据结构与算法:十大排序算法之冒泡排序 package array;import java.util.Arrays;//冒泡排序 //1.比较数组中两个相邻的元素,如果第一个数比第二个数大,我们就交换 ...
- 【数据结构与算法】这或许是东半球分析十大排序算法最好的一篇文章
原地址:https://mp.weixin.qq.com/s?__biz=MzIwNTc4NTEwOQ==&mid=2247486981&idx=1&sn=c63cd080be ...
- 这或许是东半球分析十大排序算法最好的一篇文章
作者 | 不该相遇在秋天 转载自五分钟学算法(ID:CXYxiaowu) 前言 本文全长 14237 字,配有 70 张图片和动画,和你一起一步步看懂排序算法的运行过程. 预计阅读时间 47 分钟,强 ...
- 「干货总结」程序员必知必会的十大排序算法
点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:硬刚一周,3W字总结,一年的经验告诉你如何准备校招! 个人原创100W+访问量博客:点击前往,查看更多 绪论 身 ...
- 「归纳|总结」程序员必知必会的十大排序算法
微信搜一搜「bigsai」关注这个有趣的程序员 新人原创公众号,求支持一下!你的点赞三连肯定对我至关重要! 文章已收录在 我的Github bigsai-algorithm 欢迎star 本文目录 绪 ...
最新文章
- linux基础上的三维重建,Ubuntu16.04下用ZED双目立体相机进行SLAM(以相机轨迹生成和三维重建为例)...
- (转载)浅析Hadoop文件格式
- nyoj 55(优先队列)
- 基于模块度的社团检测算法
- 基于Vue+ElementUI的后台管理系统开发的总结
- MOTChallenge榜单第一!用于多目标跟踪简单高效的数据关联方法 BYTE
- git 还原文件到其他版本_如何在Git中还原旧文件版本
- uniapp微信小程序获取位置(高德SDK)
- 查看linux jvm使用情况,查看jvm内存使用命令
- Office 2007 SP3 正试版补丁包下载
- mysql64官网下教程_最新版MySQL 8.0.22下载安装超详细教程(Windows 64位)
- iptables 跨网段转发
- 《MySQL必知必会》SQL文件
- Apex_json应用
- JavaWeb项目实现163邮箱验证码
- ICEM-圆柱与长方体相切
- 逍遥安卓模拟器卡android,逍遥安卓模拟器卡顿如何解决
- 刘强东终于向自己的兄弟下手了!
- Anuglar8集成高德地图
- OLED12864播放视频
热门文章
- 云服务器架设大话西游2,端游[大话西游]天演册虚拟机镜像一键启动服务端+客户端+GM工具等...
- 计算机系统删除一点会怎么样,怎么样清理C盘的多余文件?
- html转换下一页,如何转到下一页与HTML和/或JS锚?
- 玩转软路由 篇一:巨详细的修改Esxi7.0管理端口教程
- 这个可以有!百度大脑EasyDL新发布EasyData搞定AI开发中的数据管理问题
- BootStrap左侧菜单栏
- 致远OA A8 漏洞综合工具
- 水平线标记的用法和属性
- 模拟量转数字量的本质
- 论文阅读笔记:A CRITIQUE OF SELF-EXPRESSIVE DEEP SUBSPACE CLUSTERING,自表达深度子空间聚类批判