• 排序算法-交换排序详解


    交换排序基本思想

    元素两两比较,如果发生逆序则交换,直到所有记录都排好序为止。

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

    冒泡排序

    冒泡排序(Bubble Sort)是一种最简单的交换排序方法,它通过两两比较相邻记录的关键字,如果发生逆序,则进行交换,从而使关键字小的记录如气泡一般逐渐往上 "漂浮"(左移),或者使关键字大的记录如石块一样逐渐向下 "坠落”(右移)。

    算法与过程

    在这里插入图片描述

    void BubbleSort(SqList &L) 
    {	//对顺序表L做冒泡排序
    	m=L.length-1;flag=1; 				// flag用来标记某一趟排序是否发生交换
    	while ((m>O) && (flag==1)) 
    	{
    		flag=O; 						// flag置为0,如果本趟排序没有发生交换,则不会执行下一趟排序
    		for(j =1; j<=m; j++) 
    			if(L.r[j].key>L.r[j+1].key)
    			{
    				flag=1;					// flag置为1,表示本趟排序发生了交换
    				t=L.r[j];L.r[j]=L.r[j+1];L.r[j+1]=t;	// 交换前后两个记录
    			}
    		--m;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    冒泡排序算法分析

    最好情况(正序)

    • 比较次数:n-1
    • 移动次数:0

    最坏情况(逆序)
    在这里插入图片描述
    对冒泡算法的评价:

    • 冒泡排序最好时间复杂度是O(n)
    • 冒泡排序最坏时间复杂度为O(n2)
    • 冒泡排序平均时间复杂度为O(n2)
    • 冒泡排序算法中增加一个辅助空间temp,辅助空间为S(n)=O(1)
    • 冒泡排序是稳定的

    快速排序

    快速排序 (Quick Sort) 是由冒泡排序改进而得的。 在 冒泡排序过程中, 只对相邻的两个记录进行比较, 因此每次交换两个相邻记录时只能消除一个逆序。 如果能通过两个(不相邻)记录的一次交换,消除多个逆序, 则会大大加快排序的速度。 快速排序方法中的一次交换可能消除多个逆序。

    快速排序基本思想

    • 任取一个元素(如:第一个)为中心(pivot:枢轴、中心点);
    • 所有比它小的元素一律前放,比它大的元素一律后放,形成左右两个子表;
    • 对各子表重新选择中心元素并以此规则调整;
    • 直到每个子表的元素只剩一个。

    快速排序的过程

    选定一个中间数作为参考,所有元素与之比较,小的调到其左边,大的调到其右边。

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

    快速排序算法

    int Partition(SqList &L, int low, int high) 
    {	//对顺序表L中的子表r[low .. high]进行一趟排序,返回枢轴位置
    	L.r[O]=L.r[low]; 							// 用子表的第一个记录做枢轴记录
    	pivotkey=L.r[low].key; 						// 枢轴记录关键字保存在pivotkey中
    	while(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[O];							// 枢轴记录到位
    	return low;									// 返回枢轴位置
    }
    
    void QSort(SqList &L,int low,int high) 
    {	// 调用前置初值: low=1; high=L.length; 
    	// 对顺序表L中的子序列L.r[low .. high]做快速排序
    	if(low<high) { 							// 长度大于1
    		pivotloc=Partition(L, low, high); 	// 将L.r[low.. high] 一分为二,pivotloc是枢轴位置
    		QSort(L, low, pivotloc-1); 			// 对左子表递归排序
    		QSort (L, pivotloc+1, high); 		// 对右子表递归排序
    	}
    }
    
    void QuickSort(SqList &L) 
    {	//对顺序表L做快速排序
    	QSort(L,1,L.length);
    }
    
    • 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
    • 29

    快速排序算法分析

    时间复杂度:
    平均计算时间是O(nlog2n);
    Qsort():O(log2n)
    Partition():O(n)

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

    稳定性:
    快速排序时一种不稳定的排序方法。
    在这里插入图片描述

    试对(90,85,79,74,68,50,46)进行快速排序的划分,你是否发现什么特殊情况?再对(46,50,68,74,79,85,90)进行快速排序划分呢?
    由于每次枢轴记录的关键字都是大于其它所有记录的关键字,致使一次划分之后得到的子序列(1)的长度为0,这时已经退化成为没有改进措施的冒泡排序。

    • 快速排序不适于对原本有序或基本有序的记录序列进行排序。
    • 划分元素的选取是影响时间性能的关键。
    • 输入数据次序越乱,所选划分元素值得随机性越好,排序速度越快,快速排序不是自然排序方法。
    • 改变划分元素的选取方法,至多只能改变算法平均情况下的时间性能,无法改变最坏情况下的时间性能。即最坏情况下,快速排序的时间复杂性总是O(n2)。
  • 相关阅读:
    MATLAB | 官方举办的动图绘制大赛 | 第一周赛情回顾
    【加密算法】PKI技术
    F5 BIG-IP iControl REST命令执行(CVE-2022-1388)
    REACT全家桶(6)----router
    图解设计模式——学习设计模式之前需要了解的信息
    ctfshow-web-web15 Fishman
    VS Code调试使用标准输入功能的go程序的问题
    连接查询-多表联合查
    我们小公司使用了6年的项目部署方案,打包 + 一键部署详解,还挺方便
    spring-data-mongodb的Aggregation详解
  • 原文地址:https://blog.csdn.net/A_art_xiang/article/details/126189891