• 【数据结构】排序3——交换排序(冒泡排序、快速排序)



    交换排序

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

    常见的交换排序方法:
    冒泡排序T(n)=O(n2)
    快速排序T(n)=O( nlog2n)

    冒泡排序

    ——基于简单交换思想

    【基本思想】
    每趟不断将记录两两比较,并按“前小后大”规则交换。
    第一个数和第二个数比较,若第一个数大于第二个数,则交换位置,否则,位置不变;
    完成之后第二个数和第三个数比较,若第二个数大于第三个数,则交换位置,否则位置不变;
    完成之后第三个数和第四个数比较,……
    直到比较到最后一个数。

    例:
    在这里插入图片描述
    21<25,位置不变
    25<49,位置不变
    49>25,互换位置
    ……
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述
    总结:
    n个数据记录,总共需要比较n-1趟。
    第m趟需要比较n-m次。

    冒泡排序算法

    void bubble_sort(SqList &L){
    	int m,i,j;
    	RedType x;//交换时临时存储
    	for(m=1;m<=n-1;m++){//总共需要比较m趟
    		for(j=1;j<=n-m;j++){
    			if(L.r[j].key>L.r[j+1].key)//发生逆序
    				x=L.r[j];//交换
    				L.r[j]=L.r[j+1];
    				L.r[j+1]=x;
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

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

    提高排序算法效率:
    一旦某一趟比较时不出现记录交换,说明已排好序了,就可以结束本算法。

    void bubble_sort(SqList &L){
    	int m,i,j,flag=1;//flag作为是否有交换的标记,有交换flag=1,没交换flag=0
    	for(m=1;m<=n-1&&flag==1;m++){
    		flag=0;
    		for(j=1;j<=m;j++){
    			if(L.r[j].key>L.r[j+1].key)//发生逆序
    				flag=1;
    				x=L.r[j];//交换
    				L.r[j]=L.r[j+1];
    				L.r[j+1]=x;
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    算法分析

    时间复杂度:
    平均时间复杂度为O(n2)
    最好时间复杂度(正序)是O(n)
    最坏时间复杂度(逆序)为O(n2)

    空间复杂度:
    算法中增加一个辅助空间temp
    空间复杂度S(n)=O(1)

    稳定性:
    冒泡排序是一种稳定的排序方法。

    快速排序

    ——改进的交换排序

    pivot:枢轴、中心点

    【基本思想】
    ① 任取一个元素为中心(中间数),通常是取第一个元素(枢轴),中间数可以是第一个数、最后一个数、最中间一个数、任选个数等;
    ② 所有比它小的元素一律前放,比它大的元素一律后放;(小的从前往后放,大的从后往前放)
    ③ 形成左右两个子表;
    ④ 对各子表重新选择中心元素并依此规则调整;(递归思想)
    ⑤ 直到每个子表的元素只剩一个,就达到整个序列有序。

    优点:简单;
    缺点:花费空间。

    改进:
    ① 每一趟的子表的形成是采用从两头向中间交替式逼近法;
    ② 由于每趟中对各子表的操作都相似,可采用递归算法。
    在这里插入图片描述

    把第一次比较结束后的表以49为中心分成左右两个子表,对各子表重新选择中心元素并依此规则调整,这里左边选择了27作为中心元素,右边选择了76作为中心元素。

    在这里插入图片描述

    【基本步骤】
    ① 设下标1号元素作中间数(界点)pivotkey放置到0号下标位置,low指向第一个空,high指向末尾下标为L.length的位置。
    ② 由于low指向空,所以从high开始比较:
    若high 若high>pivotkey,则high的元素位置不变,high的位置也不变;
    若high=pivotkey,则high的元素位置不变,high的位置也不变。
    ③ 由于high指向空,所以从low开始比较:
    若low>pivotkey,则low的元素放置到high位置,且high的位置往后移一个位置high-1;
    若low 若low=pivotkey,则low的元素位置不变,low的位置也不变。
    ④ 直到low=high,把界点pivotkey移到low和high的位置,停止这趟比较。
    ⑤ 把第一次比较结束后的表以界点pivotkey为中心分成左右两个子表。
    ④ 对各子表重新选择中心元素并依此规则调整。(递归思想)
    ⑤ 直到每个子表的元素只剩一个,就达到整个序列有序。

    改进后的快速排序算法

    //主函数
    void main(){
    	QSort(L,1,L.length);//对顺序表L进行排序,需要排序的数据范围从位置1到位置L.length
    }
    
    void Partition(SqList &L,int low,int high){
    	L.r[0]=L.r[low];//把中间数放到0号空位置
    	pivotkey=L.r[low].key;
    	while(low<high){//直到low=high,循环结束
    		while(low<high&&L.r[high].key>=pivotkey)
    			--high;
    		L.r[low]=L.r[high];
    		while(low<high&&L.r[low].key<=pivotkey)
    			++low;
    		L.r[high]=L.r[low];
    	}
    	L.r[low]=L.r[0];//此时low的位置和high的位置是一样的,是一个空位置
    	return low;
    }//时间复杂度:O(n)
    
    void QSort(SqList &L,int low,int high){//对顺序表L进行排序,需要排序的数据范围从位置low到位置L.length
    	if(low<high){
    		pivotloc==Partition(L,low,high);
    		//将L.r[low]到L.r[high]一分为二,pivotloc为枢轴元素排好序的位置
    		QSort(L,low,pivotloc-1);//对低字表递归排序
    		QSort(L,pivotloc+1,high);//对高字表递归排序
    	}	
    }//时间复杂度:O(log^2^n)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    算法分析

    时间复杂度:
    可以证明,平均计算时间是O(nlog2n)。
    Qsort( ):O(log2n)
    Partition( ):O(n)
    实验结果表明:就平均计算时间而言,快速排序是我们所讨论的所有内排序方法中最好的一个。

    空间复杂度:
    快速排序不是原地排序
    由于程序中使用了递归,需要递归调用栈的支持,而栈的长度取决于递归调用的深度。(即使不用递归, 也需要用用户栈)
    在平均情况下:需要O(logn)的栈空间
    最坏情况下:栈空间可达O(n)。

    稳定性:
    快速排序是一种不稳定的排序方法。
    例如: 49, 38, 49*, 20, 97, 76
    一次划分后: 20, 38, 49*, 49, 97, 76
    49和49*位置互换,所有不稳定

    划分元素的选取是影响时间性能的关键。
    快速排序不适于对原本有序或基本有序的记录序列进行排序,输入数据次序越乱,所选划分元素值的随机性越好,排序速度越快,快速排序不是自然排序方法


  • 相关阅读:
    C++ Reference: Standard C++ Library reference: C Library: cwchar: mbrlen
    【Go电商实战05】结合项目解答使用Go中间件遇到的问题:中间件的概念和应用
    20221121 秩相同,值域不一定相同
    AC自动机(查询)
    SSL 证书,了解一下常识
    派金SDK接入文档
    Java版本+企业电子招投标系统源代码+支持二开+招投标系统+中小型企业采购供应商招投标平台
    Django04_路由分发
    企业为什么要搭建数据指标体系
    【C++】智能指针用法详解(非常实用)
  • 原文地址:https://blog.csdn.net/weixin_54007670/article/details/127499903