基本排序算法 (六种,堆排序除外)及其稳定性

1.冒泡排序

冒泡排序就是依次比较相邻的两个元素,并且根据大小交换的过程。每一轮都能找出一个最大的元素,并让他能到对应的位置。

举例:如果初始数组是。

6,5,4,3,2,1

第一次冒泡:索引一开始在0处。6 > 5交换 ,索引变为1,6 大于4 交换,依次,6 大于3交换,6 大于2 交换,6 大于1交换。得到5,4,3,2,1,6

第二次冒泡因为已经找到了最大值,并把他放到了最右边,所以我们不用交换最后 一组了。

得到 4,3,2,1,5,6

第三,四,五,六次冒泡都是重复了以上过程,最后得到1,2,3,4,5,6,这也是冒泡排序最糟糕的情况,那就是逆序数组,此时会经历两次完整的for循环,时间复杂度为O(n2)

平均时间复杂度O(n2)

空间O(1)

实现代码

测试代码:

输出结果: 

2.选择排序

选择排序就是根据索引来找到每次循环最小的那个元素的索引,然后把它放到相对最边上的位置。重复 过程,直到排序成功。初始一开始最小索引为0

举例:5,3,4,7,1,9

第一次:假设索引为0处最小,然后往后寻找,发现5大于3,于是索引更新为3处的位置1,接着往后找发现3大于1,于是索引更新为1在的位置4。最后交换初始索引0与最后索引4处的两个元素。

数组变成1,3,4,7,5,9

第二次,索引从1开始,重复以上步骤,数组变成1,3,4,7,5,9

之后一直重复以上过程,直到排序完成

平均时间复杂度O(n2)

空间O(1)

实现代码:

测试代码:

结果

3.插入排序:

插入排序就是初始索引0处的元素不动,从索引1处元素开始,依次和前面的元素两两比较,如果小于前面的元素就交换。直到不能交换时,此时他的位置一定是能够刚好时拍完序的数组形成正序的。然后索引加一后继续

举例:5,3,8,4,1,9

第一次:我们从3开始,3小于5,于是变成

        3,5,8,4,1,9

第二次:我们从8开始,不变

第三次:我们从4开始,4小于8,交换。4又小于5,交换变成

        3,4,5,8,1,9

第四次:我们从1开始,一直小一直交换,变成

        1,3,4,5,8,9

最后一次:不变,得到1,3,4,5,8,9

时间复杂度 O(n2)

空间O(1)

代码实现:

测试: 

------------------------------------以上排序属于基本排序---------------------------------------------- 

4.希尔排序

希尔排序就是增强版的插入排序,属于一种分组来进行排序的算法。他有一个增长量h,每次都是相距h的两个元素进行比较,然后每次h都会变化。

首先我们要确定增长量h的改变:

举例:4,6,5,2,7,8,1,9,0,3

首先:数组的长度为10,10 / 2 = 5,第一轮确定h = 7

于是比较索引0处与7处两个值,9 大于4,不变。比较索引1与索引8处两个值,0小于6,交换。重复步骤,最后变成

        4,0,3,2,7,8,1,9,6,5

第二轮:h = h / 2 = 3

        2小于4,交换。1小于4小于2,交换。5大于4,大于2,大于1,不变。

        1,0,3,2,7,8,4,9,6,5

        0小于7,不变,7小于9,不变

        1,0,3,2,7,8,4,9,6,5

        3小于8,不变,8大于6,交换

        1,0,3,2,7,6,4,9,8,5

第三轮 h = h / 2 = 1

        变为了插入排序

最后:

        0,1,2,3,4,5,6,7,8,9

时间复杂度:要根据步长分析

空间O(1)

实现代码:

测试:

 

5.归并排序

归并排序主要是一种分而治之的思想,他把要排序的数组利用递归切分成最小的子序列,然后相邻分别比较。利用辅助数组来时刻排序。二分法是主要思想

首先我们要切分数组为最小的子序列,利用sort的重载方法,与递归,将他们切分为单个的数,

 

接着我们要建立辅助数组,并且利用辅助数组进行相邻排序。排完序后进行递归完成后的排序,然后回溯回去重复此步骤。

 

 

 举例 

8,4,5,3,1,2,5,3

首先利用sort递归,我们会切分为单个的子序列,然后进行merge排序。

4,8,3,5,1,2,3,5

然后子序列回溯成两个的子序列,继续进行merge排序

3,4,5,8,1,2,3,5

最后分成四个的子序列,排序

1,2,3,3,4,5,5,8

排序完成

6.快速排序

 

快速排序是利用分组的思想,每次我们都选取序列第一个元素作为一个key。然后我们要把大于他的放到他的右边,小于他的我们放在他的左边。此处我们利用双指针方法,左指left,右值right,left找大于他的,right找小于他的,然后交换,直到终止条件为left与right重合时停止,这时我们可以确定终止指针,左边的都小于key,右边的都大于key。然后交换此终止指针的位置与key的位置,把key的左右再分为两组,再重复此步骤,最后直到分为最小的子序列为止。

首先定义sort递归。

 然后我们要返回每次递归要找的那个索引,以这个索引的左右分组。

 

排序的稳定性:如果在一个数组中有相同的元素,排完序后他们的前后顺序依然不变,则称稳定。

例如:1,3,5(1), 5(2), 4  排完后,5(1)依然在5(2)的前面 则是稳定性的

意义:在多次排序时才有意义,一次排序时没有意义。

冒泡:稳定,因为只有当a[i] > a[i++]时才会交换。

选择:不稳定 因为选择排序是把元素放在对应的索引上,例如 5(1),5(2),3,1在第一轮过后,5(1)和 1交换了位置,5(2)跑到了5(1)的前面,所以他不稳定。

插入排序:稳定,和冒泡的含义一样,只有大于才会交换。

希尔排序:不稳定,和选择含义一样,他是分组的,分组交换,交换后可能就把后面的换到前面去了。

归并排序;稳定。他在辅助数组那步才是真正的比较,也是类似于比大小,大于才能交换。所以是稳定的。

快速排序:不稳定,快速排序是找一个临界值,当他们都要放在临界值一边时,放的顺序可能就和之前的前后顺序不一样了。所以他是不稳定的。

    

总结:在排序中,如果一次排序就行,我们尽量选择那些性能高的,时间和空间复杂度符合我们要求的。如果多次排序,我们要选择稳定性高的,不会发生顺序倒乱。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值