• 排序——交换排序


    在上篇文章我们详细介绍了排序的概念与插入排序,大家可以通过下面这个链接去看:

    排序的概念及插入排序

    这篇文章就介绍一下一种排序方式:交换排序。

    一,交换排序

    基本思想:两两比较,如果发生逆序则交换,直到所有记录都排好序为止。

    而交换排序又分为两种:

            冒泡排序O(n2)

    快速排序O( nlog2n )

    1,冒泡排序

    A 基本内容

    学习过C语言的朋友应该对这个比较熟悉,其基本思想就是:  

    每趟不断将记录两两比较,并按“前小后大” 规则交换

    如图进行一次冒泡排序的过程:

    21254925*16,  08

    212525*1608 49

    21251608 25*49

    211608 2525*49

    1608 212525*49

    0816212525*49

     冒泡排序的优点:

    每趟结束时,不仅能挤出一个最大值到最后面位置,还能同时部分理顺其他元素; 

        一旦下趟没有交换,还可提前结束排序

    在c语言的代码中实际就是通过两个for循环来实现 

    1. void main()
    2. { int a[11]; /*a[0]不用,之用a[1]~a[10]*/
    3. int i,j,t;
    4. printf("\nInput 10 numbers: \n");
    5. for(i=1;i<=10;i++) scanf("%d",&a[i]); printf("\n");
    6. for(j=1;j<=9;j++)
    7. for(i=1;i<=10-j;i++)
    8. if(a[i]>a[i+1]) {t=a[i];a[i]=a[i+1];a[i+1]=t;}//交换
    9. for(i=1;i<=10;i++) printf("%d ",a[i]);
    10. }

    下面是一个例子 

    下面这段代码与上面的区别是,当遇见数组部分有序时,可以提前结束循环,节省不必要的时间。

    1. 定义了一个名为bubble_sort的函数,接受一个顺序表L作为参数。
    2. 初始化变量m为顺序表的长度减1,flag为1,表示是否需要继续排序。
    3. 使用while循环进行排序,条件是m > 0flag == 1。当m等于0时,说明已经遍历完所有元素;当flag为0时,说明在一次循环中没有发生任何交换,说明已经排序完成。
    4. while循环内部,使用for循环遍历顺序表中的元素,从第一个元素到第m个元素。
    5. for循环内部,比较当前元素L.r[j].key和下一个元素L.r[j+1].key的大小。如果当前元素的键值大于下一个元素的键值,则交换这两个元素的位置,并将flag设置为1,表示发生了交换。
    6. 每次循环结束后,将m减1,缩小未排序部分的范围。
    7. while循环结束时,顺序表L中的元素已经按照升序排列。
    1. void bubble_sort(SqList &L)
    2. { int m,i,j,flag=1; RedType x;
    3. m=n-1;
    4. while((m>0)&&(flag==1))
    5. { flag=0;
    6. for(j=1;j<=m;j++)
    7. if(L.r[j].key>L.r[j+1].key)
    8. { flag=1;
    9. x=L.r[j];L.r[j]=L.r[j+1];L.r[j+1]=x; //交换
    10. }//endif
    11. m--;
    12. }//endwhile
    13. }

    B 冒泡排序的算法分析:

    设对象个数为 n 
    比较次数 移动次数 与初始排列有关

    最好情况下: 只需 1趟排序,比较次数为 n-1,不移动  

    1. while((m>0)&&(flag==1))
    2. { flag=0;
    3. for(j=1;j<=m;j++)
    4. if(L.r[j].key>L.r[j+1].key)
    5. { flag=1; x=L.r[j];L.r[j]=L.r[j+1];L.r[j+1]=x; }
    6. ……

    最坏情况下: n-1趟排序,第i趟比较n-i次,移动3(n-i) 

    冒泡排序

    时间复杂度为 o(n2) 

    空间复杂度为 o(1)

    是一种稳定的排序方法

    2,快速排序

    A 基本内容

    基本思想:

    任取一个元素 ( 如第一个 ) 为中心
    所有比它 的元素一律前放,比它 的元素一律后放,形成 左右两个子表
    对各子表重新选择 中心 元素并依此规则调整,直到每个子表的元素 只剩一个

     在数组中,我们通过两个指针来实现排序过程

     后面也是一样的操作,我们会发现每趟子表的形成从两头向中间交替式逼近,对各子表操作相似,因此我们可采用递归算法来实现对数据的排序过程。

    1. // 快速排序算法
    2. void main()
    3. {
    4. QSort(L, 1, L.length); // 对数组L进行快速排序
    5. }
    6. // 快速排序函数,参数为待排序的数组L,起始下标low和结束下标high
    7. void QSort(SqList &L, int low, int high)
    8. {
    9. if (low < high)
    10. {
    11. pivotloc = Partition(L, low, high); // 获取基准元素的位置
    12. QSort(L, low, pivotloc - 1); // 对基准元素左边的子数组进行快速排序
    13. QSort(L, pivotloc + 1, high); // 对基准元素右边的子数组进行快速排序
    14. }
    15. }
    16. // 划分函数,参数为待排序的数组L,起始下标low和结束下标high
    17. int Partition(SqList &L, int low, int high)
    18. {
    19. L.r[0] = L.r[low]; // 将第一个元素作为基准元素
    20. pivotkey = L.r[low].key;
    21. while (low < high)
    22. {
    23. // 从右向左找到第一个小于基准元素的下标
    24. while (low < high && L.r[high].key >= pivotkey)
    25. --high;
    26. L.r[low] = L.r[high]; // 将找到的元素放到左边
    27. // 从左向右找到第一个大于基准元素的下标
    28. while (low < high && L.r[low].key <= pivotkey)
    29. ++low;
    30. L.r[high] = L.r[low]; // 将找到的元素放到右边
    31. }
    32. L.r[low] = L.r[0]; // 将基准元素放到正确的位置
    33. return low; // 返回基准元素的下标
    34. }

     B 快速排序的算法分析:

     最好情况:划分后,左右子序列长度相同

    最坏情况:递归树成为单支树 

    到此交换排序就结束了, 如果文章对你有用的话请点个赞支持一下吧!

    下篇文章将更新选择排序的内容。

  • 相关阅读:
    使用 TiUP 命令管理组件
    JDK安装配置
    Prometheus :(一)基本概念
    深入理解.Net中的线程同步之构造模式(二)内核模式2.内核模式构造物Semaphone
    NOI / 1.6编程基础之一维数组(2)
    场景应用:利用Redis实现分布式Session
    @data注解的作用
    【论文阅读】ConvNeXt:A ConvNet for the 2020s 新时代卷积网络
    skywalkingUI界面说明
    Vue3+ts(day07:pinia)
  • 原文地址:https://blog.csdn.net/Blusher1/article/details/140370134