前言
排序在数据结构中占有非常重要的地位,我们在前面二叉树的数组实现时也用到了堆排序,下面我们就系统地讲一下排序。
1. 排序及其运用
1.1 什么是排序
所谓排序,就是使⼀串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
1.2 排序的运用
购物软件筛选排序
院校排名
1.3 常见排序算法
2. 实现常见的排序算法
这里使用一个简单的无序数组实现各种排序
int arr[] = {9,5,3,4,6,1,2,8,7};
2.1 插入排序
思想:将待排序的记录按照关键值的大小逐个插入到一个已排好序的有序序列中,直到所有的记录都插入完为止,得到一个新的有序序列。
我们玩的扑克牌就运用到了插入排序的思想。
2.1.1 直接插入排序
简单来说,就是将9和5进行排序,排序好了之后再来看3,将3插入到已经排好序的9,5排序中,3小于9,9的位置后移,3比5小,五的位置后移,最后将3插入最前面的位置。排好后就是359,再看4,以此类推,直到所有的数据都排好。
因为每次的新数据都与原数据进行比较,所以我们需要用tmp将新数据存储起来。在一开始设置一个end为i的下标表示已排好序的最后一个位置,然后tmp是排好序后面的第一个数据,即end+1。这里我们进行升序排序,如果tmp的值小于end的值,那就将tmp位置的值变为end位置的值,然后end--,依次类推,直到找到tmp的值大于end的值,然后就将end位置后面的空余位给tmp值,如果一直没有找到tmp大于end的位置,那么end就会变为-1,然后end+1为0,将第一个位置给tmp。
时间复杂度:分两种情况:
如果遇到降序存储的数组,依次需要移动1,2,3,。。。。n-1次。然后得到就是时间复杂度为O(n^2)。
如果遇到升序的数组,时间复杂度就是O(1)。
空间复杂度:O(1)。
特点:元素集合越接近有序,时间效率越高。
2.1.2 希尔排序
希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定⼀个整数(通常是gap =n/3+1),把待排序文件所有记录分成各组,所有的距离相等的记录分在同⼀组内,并对每⼀组内的记录进行排序,然后gap=gap/3+1得到下一个整数,再将数组分成各组,进行插入排序,当gap=1时,就相当于直接插入排序。
通俗来讲,就是将待排序集合按照一定的间距分为数组,例如间距为3,总共有9个数据,那么下标为0,3,6的数据就是一组,1,4,7的数据为一组,2,5,8的数据为一组。将各组数据进行类直接插入排序后,再将gap缩小,再进行排序操作,最后直到gap为1,则是直接插入排序。
希尔排序是在直接插入排序上面进行的优化,综合来说它的效率高于直接插入排序。
代码实现:
分析:因为最后一次是直接插入排序,为了避免造成最后一次gap直接为0的情况,我们将gap= gap/3+1。其余的代码就跟直接插入排序没什么区别,除了将end--和end+1分别变成了end-gap,end+gap。
时间复杂度:希尔排序的时间复杂度为O(n^1.3)。
空间复杂度:O(1)。
2.2 选择排序
选择排序思想:是通过每次选择出最大或最小的数据按要求放到数组尾部或头部。
2.2.1 直接选择排序
简单来说,就是遍历数组每次找到最大的数据,如果最大的数据是尾部,则不进行交换,如果不是,则进行交换。
代码实现:
我们这里对直接选择排序进行简单优化,在找最大数据的时候也找最小数据。将最前面的数据设置为假的最大和最小,然后遍历数组真的找最大最小。遍历完之后对max和end进行交换,对min和begin进行交换。然后将end--,begin++,让后面的遍历个数依次减少。
注意,如果是9,3,1这种情况,会发现我们的代码会有点缺陷。即交换完了之后还是9,3,1。所以我们通过再添加一个条件,如果最大值在begin,最小值在end,我们就将最大值的下标变为最小值的下标,这样运行时就先让end进行自交换,然后再交换begin和min,就实现了直接选择排序。
时间复杂度:while循环时间复杂度为O(n),内部为O(n)。所以为O(n^2)。
空间复杂度:O(1)。
2.2.2 堆排序
关于堆排序,已经在之前的博客里面讲解过,这里仅提供博客链接。
堆排序以及topk问题的解决 · 945d050 · 重邮阿江/c_study_experience - Gitee.com
2.3 交换排序
交换排序的基本思想:比较两个相邻的数据,将较大的数据向后移动,较小的数据向前移动。
2.3.1 冒泡排序
冒泡排序从头比较两个相邻的数据,数据较大的向后移动,每轮遍历排好一个最大的数据。
分析:一个for外循环表示遍历次数,一个for内循环表示遍历的下标数,在每次遍历的时候,如果遇到前者大于后者的情况,则进行交换,把较大的数移到后面。
优化:如果遇到已经是升序的情况,为了避免浪费资源,我们设置一个exchange为0,如果一次遍历完之后,没有进行交换的情况,那么这个数组说明是升序的,我们直接退出。
时间复杂度:O(n^2)。
空间复杂度:O(1)。
3. 源码
排序 · 79a3b38 · 重邮阿江/c_study_experience - Gitee.com