数据结构——快速排序

快速排序:通过一趟排序,将待排序序列分成两个部分,左边部分的值都小于基准值,右边部分都大于基准值,此时分别在对这两部分的子序列继续进行排序,以达到整个序列都有序的目的。

第一种方法:挖空法

单次划分函数:partintion

步骤

1:将待排序的第一个值作为基准值取出来,放到tmp中

2:进人while循环,循环条件就是left和right不相遇

3:先从右向左找比基准值tmp小的值,如果找到了,则放到左边的空位(left)

4:在从左向右找比基准值tmp大的值,如果找到了,则放到右边的空位(right)

5:反复执行23,直到left和right相遇

6:相遇之后,将tmp值挪动回去,然后返回基准值所在下标

例如:

默认第一个值是基准值,小于这个基准值的都放他左边,大于它的就放到他的右边。

从右向左找 找到比基准值小的值,将这个值放到左边,从左向右找到比基准值大的值放到右边去,这个过程交替进行,循环条件就是这两个左右指针不会相遇。

从右开始28大于71将28放到左边,右边空出一个位置,让左指针向右挪动,直到找到比基准值71大的值放到右边空格处。

此时左边有出现一个新的空白格子,让左指针向右挪动,直到找到比基准值71小的值,将这个值放到左边空格处也就是左指针所指向的位置。

反复交替进行

两个指针相遇将这个基准值放到两指针相遇的地方。

以基准值为中心左边的值都小于基准值,右边都大于基准值

分别再对这两个部分进行快速排序

先排左边

将默认的第一个数为基准值取出来从右向左开始找比基准值小的值,将这个值放到左指针指向的位置。此时右边就会有新的空白格子就将这个,在从左向右开始找比基准值大的数据,挪动到右边空白格子位置也就是右指针指向的位置。

最终结果为:

此时又以28开始分成左右两个部分。

排28的左边:

默认第一个数是基准值,将12取出来,此时左边就有一个空白格子也就是左指针指向的位置,从右向左找比基准值小的值,发现左指针和右指针相遇了,将基准值放到左指针和右指针相遇的地方

排28的右边部分:

默认第一个值是基准值,将基准值取出来。

从右至左的找比基准值小的数,将这个数放到右边空白格子处,也就是右指针指向的位置。

再从左向右找比基准值大的数,此时发现左右指针相遇了,将基准值放到左右指针相遇的位置。


再排他的右边

从右向左找比基准值小的值,将这个基准值挪动到左指针指向的位置。

在从右向左找比基准值大的值挪动到右指针指向的位置。

再从右向左找,比基准值小的值,将这个值挪动到有右边空白格子处。

此时两个指针相遇,将基准值89放到空白格子处。

此时以89为界限将这个序列分成了两个部分。

81他本身只有一个值,只有一个值就没有可以比较的数,此时就意味着单个数它本身就是有序的。

那么就是意味着进行比较最少需要两个值。

此时就处理右边:

从右向左找比基准值小的值将这个值挪动到左边空白格子处,此时发现左右两个指针相遇了。将基准值放到左右指针相遇的地方。

这些排完之后序列完全有序,最终为:

第二种方法:申请等长的辅助空间brr 空间复杂度O(n)

将71作为基准值,比基准值小的就从辅助空间的左边开始放。

比基准值大的就从辅助空间的右边开始放。

重复以上操作:

代码实现:

递归的方式实现:

cs 复制代码
int Partition(int arr[], int left, int right) {
	int tmp = arr[left];
	while (left < right) {
		while (left<right && arr[right]>tmp) {
			right--;
			//情况1:
			if (left == right) {
				break;
			}
			arr[left] = arr[right];
		}
		while (left < right && arr[left] < tmp) {

			left++;
			if (left == right) {

				break;
			}
			arr[right] = arr[left];
		}
		
	}
	arr[left] = tmp;//arr[right]=tmp;
		return left;
}


void Quick(int arr[], int left, int right) {
	if (left >= right) { //递归出口
		return;
	}
	int par = Partition(arr, left, right);
	Quick(arr, left, par - 1);
	Quick(arr, par + 1, right);
}

void Quick_Sort(int arr[], int len) {
	Quick(arr, 0, len - 1);
}

快速排序的非递归写法:

cpp 复制代码
int Partition(int arr[], int left, int right) {
	int tmp = arr[left];
	while (left < right) {
		while (left<right && arr[right]>tmp) {
			right--;
			//情况1:
			if (left == right) {
				break;
			}
			arr[left] = arr[right];
		}
		while (left < right && arr[left] < tmp) {

			left++;
			if (left == right) {

				break;
			}
			arr[right] = arr[left];
		}
		
	}
	arr[left] = tmp;//arr[right]=tmp;
		return left;
}


//快速排序的非递归
void Quick_Sort_N0(int arr[], int len) {

	//0.assert
	assert(arr != NULL);

	//1.申请一个栈,将第一次要处理的序列的左右边界输入进去《0,len-1>
	std::stack<int>st;
	st.push(0);
	st.push(len - 1);
	//2.进入while循环 循环条件是栈只要不空
	while (!st.empty) {
	//3.取出一对值,作为要处理的子序列的左右边界调用partition函数
		int right = st.top();
		st.pop();
		int left = st.top();
		st.pop;
	//4,申请一个变量par来接收partition 函数返回的基准值下标
		int par = Partition(arr, left, right);
	//5.判断以基准值为中心的两部分 是否需要在划分,如果需要则将其左右边界压入到栈中
	//注意:两部分先左先右都行但是要模拟递归的执行顺序则先右
		if (par + 1 < right) {
			st.push(par + 1);
			st.push(right);
		}
		if (left < par - 1) {
			st.push(left);
			st.push(par - 1);
		}
	}
	

	

	//6.当while循环退出 则说明数据全部处理完毕
}

快速排序的优化:

1.数据量不大(N不大),那可以不执行快排,直接去调用冒泡/直接插入。

2.三数取中法

找(最左端值,最右端值,中间位置值)这三个值中的不大不小的那个值,将其交换到最左端的位置。

3.随机数法

通过随机函数来随机抓取值进行打乱。

cs 复制代码
int Partition(int arr[], int left, int right) {
	int tmp = arr[left];
	while (left < right) {
		while (left<right && arr[right]>tmp) {
			right--;
			//情况1:
			if (left == right) {
				break;
			}
			arr[left] = arr[right];
		}
		while (left < right && arr[left] < tmp) {

			left++;
			if (left == right) {

				break;
			}
			arr[right] = arr[left];
		}
		
	}
	arr[left] = tmp;//arr[right]=tmp;
		return left;
}

void swap(int a, int b) {
	int temp = a;
	a = b;
	b = temp;
}
void Three_Get_Mid(int arr[], int left,int right) {
	
	int mid = (left+right+1)/2;
	//第一个if:保证最左端和中间位置的较大值放到中间位置
	if (arr[left]>arr[mid]) {
		swap(arr[left], arr[mid]);
	}
	//第二个if:保证三者中的最大值放到最右端位置
	if (arr[mid] > arr[right]) {
		swap(arr[right], arr[mid]);
	}
	//第三个位置:最大值既然在最右端 那么我们需要那个不大不小的值,要么在最左端,要么在中间位置
	if (arr[left] < arr[mid]) {
		swap(arr[left], arr[mid]);
	}
	int temp = arr[mid];
	arr[mid] = arr[left];
	arr[left] -= temp;
}

void Quick(int arr[], int left, int right) {
	//优化2:三数取中法(left,mid,right)
	Three_Get_Mid(arr, left, right);
	int par = Partition(arr, left, right);
	if (left < par - 1) {
	Quick(arr, left, par - 1);
	}
	if (par + 1 < right) {
	Quick(arr, par + 1, right);
	}

}

void Quick_Sort(int arr[], int len) {
	//优化1:直接调用冒泡排序或者直接插入排序
	if (len <= 100) {
		return Tnsert_Sort(arr, len);//直接插入排序
	}
	Quick(arr, 0, len - 1);
}

八大排序总结:

相关推荐
shehuiyuelaiyuehao1 小时前
算法39,位运算,消失的两个数字
java·数据结构·算法
多弗朗皮卡丘3 小时前
数据结构4:链表(下)
c语言·数据结构·链表
午彦琳4 小时前
2026.9.9
数据结构·算法·leetcode
橘子汽水1685 小时前
Leetcode 200,994岛屿数量,腐烂的橘子
数据结构·算法·leetcode
kiracrimson6 小时前
【无标题】
数据结构
zcmodeltech7 小时前
冷链物流沙盘模型控制系统设计——基于STM32与Modbus RTU的冷藏车、冷库全流程动态展示方案
数据结构·stm32·单片机·嵌入式硬件·物联网·能源
Shan12058 小时前
经典算法题示例与详解:飞地的数量(二)
java·数据结构·算法
小七在进步10 小时前
类和对象(一)
java·数据结构·算法
charlie11451419111 小时前
浅谈C++的列表初始化std::initializer_list
开发语言·数据结构·c++·list·开源项目