十大排序算法笔记(C语言)(一)选择排序、冒泡排序、插入排序、希尔排序、快速排序
排序算法 | 最好情况 | 最坏情况 | 平均时间复杂度 | 空间复杂度 | 稳定性 |
---|---|---|---|---|---|
选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 不稳定 |
冒泡排序 | O(n) | O(n^2) | O(n^2) | O(1) | 稳定 |
插入排序 | O(n) | O(n^2) | O(n^2) | O(1) | 稳定 |
希尔排序 | O(n^(1.3)) | O(n^2) | O(n^(1.3-2)) | O(1) | 不稳定 |
快速排序 | O(n*logn) | O(n^2) | O(n*logn) | O(logn) | 不稳定 |
文章目录
- 一、选择排序
- 1.1 选择排序基础
- 1.2 代码演示
- 1.3 选择排序的复杂度、稳定性以及使用场景
- 1.3.1 时间复杂度
- 1.3.2 空间复杂度
- 1.3.3 排序稳定性
- 1.3.4 使用场景
- 二、冒泡排序
- 2.1 冒泡排序基础
- 2.2 代码演示
- 2.3 冒泡排序的复杂度、稳定性以及使用场景
- 2.3.1 时间复杂度
- 2.3.2 空间复杂度
- 2.3.3 排序稳定性
- 2.3.4 使用场景
- 三、插入排序
- 3.1 插入排序基础
- 3.2 代码演示
- 3.3 插入排序的复杂度、稳定性以及使用场景
- 3.3.1 时间复杂度
- 3.3.2 空间复杂度
- 3.3.3 排序稳定性
- 3.3.4 使用场景
- 四、希尔排序
- 4.1 希尔排序基础
- 4.2 代码演示
- 4.3 希尔排序的复杂度、稳定性以及使用场景
- 4.3.1时间复杂度
- 4.3.2 空间复杂度
- 4.3.3 排序稳定性
- 4.3.4 使用场景
- 五、快速排序
- 5.1 快速排序基础
- 5.2 代码演示
- 5.3 快速排序的复杂度、稳定性以及使用场景
- 5.3.1 时间复杂度
- 5.3.2 空间复杂度
- 5.3.3 排序稳定性
- 5.3.4 使用场景
一、选择排序
1.1 选择排序基础
工作原理:扫描整个列表,找出最小的元素,然后将最小的元素与第一个元素交换位置。接着从第二个位置开始扫描,找出n-1个元素中最小的元素,将其与第二位置上的元素交换位置。如此类推,做n-1次后排序结束。
动画演示过程:
1.2 代码演示
void SelectionSort(int a[],int n){int i,j,temp;for(i = 0;i < n;i++){for(j = i+1;j < n;j++){if(a[j]<a[i]){//如果后面元素的值小于前面的,则进行交换temp = a[j];a[j] = a[i];a[i] = temp;}}
}
1.3 选择排序的复杂度、稳定性以及使用场景
1.3.1 时间复杂度
由上面的代码可以看出,选择排序是在两层循环中进行的。因此,不管是最坏,最好的情况,时间复杂度都是O(n^2)。但是,如果一开始就是升序的,则交换的次数为0,如果是降序的,则交换次数为n-1。(默认结果为升序排序)。
1.3.2 空间复杂度
选择排序完全就是比较和交换数据,只需要一个辅助空间用来存储待比较的元素的下标,并没有消耗更多的额外空间,因此其空间复杂度是O(1)。
1.3.3 排序稳定性
选择排序是一种不稳定的算法,因为如果前后两个元素的值相同,则经过排序后,两者的前后顺序发生变化。
Eg:数组 4、6、4、3、8,在对其进行第一遍循环的时候,会将第一个位置的4与后面的3进行交换。此时,就已经将两个4的相对前后位置改变了。因此选择排序不是稳定性排序算法。
1.3.4 使用场景
待排序序列中,元素个数较少时
二、冒泡排序
2.1 冒泡排序基础
工作原理:比较相邻的元素,将大的元素交换到右边的位置,重复多次后,最大的元素就“沉淀”到列表的最后一个位置。第二遍将第二大元素沉淀下去,n-1次后结束。
动画演示过程:
2.2 代码演示
void BubbleSort(int a[],int n){int i,j,temp;for(i = 1;i <= n-1; i++) {//若有n个数,则交换的次数是n-1;for(j = 0;j <= n-i;j++){if(a[j] > a[j+1]){temp = a[j];//如果左边的数大于右边的,则交换a[j]和a[j+1]的位置 a[j] = a[j+1];a[j+1] = temp;}}}
}
2.3 冒泡排序的复杂度、稳定性以及使用场景
2.3.1 时间复杂度
默认结果为升序
(1)如果一开始就是升序排列,一趟扫描即可完成排序。所需的关键字比较次数C和交换次数M均达到最小值:
C(min) = n-1;M(min) = 0
因此,冒泡排序在最好情况下的时间复杂度为O(n)。
(2)如果一开始是降序排列,需要进行n-1趟排序。每趟排序要进行n-i次关键字的比较(1≤i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和交换次数均达到最大值:
C(max) = 1+2+…+(n-1)=n*(n-1)/2
M(max)= 3n(n-1)/2
因此,冒泡排序在最坏情况下的时间复杂度为O(n^2)。
2.3.2 空间复杂度
冒泡排序完全就是比较和交换数据,只需要一个辅助空间用来存储待比较的元素的下标,并没有消耗更多的额外空间,因此其空间复杂度是O(1)。
2.3.3 排序稳定性
在冒泡排序中,遇到相等的值,是不进行交换的,只有遇到不相等的值才进行交换,所以是稳定的排序方式。
2.3.4 使用场景
待排序序列中,元素个数较少时
三、插入排序
3.1 插入排序基础
工作原理:先假定第一个为有序数列,后面的为无序数列,然后从第二个元素开始,插入到前面的有序数列中,直到所有元素都插入进去为止。
动画演示过程:
3.2 代码演示
void InsertSort(int a[],int n){int i,j,temp;for(i = 1;i < n;i++){if(a[i] < a[i-1]){j = i-1;//先标记现在的位置temp = a[i];while(j >= 0&&temp < a[j]){a[j+1] = a[j];j--;}a[j+1] = temp;//将待排序元素插入数组中}}
}
3.3 插入排序的复杂度、稳定性以及使用场景
3.3.1 时间复杂度
默认结果为升序排列
(1)如果一开始的时候就是升序排序的话,只需要当前的数与前面一个数作比较就行了,这时一共需要n-1次,时间复杂度为O(n)。
因此,插入排序在最好的情况下的时间复杂度为O(n)。
(2)如果一开始的时候是降序排序的话,总次数为1+2+3+…+n-1 = n*(n-1)/2。
因此,插入排序在最坏的情况下的时间复杂度为O(n^2)。
(3)平均情况是,右半区每一个数,都和一半的左半区的数比较。总次数为1/2 + 2/2 + 3/2 + … + ( n - 1 )/2 = O(n^2)。
因此,插入排序在的平均时间复杂度为O(n^2)。
3.3.2 空间复杂度
插入排序完全就是比较和交换数据,只需要一个辅助空间用来存储待比较的元素的下标,并没有消耗更多的额外空间,因此其空间复杂度是O(1)。
3.3.3 排序稳定性
在使用插入排序时,元素从无序部分移动到有序部分时,必须是不相等(大于或小于)时才会移动,相等时不处理,所以插入排序是稳定的。
3.3.4 使用场景
待排序序列的元素个数不多,且元素基本有序。
四、希尔排序
4.1 希尔排序基础
工作原理:希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序。它与插入排序的不同之处在于,它会优先比较距离较远的元素,间隔慢慢减成1,插入排序的间隔一直就是1。希尔排序又叫缩小增量排序。
动画演示过程:
4.2 代码演示
void ShellSort(int a[],int n){int i,j,temp;int gap = n/2;//先让比较的间距为n/2;while(gap > 0){for(i = gap;i < n;i++){if(a[i - gap] > a[i]){//与直接插入排序差不多的思路,只是间距逐渐减小temp = a[i];j = i -gap;while(j >= 0&&a[j]>temp){a[j+gap] = a[j];j -= gap;}a[j+gap] = temp;}}gap /= 2;}
}
4.3 希尔排序的复杂度、稳定性以及使用场景
4.3.1时间复杂度
(1)最好情况:T(n) = O(n^1.3)
(2)最坏情况:T(n) = O(n^2)
(3)平均情况:T(n) =O(n^(1.3-2))[注:与所分的序列有关]
4.3.2 空间复杂度
希尔排序完全就是比较和交换数据,只需要一个辅助空间用来存储待比较的元素的下标,并没有消耗更多的额外空间,因此其空间复杂度是O(1)。
4.3.3 排序稳定性
希尔排序是直接插入排序的优化版,在排序过程中,会根据间隔将一个序列划分为不同的逻辑分组,在不同的逻辑分组中,有可能将相同元素的相对位置改变。如[2,2,4,1],按间隔为2,降序排序,前两个元素的相对位置就会改变。
因此,希尔排序是不稳定的排序方式。
4.3.4 使用场景
待排序序列元素较少时。
五、快速排序
5.1 快速排序基础
工作原理:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序(在这里用到递归思想),以达到整个序列有序。
动画演示过程:
5.2 代码演示
void QuickSort(int* a,int n)
{int i,j;int pivot = a[0];//让第一个数为基准i =0;j = n-1;while (i < j){while(i <j&&a[j] > pivot){j--;}if (i < j){a[i] = a[j];i++;}while (i < j&&a[i] <= pivot){i++;}if (i <j){a[j] = a[i];j--;}}a[i] = pivot;//此时i == j; if (i > 1){quicksort(a,i) ;//左递归 }if (n-i-1>1){quicksort(a+i+1,n-i-1);//右递归 }
}
5.3 快速排序的复杂度、稳定性以及使用场景
5.3.1 时间复杂度
快速排序涉及到递归调用,所以快速排序的时间复杂度需要从递归算法的复杂度说起。
递归算法的时间复杂度为:T(n) = aT[n/b]+f(n)。
(1)最好情况就是每一次取到的元素都刚好平分整个数组
此时,时间复杂度为:T(n) = 2T[n/2]+f(n)
下面来推算下,在最优的情况下快速排序时间复杂度的计算(用迭代法):
T[n] = 2T[n/2] + n ----------------第一次递归
令:n = n/2 = 2 { 2 T[n/4] + (n/2) } + n ----------------第二次递归
= 2^2 T[ n/ (2^2) ] + 2n
令:n = n/( 2^(m-1) ) = 2^m T[1] + mn ----------------第m次递归(m次后结束)
当最后平分的不能再平分时,也就是说把公式一直往下跌倒,到最后得到T[1]时,说明这个公式已经迭代完了(T[1]是常量了)。 .
得到:T[n/ (2^m) ] = T[1] ===>> n = 2^m ====>> m = logn;
T[n] = 2^m T[1] + mn ;其中m = logn;
T[n] = 2^(logn) T[1] + nlogn = n T[1] + nlogn = n + nlogn ;其中n为元素个数
又因为当n >= 2时:nlogn >= n (也就是logn > 1),所以取后面的 nlogn;
因此,快速排序最好的情况下时间复杂度为:O(nlogn)。
(2)最差情况就是每一次取到的元素就是数组中最小/最大的,这种情况其实就是冒泡排序了(每一次都排好一个元素的顺序)
因此,快速排序最差的情况下时间复杂度为:O(n^2)。
(3)平均时间复杂度:从最好情况的分析中可知,快速排序的最好情况就是按平均来的
因此,快速排序的平均时间复杂度等于最好情况下的时间复杂度,也为:O(nlogn)。
5.3.2 空间复杂度
快速排序使用的空间是O(1)的,也就是个常数级;而真正消耗空间的就是递归调用了,因为每次递归就要保持一些数据,其空间复杂度为O(logn)。
5.3.3 排序稳定性
在快速排序中,每一趟排序都需要选择pivot(基准)。此时,基准两边可能出现和基准元素相同的值。如序列[1,5,2,4,5,4,6,5],如果选择了a[4]作为基准因子,那么a[1]和a[7]势必会被分到基准因子的同一侧,序列的稳定性被破坏。所以,快速排序是一种不稳定的排序算法。
5.3.4 使用场景
待排序序列元素较多,并且元素较无序
十大排序算法笔记(C语言)(一)选择排序、冒泡排序、插入排序、希尔排序、快速排序相关推荐
- 数据挖掘十大经典算法笔记
主要总结一下数据挖掘十大经典算法,包括各自优缺点, 适用数据场景,做个小笔记,分享一下 数据挖掘主要分为分类算法,聚类算法和关联规则三大类,这三类基本上涵盖了目前商业市场对算法的所有需求.而这三类里又 ...
- python 按条件选择行和列数据_小白学数据结构-排序算法Python(冒泡、选择、快速、希尔等等)...
排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 我们通常所说的排序算法往往指的是内部排序算法,即数据 ...
- JavaScript 几种排序算法实现(冒泡、选择、插入、归并、快速排序)
1. 冒泡 // 冒泡 - 每次循环, 将两两中偏大的元素移动到右边 for (let i = 0; i < arr.length - 1; i++) {for (let j = i; j &l ...
- 常见排序算法(C语言实现)
常见排序算法(C语言实现) 文章目录 常见排序算法(C语言实现) 一.插入排序 二.希尔排序 三.选择排序 四.堆排序 五.冒泡排序 六.快速排序 七.归并排序 一.插入排序 void insertS ...
- c语言动画原理,动画详解十大经典排序算法(C语言版)
排序算法是程序员必备的基础知识,弄明白它们的原理和实现很有必要.本文中将通过非常细节的动画展示出算法的原理,配合代码更容易理解. 概述 由于待排序的元素数量不同,使得排序过程中涉及的存储器不同,可将排 ...
- C语言——十四种内部排序算法【直接插入排序-冒泡排序-选择排序-插入排序-希尔排序-归并排序-快速排序-堆排序-折半插入排序-二分查找-路插入排序-表插入排序-简单选择排序-直接选择排序-树形选择】
目录: 一:插入排序 A:直接插入排序 1.定义: 2.算法演示 实例1: 3.基本思想 4.排序流程图 实例1: B:希尔排序 1.定义: 2.算法演示 实例2: C:其他插入排序 a:折半插入排序 ...
- JS的十大经典算法排序
更正(2018/5/31):如果看的是原文章的话,注意希尔排序少一个等号,在本博中,我已经添加上了,希尔排序(更正后)及以前的经测试都是正确的,后面的我正找时间持续研究验证中--(过程可能有点慢) 更 ...
- 经典十大排序算法(含升序降序,基数排序含负数排序)【Java版完整代码】【建议收藏系列】
经典十大排序算法[Java版完整代码] 写在前面的话 十大排序算法对比 冒泡排序 快速排序 直接选择排序 堆排序 归并排序 插入排序 希尔排序 计数排序 桶排序 基数排序 完整测试类 写在前面的话 ...
- 决策树C4.5算法 c语言实现,数据挖掘十大经典算法(1) C4.5_决策树算法
数据挖掘十大经典算法(1) C4.5_决策树算法 机器学习中,决策树是一个预测模型:他代表的是对象属性与对象值之间的一种映射关系.树中每个节点表示某个对象,而每个分叉路径则代表的某个可能的属性值,而每 ...
- 十大经典算法总结(JavaScript描述)
前言 读者自行尝试可以想看源码戳这,博主在github建了个库,欢迎star.读者可以Clone下来本地尝试.此博文配合源码体验更棒哦~~~ 个人博客:Damonare的个人博客 原文地址:十大经典算 ...
最新文章
- Cocos2d-x 3.0正式版及android环境搭建
- 2019 年如何在 CentOS 7 上安装最新版 Nginx
- 一键移植工具_让UI设计畅通无阻 — 信息系统人机界面增强工具(HFE Designer)
- spring源码分析-core.io包里面的类
- Java 文件操作二(重命名、设置只读、是否存在、指定目录中创建文件、获取文件修改日期、创建文件、文件路径比较)
- 零基础小白学习UI设计的4个步骤
- 集中器到服务器传输协议,集中器130通讯协议(捷先数码).doc
- Cpdetector编码识别
- ElasticSearch学习笔记(二)
- 网卡bonding配置
- [译]Chipmunk教程 - 5 跟踪球体的运动
- 数值分析第八章知识点总结——常微分方程数值解法
- Unity3d iOS 内购详细流程总汇
- 产品经理面试,设计攻略
- 安装光盘并重新启动计算机戴尔,戴尔电脑怎么设置光盘启动
- ShenYu 网关源码学习(1)- 简单介绍、编译和测试
- 基于react+antd的后台管理模板
- python绘制小提琴图_Python:matplotlib 和 Seaborn 之热图、小提琴图和箱线图 (三十四)...
- GAN (Generative Adversarial Nets 生成对抗网络)
- matlab中函数参数和变量作用域
热门文章
- 带你玩转Visual Studio——Property Manager的配制
- puppet自动化部署
- 一个因全局变量引发的故事!
- 编译小程序,开发者工具打开报错Cannot read property ‘createTextNode‘ of undefined或iphone机型无法预览
- springboot 微信支付接口
- SpCL阅读笔记:Self-paced Contrastive Learning with Hybrid Memory for Domain Adaptive Object Re-ID
- Windows系统下通过文件路径进入相应DOS界面
- PHP获取以毫秒级为单位获取当前时间
- 愿以三生烟火,换君一世迷离
- C. Minimum Ties