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)的前面,所以他不稳定。
插入排序:稳定,和冒泡的含义一样,只有大于才会交换。
希尔排序:不稳定,和选择含义一样,他是分组的,分组交换,交换后可能就把后面的换到前面去了。
归并排序;稳定。他在辅助数组那步才是真正的比较,也是类似于比大小,大于才能交换。所以是稳定的。
快速排序:不稳定,快速排序是找一个临界值,当他们都要放在临界值一边时,放的顺序可能就和之前的前后顺序不一样了。所以他是不稳定的。
总结:在排序中,如果一次排序就行,我们尽量选择那些性能高的,时间和空间复杂度符合我们要求的。如果多次排序,我们要选择稳定性高的,不会发生顺序倒乱。