数据结构 经典排序算法总结(一)

  • 排序总结
  • 插入排序
    • 直接插入排序
    • 希尔排序
  • 选择排序
    • 简单选择排序
    • 堆排序
  • 推荐阅读

排序总结

经典排序算法是数据结构体系中最重要的内容之一,这一块必须要非常熟练的掌握,应该做到可以立马写出每个排序的代码,有多种实现方法的必须多种都能很快写出来,当然对各个排序的性能的了解也是基础且重要的。我们先对排序这一块进行一个整体的把握。

我们先对整个排序大概总结

名词解释:

排序:排序是将一批无序的记录(数据)重新排列成按关键字有序的记录序列的过程。
稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次 序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排 序算法是稳定的;否则称为不稳定的。
内排序:整个排序过程完全在内存中进行,七大经典排序算法都是内排序。
外排序:由于待排序记录数据量太大,内存无法容纳全部数据,排序需要借助外部存储设备才能完成。

插入排序

直接插入排序

插入排序,一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法。插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表。在其实现过程使用双层循环,外层循环对除了第一个元素之外的所有元素,内层循环对当前元素前面有序表进行待插入位置查找,并进行移动。
思想:每一趟将一个待排序的记录,按其关键字的大小插入到已经排好序的一组记录的适当位置上,直到所有待排序记录全部插入为止。
适用情况:小规模数据 或 者基本有序的数据
时间复杂度和稳定性:O(n)~O(n2) 稳定

在一个乱序的数组中,假如我们想要数组按升序排序。我们可以将数组分为已排好序的部分和未排序的部分。这里我们一开始假设数组中的第一个元素是已经排好序的部分。然后依次遍历未排序的部分,将未排序部分的第一个元素(索引为i)和已排序的最后一个元素对比(索引为end),这里要保存索引为i的值,假设为data,只要比索引为end的元素的值小,索引为end+1元素就等于索引为end的元素,并end- -,也就是向前查找。重复此步骤,直到找到索引为end的元素比data小 或者 end == -1,找到了之后就将data的元素插入到end+1的位置上。要插入的次数为n - 1次,n为数组长度。也就是未排序部分大小。

代码:

#include <stdio.h>//插入排序
void InsertSort(int* arr, int size)
{//空数组  或 只有一个元素的数组if (arr == NULL || size == 1){return;}//遍历未排序的元素for (int i = 1; i < size; ++i){//保存未排序部分的第一个元素int data = arr[i];//已排序的最后一个元素的索引int end= i - 1;while (end >=0 && arr[end] > data){//前面元素覆盖后面元素arr[end + 1] = arr[end];//向前查找--end;}//找到位置并在该位置的下一个位置插入arr[end + 1] = data;}
}

运行结果:

希尔排序

希尔排序也是插入排序的一种,是对简单插入排序的一种扩展和优化。

希尔排序,又称“缩小增量排序”。是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。
思想:让数据越来越接近有序,减少数据移动的次数,从而调高插入排序的性能。
适用情况:即使数据大且无序,效率也很高。
时间复杂度和稳定性:O(n1.3)~O(n2) 不稳定

图解释:

gap为组数,将原来待排序列分为gap组,分别进行插入排序,使每组都变成有序的序列,从而减少整体的插入排序的次数。
代码:

//希尔排序
void ShellSort(int* arr, int size)
{int gap = size;while (gap > 0){gap = gap / 2;//最后一趟排序,间隔必须是1,保证所有有效数据在同一组for (int i = gap; i < size; ++i){//同一组数据,最后一个有序数据的位置int end = i - gap;//待插入排序int data = arr[i];while (end >= 0 && arr[end] > data){arr[end + gap] = arr[end];end -= gap;}arr[end + gap] = data;}}
}

运行结果:

测试直接插入排序 和 希尔排序的效率

void Test()
{int n = 0;printf("数据量: ");scanf("%d", &n);srand((unsigned)time(NULL));int* src = (int*)malloc(sizeof(int) * n);int* dest1 = (int*)malloc(sizeof(int) * n);int* dest2 = (int*)malloc(sizeof(int) * n);for (int i = 0; i < n; ++i){src[i] = rand();}//保证要排序的数据是一模一样的memcpy(dest1, src, sizeof(int) * n);memcpy(dest2, src, sizeof(int) * n);time_t begin = clock();InsertSort(dest1, n);time_t end = clock();printf("InsertSort:%lld\n", end - begin);begin = clock();ShellSort(dest2, n);end = clock();printf("ShellSort:%lld\n", end - begin);
}

运行截图:

我们发现,在数据规模大的时候,希尔排序比直接插入排序的效率高很多。但是,其实对于数据规模小的,已经有序的数据,直接插入排序的效率会高,读者可以自行尝试。

选择排序

简单选择排序

简单选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。
思想:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
适用情况:实现简单思想简单,规模小且不要求稳定性。
时间复杂度和稳定性:O(n2)~O(n2) 不稳定

代码:

void Swap(int* arr, int pos1, int pos2)
{int tmp = arr[pos1];arr[pos1] = arr[pos2];arr[pos2] = tmp;
}
//选择排序
void SelectSort(int* arr, int size)
{for (int i = 0; i < size; ++i){int minIdx = i;for (int j = i + 1; j < size; ++j){if (arr[j] < arr[minIdx]){minIdx = j;}}if (minIdx != i){Swap(arr, i, minIdx);}}
}

运行结果:

堆排序

堆排序:堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序。
思想:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。
适用场景:但有时候你要的不是“排序”,而是另外一些与排序相关的东西,比如最大/小的元素,topK之类,这时候堆排序的优势就出来了。用堆排序可以在N个元素中找到top K,时间复杂度是O(N log K)也就是说,如果你要在很多元素中找很少几个top K的元素,或者在一个巨大的数据流里找到top K,堆排序无疑是最好的选择。
时间复杂度和稳定性:O(nlogn)~O(nlogn) 不稳定

堆排序我们已经在 数据结构 堆.中讲过,写的也比较详细。
这里我就直接放代码

代码:

void ShiftDown(int* arr, int size, int parent)
{int child = 2 * parent + 1;while (child < size){if (child + 1 < size && arr[child + 1] > arr[child]){child++;}if (arr[child] > arr[parent]){int tmp = arr[parent];arr[parent] = arr[child];arr[child] = tmp;parent = child;child = 2 * parent + 1;}else{break;}}
}//堆排序
void HeapSort(int* arr, int size)
{for (int i = (size - 2) / 2; i >= 0; --i){ShiftDown(arr, size, i);}int end = size - 1;while (end > 0){Swap(arr, 0, end);ShiftDown(arr, end, 0);--end;}
}

运行截图:

推荐阅读

数据结构 10分钟让你掌握经典排序(二)

数据结构 10分钟让你掌握经典排序(一)相关推荐

  1. 数据结构 10分钟让你掌握经典排序(二)

    数据结构 经典排序算法总结(二) 交换排序 冒泡排序 快速排序(重要) 归并排序 归并排序 非比较排序 计数排序 交换排序 冒泡排序 冒泡排序:是一种简单的排序算法.它重复地走访过要排序的数列,一次比 ...

  2. 数据结构与算法笔记 —— 十大经典排序及算法的稳定性

    一.十大经典排序算法 排序算法是<数据结构与算法>中最基本的算法之一. 排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全 ...

  3. 我用 Python 3分钟实现9种经典排序算法的可视化

    导读:最近在某网站上看到一个视频,是关于排序算法的可视化的,看着挺有意思的,也特别喜感. 不知道作者是怎么做的,但是突然很想自己实现一遍,而且用python实现特别快,花了一天的时间,完成了这个项目. ...

  4. 十大经典排序算法动画与解析,看我就够了!(附代码)

    作者 | 程序员小吴 来源 | 五分钟学算法(ID:CXYxiaowu) 排序算法是<数据结构与算法>中最基本的算法之一.排序算法可以分为内部排序和外部排序.内部排序是数据记录在内存中进行 ...

  5. 3分钟快速实现:9种经典排序算法的可视化

    作者 | 爱笑的眼睛 来源 | 恋习Python(ID:sldata2017) 最近在某网站上看到一个视频,是关于排序算法的可视化的,看着挺有意思的,也特别喜感. ▼ 6分钟演示15种排序算法 不知道 ...

  6. c 语言从大到小排序算法,10 大经典排序算法(动图演示+ C 语言代码)

    原标题:10 大经典排序算法(动图演示+ C 语言代码) 来源:C语言与CPP编程 以前也零零碎碎发过一些排序算法,但排版都不太好,又重新整理一次,排序算法是数据结构的重要部分,系统地学习很有必要. ...

  7. 【数据结构】八大经典排序(两万字大总结)

    文章目录 排序的基础知识 1. 排序的概念 2. 常见排序分类 3. 排序的运用 常见排序算法的实现 1. 直接插入排序 1.1 排序思想 1.2 代码实现 1.3 复杂度及稳定性 1.4 特性总结 ...

  8. 数据结构十大经典排序算法--Python

    十大经典排序算法 (java实现看这个)https://program.blog.csdn.net/article/details/83785159 名词解释: 1.冒泡排序 2.选择排序 3.插入排 ...

  9. 算法大总结之----10大经典排序算法(从小到大排列)

    目录 1. 冒泡排序 1.1. 算法讲解 1.2. 代码实现 2. 选择排序 2.1. 算法讲解 2.2. 代码实现 3 插入排序 2.1. 算法讲解 2.2. 代码实现 4 希尔排序 2.1. 算法 ...

最新文章

  1. 对 Jenkins+ANT+Jmeter 接口测试的实践
  2. mysql目录权限设置_MySQL文件及目录权限设置分析-爱可生
  3. 项目管理:软件工程相关知识笔记
  4. AdaBoost详解
  5. W25Q128 闪存芯片SPI详解
  6. 数据可视化——利用pandas和seaborn绘图基础
  7. Android模拟器所支持的OpenGL ES扩展
  8. Imagick 处理gif psd格式
  9. 【LeetCode】【字符串】题号:*657. 机器人能否返回原点
  10. java程序中oracle回滚,Oracle的DDL语句不能回滚(直接提交)
  11. 【微信小程序模板直接套用】微信小程序制作模板套用平台
  12. 机器学习考试 ppt
  13. MD5值的简介和查看
  14. d630 无线驱动 linux,DELL D630安装CentOS6的无线网卡驱动
  15. 微信防撤回dll文件制作
  16. 文科生学python简书_文科生Python教程(一)
  17. PV操作与信号灯及例子
  18. C语言实现动态通讯录(附带文件保存)
  19. VSCode中针对C语言的代码格式化配置
  20. 我不知道 我知道你不知道 现在我知道了 我也知道了

热门文章

  1. android通讯录备份软件下载,通讯录同步助手
  2. mba案例分析_2020年(第八届)MBA企业案例分析实践课程暨大赛完美收官!
  3. 生成新的dataframe_Python之Pandas使用系列(九):DataFrame中列操作的技巧
  4. 算天数什么时候加一什么时候不加一_陌陌加公会不加公会的区别?
  5. ib_logfile和mysql_bin_mysql的innodb中事务日志ib_logfile
  6. xp无法使用计算机管理员权限,xp无法无法使用管理员权限运行软件的解决步骤...
  7. 数字倒序Java_怎么用Java编写一个程序,将输入的数字重新倒叙排列?
  8. springboot 分页查询参数_精通SpringBoot--分页查询功能的实现
  9. php写else老是报错,调试PHP错误经常用到的一些
  10. Java Swing Mysql学生成绩管理系统