排序算法作为算法和数据结构的重要部分,系统地学习一下是很有必要的。排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。

排序分为内部排序和外部排序:

  • 若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序;
  • 反之,若参加排序的记录数量很大,整个序列的排序过程不可能在内存中完成,则称此类排序问题为外部排序。

常说的的八大排序算法均属于内部排序。如果按照策略来分类,大致可分为:交换排序、插入排序、选择排序、归并排序和基数排序。如下图所示:

下表给出各种排序的基本性能,本篇文章不做详细介绍,具体分析请参看其他博客的详解:

1. 交换排序

1.1 冒泡排序

基本思想:比较相邻元素,每比较一轮,将最大的元素置于比较区间内的最后一个元素。优化点:如果哪一轮比较发现没有需要交换的元素,排序即结束。时间复杂度:平均和最坏情况--O(n的平方),最好情况:O(n),此时给定序列已经排好序。

void bubbleSort(vector<int>& nums) {int n = nums.size();bool needSwap = true;for(int i = 1; i < n && needSwap; i++) {bool needSwap = false;for(int j = 0; j < n - i; j++) {if(nums[j] > nums[j+1]) {swap(nums[j], nums[j+1]);needSwap = true;}}}
}

1.2 快速排序

基本思想:保证区间内每个元素的所有左边元素都小于该元素,所有右边元素都大于该元素。时间复杂度平均情况为:O(nlogn),最坏情况:O(n的平方)(每次选的基准点的元素为最大元素或者最小元素),最好情况: O(nlogn)。

int partition(vector<int>& nums, int left, int right) {int pivotValue = nums[left];while(left < right) {while(left < right && nums[right] >= pivotValue)right--;nums[left] = nums[right];while(left < right && nums[left] <= pivotValue)left++;nums[right] = nums[left];}nums[left] = pivotValue;return left;
}void quickSort(vector<int>& nums, int left, int right) {if(left < right) {int pivotInd = partition(nums, left, right);quickSort(nums, left, pivotInd - 1);quickSort(nums, pivotInd + 1, right);}
}

2. 插入排序

2.1 直接插入排序

基本思想:处理下标为i的元素时,0~i-1的元素已经排好序,需要找到下标为i元素的插入位置。时间复杂度平均情况为:O(n的平方),最坏情况:O(n的平方),最好情况: O(n),此时给定序列已经排好序。

void insertSort(vector<int>& nums) {int n = nums.size();int i = 0, j = 0;for(i = 1; i < n; i++) {int temp = nums[i];for(j = i - 1; j >= 0; j--) {if(nums[j] > temp) {nums[j + 1] = nums[j];} else {break;}}nums[j+1] = temp;}
}

2.2 希尔排序

基本思想:不断缩小插入排序的步长,直到为0时退出,排序结束。时间复杂度平均情况为:O(nlogn),最坏情况:O(n的平方),最好情况: 未知,大概n的1.3次方左右。

void shellShort(vector<int>& nums) {int n = nums.size();int gap = n / 2;int i = 0, j = 0;while(gap > 0) {for(i = gap; i < n; i++) {int temp = nums[i];for(j = i - gap; j >= 0; j = j - gap) {if(nums[j] > temp) {nums[j + gap]  = nums[j];} else {break;}}nums[j + gap] = temp;}gap = gap / 2;}
}

3. 选择排序

3.1 简单选择排序

基本思想:每次选中排序区间内的最小元素(记录其下标),置于排序区间的第一个位置。其平均、最好,最坏时间复杂度均为O(n的平方)。

void simpleSelectSort(vector<int>& nums) {int n = nums.size();for(int i = 0; i < n; i++) {int minInd = i;for(int j = i + 1; j < n; j++) {if(nums[j] < nums[i])minInd = j;}if(minInd != i) {swap(nums[i], nums[minInd]);}}
}

3.2 堆排序

基本思想:将数组视为一颗二叉树,下标为i的元素,其左右树的下标分别为2*i+1, 2*i+2(如果存在的话)。每次取出堆顶元素,进行堆的调整,如果往复,直到堆的大小为1,直接取出堆顶元素即可。其平均、最好,最坏时间复杂度均为O(nlogn)。

  • 如果是升序排序,则采用大顶堆,每次取出当前待排元素中的最大值,将其与最后一个位置的元素进行交换。
  • 如果是降序排序,则采用小顶堆,每次取出当前待排元素中的最小值,将其与最后一个位置的元素进行交换。
void headAjust(vector<int>& nums, int parent, int heapSize) {int left = 2 * parent + 1;int right = 2 * parent + 2;int largestInd = parent;if(left < heapSize && nums[left] > nums[largestInd])largestInd = left;if(right < heapSize && nums[right] > nums[largestInd])largestInd = right;if(largestInd != parent) {swap(nums[parent], nums[largestInd]);headAjust(nums, largestInd, heapSize);}
}void heapSort(vector<int>& nums) {int n = nums.size();for(int i = n / 2 - 1; i >= 0; i--) {headAjust(nums, i, n);}for(int i = n; i > 0; i--) {headAjust(nums, 0, i);swap(nums[0], nums[i - 1]);}
}

4. 归并排序

基本思想:采用分治的思想,先分成很小的子序列,然后依次合并(两路),最后得到排序数组。其平均、最好,最坏时间复杂度均为O(nlogn)。

void merge(vector<int>& nums, int left, int right) {int mid = (left + right) / 2;int *temp = new int[right - left + 1];int i = left, j = mid + 1, k = 0;while(i <= mid && j <= right) {if(nums[i] < nums[j]) {temp[k++] = nums[i];i++;} else {temp[k++] = nums[j];j++;}}while(i <= mid)temp[k++] = nums[i++];while(j <= right)temp[k++] = nums[j++];for(int i = left; i <= right; i++) {nums[i] = temp[i - left];}delete []temp;
}void mergeSort(vector<int>& nums, int left, int right) {if(left < right) {int mid = (left + right) / 2;mergeSort(nums, left, mid);mergeSort(nums, mid+1, right);merge(nums, left, right);}
}

5. 基数排序

基本思想:

(1)找出待排序的数组中最大和最小的元素

(2)统计数组中每个值为i的元素出现的次数,存入数组的第i项

(3)对所有的计数累加(从数组中的第一个元素开始,每一项和前一项相加)

(4)反向填充目标数组:将每个元素i放在新数组的第(i)项,每放一个元素就将(i)减去1

void countSort(vector<int>& nums)
{int n = nums.size();if(n <= 1) return;//确定数组最大值和最小值int max = nums[0], min = nums[0];for (int i = 1; i < n; i++){ if (nums[i] > max)max = nums[i];if (nums[i] < min)min = nums[i];}int len = max - min + 1;// 确定统计数组长度并进行初始化int* count = new int[len];for (int i = 0; i <= len; ++i)count[i] = 0;// 遍历数组,统计每个数出现的次数for (int i = 0; i < n; ++i)++count[nums[i] - min];// 统计数组做变形,后面的元素个数等于前面的元素个数之和, 再加上自身元素的个数for (int i = 1; i <= len; ++i)count[i] += count[i - 1];// 倒序遍历原始数列,从统计数组找到正确的位置,输出到结果数组int* sortedArray = new int[n];for (int i = n - 1; i >= 0; i--){sortedArray[count[nums[i] - min] - 1] = nums[i];        // 找到nums[i]对应的count的值,值为多少,表示原来排序多少,(因为从1开始,所以再减1)count[nums[i] - min]--;        // 然后将相应的count的值减1,表示下次再遇到此值时,原来的排序是多少。}for(int i = 0; i < n; i++) {nums[i] = sortedArray[i];}
}

6. 参考资料

  • https://blog.csdn.net/pushup8/article/details/85196465
  • https://blog.csdn.net/weixin_41872403/article/details/87872448
  • https://blog.csdn.net/zy704599894/article/details/79581238?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase
  • https://blog.csdn.net/qq_41855420/article/details/93653175
  • https://www.cnblogs.com/wyr-123-wky/p/11093919.html

排序算法总结(内排序)相关推荐

  1. 排序算法的详解和分析对比(详细讲解)

    目录 前言 一.排序的概念 二.排序的分类 三.常见排序算法的原理以及思想 1. 直接插入排序 1.1 直接插入排序的思想 1.2 直接插入排序代码实现 1.3 直接插入排序的详细过程 1.4 直接插 ...

  2. 万字长文,助你掌握数据库排序算法

    了解更多Greenplum技术干货,欢迎访问Greenplum中文社区网站 引言 在<深入浅出Greenplum内核>系列直播的第六场中,Greenplum内核研发张桓为大家详细介绍了Gr ...

  3. datatable的数据进行组内排序_排序算法学习分享(四)希尔排序

    排序,也称为排序算法,可以说是我们学习算法的过程中遇到的第一个门槛,也是实际应用中使用得较为频繁的算法,我将自己对所学的排序算法进行一个归纳总结与分享,如有错误,欢迎指正! 排序算法学习分享(一)选择 ...

  4. 这或许是东半球分析十大排序算法最好的一篇文章

    作者 | 不该相遇在秋天 转载自五分钟学算法(ID:CXYxiaowu) 前言 本文全长 14237 字,配有 70 张图片和动画,和你一起一步步看懂排序算法的运行过程. 预计阅读时间 47 分钟,强 ...

  5. java 基础算法教程ppt,基础排序算法(附加java实现)

    七种最基本的排序算法:(面试必会!) 冒泡排序: 最基础的排序算法,从数列最前端开始,两两比较,如果前一个数比后一个数大,那么两个数就交换位置,经过一轮遍历之后,最大的数就到了数列的最后一个位置上,再 ...

  6. 算法:三种简单排序算法

    排序算法比較常见的有:冒泡排序.简单选择排序.直接插入排序:希尔排序.堆排序.归并排序和高速排序算法等. 今天先学习一下前面三种比較简单的算法.排序的相关概念: ①排序的稳定性:两个或多个元素相等.排 ...

  7. 面试必问:十大经典排序算法总结

    0.排序算法的说明0.1 排序的定义 对一序列对象根据某个关键字进行排序. 0.2术语说明 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面:不稳定:如果a原本在b前面,而a=b,排序之后 ...

  8. 经常使用排序算法实现[交换排序之冒泡排序、高速排序]

    相关知识 1. 稳定排序和非稳定排序: 稳定排序算法会按照相等的关键(换言之就是值)维持纪录的相对次序. 假设排序算法是稳定的,就是当有两个有相等关键的纪录R和S,且在原本的列表中R出如今S之前,在排 ...

  9. 10种排序算法基础总结

    基于比较的排序: 基础排序:  冒泡排序:谁大谁上,每一轮都把最大的顶到天花板 效率太低--掌握swap. 选择排序:效率较低,但经常用它内部的循环方式来找最大值和最小值. 插入排序:虽然平均效率低, ...

最新文章

  1. 线下教育地位遭冲击?“AI+教育”公司同台讲了这些事实
  2. 带你学习JQuery:事件冒泡和阻止默认行为
  3. 8 -- 深入使用Spring -- 5...1 启用Spring缓存
  4. pdf2swf无法转换某些文档,提示缺少字体时的处理
  5. 爬虫 spider10——搭建elk平台,开发服务提供者
  6. MongoDB的数据逻辑结构
  7. 关于html:form/html:form特性
  8. 枚举命名规范_UE4 C++基础教程 - 编码规范
  9. 鸿蒙行车记录仪,百度导航新增行车记录仪功能 可消除碰瓷风险
  10. zbrush常用笔刷_如何制作精细模型,ZBrush中常用笔刷介绍
  11. HOW2J 全套教程整理:Java、前端、数据库、中间件、第三方、项目、面试题
  12. 基于 Sharding Sphere,实现数据 “一键脱敏”!
  13. 知识图谱中的结构信息建模
  14. 我转行程序员的那一年(五)
  15. 杜邦线改成焊线_做杜邦线(假)教程
  16. 维盟路由器pppoe服务配置(价值80元的帖子)
  17. js二次压缩工具nodejs版
  18. 【C# 练习】3个可乐瓶可以换一瓶可乐,现在有364瓶可乐。问一共可以喝多少瓶可乐,剩下几个空瓶?
  19. rk3128 debian9 如何配置recover键(长按开机进入loader模式)
  20. php图片点阵,HTML5边玩边学(八)-砖块贴图点阵字

热门文章

  1. MacBook Air忘了管理员密码
  2. 小白IT:Python中的网络编程是什么样?如何传输?三次捂手四次挥手?什么又是粘包呢
  3. 树莓派入门(3)树莓派GPIO学习
  4. 计算机网络5-详述链路层:封装成帧、透明传输、差错控制、链路层协议(SR GBN ALOHA CSMA PPP HDLC)、滑动窗口
  5. winform 图片压缩大小为原图的一半_这款压缩工具让我找得好辛苦
  6. Thinkpad笔记本指点杆(小红点)自动漂移的问题
  7. FPGA:基础入门按键控制LED灯
  8. 协方差矩阵的模拟及独立性、相关性的判断
  9. thunderbird 登录网易邮箱
  10. 苹果iPad2 3G版和WiFi版的区别!