排序算法-----快速排序(递归)

目录

前言

快速排序

步骤原理

大致思路

流程

动态图

代码实现

算法分析

空间复杂度

时间复杂度

稳定性


前言

今天我们开始学习排序算法中的快速排序算法,既然叫快速排序,那肯定是体现在快这方面,相较于前面所学习过的排序算法,快速排序是比这些算法的速度要快的,将来很多时候我们都会用到快速排序来去做排序的,下面就一起来学习吧!

快速排序

快速排序(Quicksort),计算机科学词汇,适用领域Pascal,C++等语言,是对冒泡排序算法的一种改进。

快速排序采用的是分治思想,即在一个无序的序列中选取一个任意的基准元素pivot,利用pivot将待排序的序列分成两部分,前面部分元素均小于或等于基准元素,后面部分均大于或等于基准元素,然后采用递归的方法分别对前后两部分重复上述操作,直到将无序序列排列成有序序列。

步骤原理

大致思路

快速排序算法通过多次比较和交换来实现排序,其排序流程如下:

1、首先设定一个分界值,通过该分界值将数组分成左右两部分。

2、将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于分界值,而右边部分中各元素都大于或等于分界值。

3、然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。

4、重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。

流程

现在给定一个数组初始 [25,24,6,65,11,43,22,51],然后进行快速排序

第一步,先选取一个参考数字temp,一般选取第一个即temp=25,然后标记最左边和最右边数字的位置分别为i, j

25 24 6 64 11 43 22 51

i j

temp

第二步,先去向左移动j 的位置,当j指向的数字小于temp时候,就停止移动,然后开始向右移动i

当i 移动到比temp要大的数字时,停止移动,此时将i 和 j 指向的数字进行交换,如下所示:

25 24 6 64 11 43 22 51

temp i j

交换后:

25 24 6 22 11 43 65 51

temp i j

第三步,此时,开始接着移动 j,当j 移动到比temp要小的数字的时候,停止移动, 如下所示:

25 24 6 22 11 43 65 51

temp i j

然后开始移动i ,当i 移动到与j 相遇的位置时,i停止移动(如果i 移动到比temp要大的数字的时候就执行上面的第二步,i与j 进行数字交换)

25 24 6 22 11 43 65 51

temp i,j

第四步,此时,i与j指向的数字与temp指向的数字进行数字交换

11 24 6 22 25 43 65 51

temp i,j

这时候我们会发现,此时i和j指向的数字的位置,左边的都比这个数字要小,右边的都比这个数字要大,于是我们就可以去进入到递归,分别对左边和右边的数字进行以上步骤的递归,最后两边的数字都会被排好序。

动态图

代码实现

cpp 复制代码
#include<stdio.h>

//快速排序---递归实现
void quick_sort(int* n, int left,int right) {
	int i, j, temp;
	i = left;
	j = right;
	if (i > j) {
		return;
	}
	else {
		temp = n[left];
		while (i != j) {
			while (n[j] >= temp && i < j)//先向左移动j
				j--;
			while (n[i] <= temp && i < j) //再向右移动i
				i++;
			if (i < j) {//此时对i和j指向的数字进行数字交换
				int num = n[i];
				n[i] = n[j];
				n[j] = num;
			}
		}//当i和j相遇的时候就结束循环

		//此时i与j相遇,就与temp交换
		int new_temp = n[i];
		n[i] = n[left];
		n[left] = new_temp;
	}
	//最后左右边依次进入到递归
	quick_sort(n, left, i - 1); //左边的数字都比temp要小
	quick_sort(n, i + 1, right);  //右边的数字都比temp要大
}

int main() {
	int array[8] = { 25,24,6,65,11,43,22,51 };
	printf("排序前:");
	for (int i = 0; i < sizeof(array) / sizeof(int); i++) {
		printf("%d ", array[i]);
	}
	printf("\n排序后:");
	quick_sort(array, 0, sizeof(array) / sizeof(int)-1);
	for (int i = 0; i < sizeof(array) / sizeof(int); i++) {
		printf("%d ", array[i]);
	}
}
//排序前:25 24 6 65 11 43 22 51
//排序后:6 11 22 24 25 43 51 65

算法分析

空间复杂度

快速排序算法没有涉及到空间的开辟,使用的空间是原数组空间,空间复杂度为O(1)

时间复杂度

快速排序之所以比较快,是因为与冒泡排序相比,每次的交换时跳跃式的,每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全部放到基准点的右边。这样整体交换次数和比较次数就少很多, 故排序速度就提高了许多,当然如果是最坏的情况下时间复杂度还是为O(n^2),其平均的时间复杂度为O(nlog2​n)

稳定性

俗话说得好:有得必有失。快速排序虽然排序速度快了很多,但是其缺牺牲了稳定性,当出现相同大小元素的时候,相同大小元素的相对位置会发生改变,每次递归都会发生变化,这就导致了快速排序的稳定性不好,这是因为快速排序改变了交换的规则,使用跳跃式交换,没有进行数字大小的一一比较,故快速排序是不稳定的,所以选择排序算法的时候要慎重选择,充分考虑到稳定性

好了,以上就是今天的全部内容了,我们下一期再见!

分享一张壁纸:

相关推荐
ChoSeitaku17 分钟前
链表循环及差集相关算法题|判断循环双链表是否对称|两循环单链表合并成循环链表|使双向循环链表有序|单循环链表改双向循环链表|两链表的差集(C)
c语言·算法·链表
娅娅梨19 分钟前
C++ 错题本--not found for architecture x86_64 问题
开发语言·c++
DdddJMs__13523 分钟前
C语言 | Leetcode C语言题解之第557题反转字符串中的单词III
c语言·leetcode·题解
兵哥工控24 分钟前
MFC工控项目实例二十九主对话框调用子对话框设定参数值
c++·mfc
Fuxiao___26 分钟前
不使用递归的决策树生成算法
算法
我爱工作&工作love我31 分钟前
1435:【例题3】曲线 一本通 代替三分
c++·算法
娃娃丢没有坏心思1 小时前
C++20 概念与约束(2)—— 初识概念与约束
c语言·c++·现代c++
lexusv8ls600h1 小时前
探索 C++20:C++ 的新纪元
c++·c++20
lexusv8ls600h1 小时前
C++20 中最优雅的那个小特性 - Ranges
c++·c++20
白-胖-子1 小时前
【蓝桥等考C++真题】蓝桥杯等级考试C++组第13级L13真题原题(含答案)-统计数字
开发语言·c++·算法·蓝桥杯·等考·13级