交换类排序:冒泡排序(优化)和快排

本文详细介绍了冒泡排序和快速排序两种经典的排序算法。包括它们的基本思想、时间复杂度、空间复杂度及稳定性等特性,并提供了具体的实现代码。此外,还探讨了几种排序算法的优化方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

冒泡排序:

思想:交换类排序,两两交换,每趟交换完成后都会有一个最大的被冒到后面
性能
* 时间复杂度:O(n^2)
* 空间复杂度:O(1)
* 稳定:稳定
代码
//两两交换,每趟交换之后都会冒出一个最大的放在后面,
void maopao(int a[],int n){
    for (int i = 0; i<n;i++) {
        for (int j = 0; j<n-i-1; j++) {
            if (a[j]>a[j+1]) {
                int temp;
                temp = a[j];
                a[j] = a[j+1];
                a[j+1] = temp;

            }
        }
    }

}
例子:8,7,6,5,4

第一趟冒泡::最大值8被放到最后面

7,8,6,5,4--------》8和7交换
7,6,8,5,4--------》8和6交换
7,6,5,8,4--------》8和5交换
7,6,5,4,8--------》8和4交换

第二趟冒泡::最大值8被放到最后面

6,7,5,4,8--------》7和6交换
6,5,7,4,8--------》7和5交换
6,5,4,7,8--------》7和4交换
后面的也一样:其实就是每次从前面比较出一个最大的放到后面,
时间复杂度:o(n2) 

冒泡优化1:之设置标记位:

举例:对于1,2,3,5,4
按照普通的冒泡
第一趟

1,2,3,5,4--------->1和2没有
1,2,3,5,4--------->2和3没有
1,2,3,5,4--------->3和4没有
1,2,3,4,5--------->4和5进行了交换//这里已经完全有序了

第二趟

1,2,3,4,5--------->1和2没有
1,2,3,4,5--------->2和3没有
1,2,3,4,5--------->3和4没有
1,2,3,4,5--------->4和5没有

可以看出,在已经有序的情况下,还是会按照上面的方式重新比较,即使没有发生交换,所以这里就有一个优化的思路,设置一个标志位,每趟冒泡将其置为 true,当这一趟发生交换时把他置为 false,继续循环,若一趟结束没有发生一次交换,说明已经有序,也就是标志位一直为 true,就可以 break 跳出循环
代码如下

//优化后的冒泡,一个标志位:每一趟循环之前设置标记为 true,当一趟遍历发生交换记录将标记为改为 false,当某一趟遍历结束还没有发生交换时,说明已经有序,所以就不会置为 false;
void maopao1(int a[],int n){
    int  flag ;//标志位
    for (int i = 0; i<n;i++) {
        flag = 1;//每趟循环之前设置为 true
        for (int j = 0; j<n-i-1; j++) {
            if (a[j]>a[j+1]) {
                flag = 0;//当发生了交换将其置为 false
                int temp;
                temp = a[j];
                a[j] = a[j+1];
                a[j+1] = temp;

            }
        }
        //如果一趟冒泡之后没有发生任何交换,说明已经有序,跳出循环
        if (flag) {
            break;
        }
    }

}

演示结果
第一趟:flag 为 true

1,2,3,5,4--------->1和2没有
1,2,3,5,4--------->2和3没有
1,2,3,5,4--------->3和4没有
1,2,3,4,5--------->4和5进行了交换//flag 被置为 flase

第二趟:flag 为 true

1,2,3,4,5--------->12没有
1,2,3,4,5--------->23没有
1,2,3,4,5--------->34没有
1,2,3,4,5--------->45没有//这一趟没有发生任何交换,flag 依然为 true,就可以跳出循环了

冒泡优化之:记录上一趟最后交换的位置

代码如下

//优化的冒泡,设置一个下表记录上次最后一次发生交换的位置,该位置前面的没有发生交换,说明已经有序,那么下次就可以缩小范围,最他后面的进行排序
void maopao2(int a[],int n){
    int lsp=0;//交换每趟结束之后最后一次交换的位置
    int lspt=0;//记录每趟之中交换的位置
    for (int i = 0;i<n-1; i++) {
        lsp = lspt;
        for (int j=n-1; j>lsp; j--) {
            if (a[j-1]>a[j]) {
                int temp;
                temp = a[j];
                a[j] = a[j-1];
                a[j-1] = temp;
                lspt = j;
            }
        }
        if (lspt == lsp) {
            break;
        }
    }
}

演示如下
第一趟

5,7,1,4,2,3------->2和3没有交换
5,7,1,2,4,3------->2和4发生交换,当前的 j 是4,所以本次交换的位置为4
5,7,1,2,4,3-------->1和 2没有交换
5,1,7,2,4,3-------->1和7发生了交换:当前 j 是2,所以本次交换的位置为2
1,5,7,2,4,3-------->1和5发生了交换,当前 j 是1,所以本次交换的位置为1

第一趟结束以后,最后一次发生交换的位置为1,之前的没有再发生交换,说明已经有序,那么下一趟要排序的范围就缩小到1~n,而不是0~n
第二趟

1,5,7,2,3,4--------->4和3交换,当前 j 是5,所以本次交换的位置为5;
1,5,7,2,3,4---------->2和3没有交换
1,5,2,7,3,4---------->7和2发生了交换,当前 j 是3,所以本次交换的位置为3
1,2,5,7,3,4---------->5和2发生了交换,所以当前位置为2,所以本次交换的位置为2

第二趟结束后,最终交换位置为2,说明2号位置前面已经有序,下次缩小范围 2~n 就可。

快排

  1. 思想:
    • 选中一个key,一般以待排序序列的第一个作为key
    • 从前往后找比key大的放在key的后面
    • 从后往前找比key小的放在key的前面
    • 一趟排序,数组被划分成了两个部分:比key小的和比key大的,对每一部分递归操作
  2. 性能
    • 时间复杂度:
      1. 取决于快排递归的深度,用递归树来描述
      2. 最优情况下,每次划分均匀,平衡二叉树,递归树深度为log2n,第一次要对整个数组扫描一遍,需要n次比较,所以是o(nlogn)
      3. 最坏情况下,待排序列为正序或者逆序,退化成一颗斜树,所以是O(n^2)
      4. 平均:O(nlogn)
    • 空间复杂度:主要是递归造成的栈空间的使用
      1. 最好情况:log2n,空间复杂度:O(logn)
      2. 最坏情况:O(n)
      3. 平均情况:O(logn)
    • 稳定性
      1. 关键字的比较和交换是跳跃的
      2. 不稳定
  3. 代码
 */
void quickSort(int a[],int l,int r){
    if (l<r) {
        //i和j作为两个指针,i++找比当前key小的,j--找比key大的
        int i = l;
        int j = r;
        int key = a[i];
        while (i<j) {
            //从后往前找找比key小的
            while (i<j&&a[j]>key) {
                j--;
            }   
            if (i<j) {
                a[i++] = a[j];
            }
            //从前往后找找比key大的
            while (i<j&&a[i]<key) {
                i++;
            }
            if (i<j) {
                a[j--] = a[i];
            }

        }
        a[i] = key;
        quickSort(a, l, i-1);
        quickSort(a, i+1, r);
    }
}
  1. 优化
    * 随机产生key
    * 三数取中:左边、右边、中间取一个值在中间的作为key
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值