文章目录
前言
提示:本人不喜欢用专业术语来记录知识点,所以接下来会用例题+白话文的方式记录:
交换排序的基本思想是两两比较待排序记录的关键字,若两个记录的次序相反则交换这两个记录,直到没有反序的记录为止。应用交换排序基本思想的主要排序方法有冒泡排序和快速排序。
提示:以下是本篇文章正文内容,下面案例可供参考
接上一篇插入排序
二、交换排序
1、冒泡排序
思想:
就是把待排序的数组从上到下存放,把关键字较小的记录看成 “较轻的”,关键字较大的记录看成 “较重的”,(关键字大的看成石块,会往下沉;关键字小的看成水蒸气泡,会往上浮;最后气泡浮起来,石头沉下去,排序就结束了)
- 此处引用网上一张比较经典的gif来展示冒泡排序的整个过程:
基本步骤:
比如说现在有ABCDE…这些数,越往后关键字越大,
他们一开始从上到下都是无序的,相邻两个比较,也就是两两比较。如果大的在上,小的在下,就进行交换,直到大的在下,小的在上为止
代码部分
public void bubbleSort() {
RecordNode temp; //辅助结点
boolean flag = true; // 是否交换的标记
for (int i = 1; i< this.curlen && flag; i++){
//有交换时再进行下一趟,最多n-1趟
flag = false; //记录未交换
for(int j = 0; j<this.curlen - i; j++){
//一次比较、交换
if (r[j].key.compareTo(r[j + 1].key) > 0){
//逆序时,交换
temp = r[j];
r[j] = r[j + 1];
r[j + 1] = temp;
flag = true; //记录交换
}
}
}
}
例题:
假设待排序的8个记录的关键字序列为 { 52,39,67,95,70,8,25,52 }冒泡排序过程如下图所示。
画法一:
画法二:
步骤:
第一趟:下标 0 和 1 比较,1 和 2 比较,2 和 3 比较,3 和 4 比较.。。。。。。小的在上,大的在下
第二趟、第三趟。。。以此类推
写的那个虚线以下是已经排好的,有序的,不需要再排了
性能分析
(1)、时间复杂度:
O(n2)
(2)、所需辅助空间:
只需一个记录的辅助空间 O(1)
(3)、算法稳定性:
是稳定的排序方法
2、快速排序(以第0个元素为枢轴)
思想:
通过一趟排序将要排序的记录分割成独立的两个部分,其中一部分的所有记录的关键字值都比另外一部分的所有记录关键字值小,然后再按此方法对这两部分记录分别进行快速排序,整个排序过程可以递归进行,以此达到整个记录序列变成有序。
首先找一个记录,以它的关键字作为“枢轴”,凡其关键字小于枢轴的记录均移动到左边,反之,凡关键字大于枢轴的记录均移动到右边。
- 此处引用网上一张比较经典的 挖坑gif 来展示快速排序的整个过程:
先设第一个位为坑位,也就是下面要讲的枢轴,接下来坑位不动,假如 key 在最左边,另一端的指针 R 就开始 - - ,直到找到比 key 小的值,找到了就去覆盖坑位,然后自己再变成新的坑位,再次遍历左边 L 开始 + +,直到找到比 key 大的值,找到了就去覆盖坑位,然后自己再变成新的坑位,然后再回到 R 重新开始,以此类推,直到 L 和 R 站在同一个坑位上,把刚开始时设的第一个数放进去就完成了排序。
代码部分
int Partition ( int i, int j) {
RecordNode pivot = r[i]; // 将第1个记录作为枢轴
while (i<j) {
//从表两端交替向中间扫描
while(i<j && pivot.key.compareTo(r[j].key) <=0{
j--; // 从右向左搜索
if (i<j) {
r[i] = r[j]; //将比枢轴记录关键字值小的记录向前移动到下标为 i 的位置上
i++;
}
while (i<j && pivot.key.compareTo(r[i].key)>0){
i++; // 从左向右搜索
if (i<j) {
r[j] = r[i]; //将比枢轴记录关键字值大的记录向后移动到下标为 j 的位置上
j--;
}
}
r[i] = pivot; //枢轴记录到位
return i; //返回枢轴位置
} // Partition
例题一:
52 49 80 36 14 58 61 97 23 75
一趟快速排序
解:
步骤:
首先设第一个数52为枢轴,从后往前找
将 r[j].getKey ()和 枢轴关键字进行比较,要求r[j].key ≥ 枢轴的关键字;
在这题上也就是看 75 和 52 比较,大的在右边
因为 75 比 52 大,所以不用动,因为本身 75 就在右边
然后 j 减减
这回 23 比 52 小,就需要交换,赋值到 i 的位置,从左边开始找,然后需要 i 加加了
将 r[i].key 和 枢轴关键字进行比较,要求r[i].key ≤ 枢轴的关键字。
i + + 后到 49,49 比 52 小,49 在左边是对的,不需要交换,然后 i 再加加
i + + 到 80 的位置,80 比 52 大,把它赋值给 j 的这个位置
然后 j 减减,到 97 的位置,97 比 52 大,不需要动
然后 j 再减减,到 61 的位置,61 比 52 大,也不需要动
然后 j 再减减,到 58 的位置,58 比 52 大,也不需要交换
然后 j 再减减,直到找到一个比枢轴 52 小的
j - - 到 14 的位置,14 比 52 小,这回需要把 14 交换到 i 的位置
交换到左边之后,i 再加加,到 36 的位置
36 比 52 小,不需要交换
然后 i 再加加,发现 i 和 j 指向了同一个数,相等了,当 i 和 j 相等了
之后就发现 52 在整个排序中的位置就找到了
我们可以发现 52 左边的值都比 52 小,52 右边的值都比 52 大
例题二:
写出对关键字序列
{ 39,2,12,40,34,33,50,1,55,60 }
进行,快速排序的第一趟结果
解:
步骤:
先取枢轴:39(第一个),然后定义两个变量 i ,j,左边 i ,右边 j
然后从后往前找比39小的
60 比 39 大,不用管,
55 比 39 大,不用管,
然后到 1 这个位置,1 比 39 小
1 就到左边 i 的位置
这里到左边 i + +,找比 39 大的交换到右边
2 比 39 小,不用动
12 比 39 小,不用动
直到 40 这个位置,比 39 大
就把 40 交换到 j 的位置
这就到 j 的位置了,再进行 j - -
再找比 39 小的
50 比 39 大,不用动,然后指向 33,比 39 小,
就把 33 交换到 i 的位置
又到 i 这边了,i + +
找比 39 大的,移动到 j 的位置
34 比 39 小,不用动
当指向 33 的时候, i 和 j 相等了
所以这个位置就是枢轴的位置
最后发现左边数字比 39 小;右边数字比 39 大
性能分析
(1)、时间复杂度:
O(nlog2n)
(2)、所需辅助空间:
O(log2n)
(3)、算法稳定性:
是不稳定的排序方法
总结
冒泡排序
冒泡排序其实挺简单的,就是两两比较,然后数字大的在下面 / 后面,数字小的在上面 / 前面
快速排序
首先取枢轴第一个数,再取两个变量 i 和 j,i 是 0, j 是数组的长度减一
然后从 j 开始往前找,找到一个比枢轴小的数,交换给左边 i 的位置,
然后 i + + ,往右找,直到找到一个比枢轴大的数,交换到右边 j 的位置
到右边位置后,j - -,找到一个比枢轴小的数,交换给刚才左边 i 的位置,
这回又到左边, i + + ,再往右找,直到找到一个比枢轴大的数,交换到右边 j 的位置
直到 i 和 j 相等,相等的这个位置就是枢轴的位置
最后左边序列比枢轴小;右边序列比枢轴大