【C语言 || 数据结构】快速排序

文章目录

前言

快速排序是一种基于分治策略的排序算法,通过选取一个基准元素将数组分为两部分,再递归地对这两部分进行排序,平均时间复杂度为O(n log n)。它在原地进行排序,且在实际应用中非常高效。

快速排序

快速排序有三种方式实现:hoare(托尼·霍尔)版本、前后指针、挖坑法
快速排序(QuickSort)的逻辑是基于分治策略,算法的基本步骤包括选择一个基准值(key),将数组分成两个子数组:一个小于基准值的子数组,另一个大于基准值的子数组,然后将key和最后的位置相互交换,最后递归地对这两个子数组进行快速排序。

1.快排的前后指针法

快速排序的前后指针方法个人认为是三种方法中较为简单,易于理解的一种了。

它通过两个指针(通常称为"前指针"和"后指针")来有效地进行分区操作。

我们可以先看动图:

算法逻辑

1.先定义一个基准值(key )和两个指针cur (快)和prev (慢),让两个指针指向key的下一个下标.

2.让cur先走,如果cur++小于 key的话,就让prev也++.

3.直到cur大于key,prev就停止下来,不在发生移动,直到cur再次移动到比key小的,然后prev再次++,然后和cur进行交换,

4.直到cur走出数组,直接让prev与key进行交换

5.最后进行递归,就可以了

1.1快排的前后指针法的代码实现
c 复制代码
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

// 前后指针法
void quicksort(int* a, int left,int right)
{
	if (left >= right)
		return;

	int key = left;	
	int prev = left;
	int cur = left + 1;
	while (cur <= right)
	{
		if (a[cur] < a[key])
		{
			prev++;
			Swap(&a[cur], &a[prev]);
		}
		cur++;
	}
	Swap(&a[key], &a[prev]);
	// [left,key-1] [key+1,right] 
	quicksort(a, left, key - 1);
	quicksort(a, key + 1, right);
}
1.2快排的前后指针法的注意事项

递归需要有跳出递归的条件,切记cur是小于等于right,不能超出数组的范围,否则就会导致越界风险。

2.快排的挖坑法

快速排序的挖坑法(也称为"填坑法")是一种直观且有效的排序算法实现方式。

看动图:

算法逻辑

1.首先将最左边的数定义为坑位 ,并把这个坑位的值记录在key 中,同时定义两个变量,begin和end,一个从最左边开始每一个从右边开始。

2.先从右边开始向左边开始找小于 key的数据,然后和坑位进行交换 ,交换完成之后,把坑位转移到end当前所在的位置。

3.然后再让begin开始向右移动,找到比key大的值然后和坑位进行交换,再次将坑位移动到当前begin所在的位置。

4.直到最后begin和end相遇 了,且坑位的值已经进行过交换,将key值放入坑位。

5.再进行递归就可以实现算法了

2.1快排的挖坑法的代码实现
c 复制代码
// 挖坑法
void quicksort(int* a, int left, int right)
{
	if (left >= right)
		return;

	int key = a[left];
	int keyi = left; // 坑位
	int begin = left;
	int end = right;
	while (begin < end)
	{
		while(begin < end && a[end] >= key)
		{
			end--;
		}

		if (begin < end && a[end] < key)	
		{
			a[keyi] = a[end];
			keyi = end;
		}

		while(begin < end && a[begin] <= key)
		{
			begin++;
		}

		if (begin < end && a[begin] > key)
		{
			a[keyi] = a[begin];
			keyi = begin;
		}
	}
	a[keyi] = key;
	// [left,keyi-1] [keyi+1,right]
	quicksort(a, left, keyi - 1);
	quicksort(a, keyi + 1 , right);
}
2.2快排的挖坑法的注意事项

开始比较的时候一定要从右边 开始进行。

开始挖坑的时候切记,需要将key值进行保存,否则后期找不到最开始的key值。

再内部进行比较的时候,也一定要将begin和end进行比较,否则就会有报错。

数据进行交换的时候,坑位移动要发生改变,否则排序将失败。

3.快排的hoare法

快速排序的Hoare法是一种基于二叉树思想的交换排序方法,由托尼·霍尔在1962年提出。

动图:

算法逻辑

1任取待排序元素序列中的某元素作为基准值(key),通常选择第一个或最后一个元素。

2.初始化两个指针,begin指向序列的开始,end指向序列的末尾。

3.begin从左边开始找比key大的值,找到就停下来。

4.end从右边开始找比key小的值,找到就和begin进行交换。

5.直到begin和end相遇,将这个位置与key进行交换,然后再分治递归即可。

3.1快排的hoare法的代码实现
c 复制代码
// hoare法
void quicksort(int* a, int left, int right)
{
	if (left >= right)
		return;

	int key = left;
	int begin = left;
	int end = right;
	while (begin < end)
	{
		while (begin < end && a[end] >= a[key])
		{
			end--;
		}

		while (begin < end && a[begin] <= a[key])
		{
			begin++;
		}
		
		Swap(&a[begin], &a[end]);
	}
	Swap(&a[begin], &a[key]);
	key = begin;
	// [left,keyi-1] [keyi+1,right]
	quicksort(a, left, key - 1);
	quicksort(a, key + 1, right);
}
3.2快排的hoare法的注意事项

开始比较的时候一定要从右边 开始进行。

end找到比key小的值需要停下来,直到begin遇到比key大的值,才进行交换。

4快排的优化

快拍有两个优化,一个是三数取中,另一个是小区间优化

4.1快排的三数取中

其实key的取值是有方法的,取三个值中间的那个,取最左边的值、最右边的值和中间的那个值。避免最坏情况的O(N^2),避免有序和接近有序。

4.2快排的三数取中的实现方法
c 复制代码
int GetMidi(int* a, int left, int right)
{
	int midi = (left + right) / 2;
	if (a[left] > a[right])
	{
		if (a[midi] < a[right])
		{
			return right;
		}
		else if(a[midi] > a[left])
		{
			return left;
		}
		else
		{
			return midi;
		}
	}
	else // r < l
	{
		if (a[midi] < a[left])
		{
			return left;
		}
		else if (a[midi] < a[left])
		{
			return midi;
		}
		else
		{
			return right;
		}
	}
}
4.3快排的小区间优化

再数据个数较小的时候,为了避免继续递归分割,转而采用其他更高效的排序算法,如插入排序,以减少递归调用的次数,提高排序效率。

4.3快排的小区间优化的代码实现
c 复制代码
// 快速排序hoare版本
void PartSort(int* a, int left, int right)
{
	if (left >= right)
		return;

	if ((left + right) < 10)
	{
		InsertSort(a+left, (right - left + 1));
	}
	else
	{
		int midi = GetMidi(a, left, right);
		Swap(&a[left], &a[midi]);

		int key = left;
		int begin = left;
		int end = right;
		while (begin < end)
		{
			while (begin < end && a[end] >= a[key])
			{
				end--;
			}

			while (begin < end && a[begin] <= a[key])
			{
				begin++;
			}

			Swap(&a[begin], &a[end]);
		}

		Swap(&a[key], &a[begin]);
		key = begin;
		PartSort(a, left, key - 1);
		PartSort(a, key + 1, right);
	}
}

// 快速排序挖坑法
void PartSort2(int* a, int left, int right)
{
	if (left >= right)
		return;

	if ((left + right) < 10)
	{
		InsertSort(a + left, (right - left + 1));
	}
	else
	{
		int midi = GetMidi(a, left, right);
		Swap(&a[left], &a[midi]);

		int key = left; // 坑位
		int keyi = a[left];
		int begin = left, end = right;
		while (begin < end)
		{
			while (a[end] >= keyi && begin < end)
			{
				end--;
			}
			if (a[end] < keyi)
			{
				a[key] = a[end];
				key = end;
			}
			while (a[begin] <= keyi && begin < end)
			{
				begin++;
			}
			if (a[begin] > keyi)
			{
				a[key] = a[begin];
				key = begin;
			}
		}
		a[key] = keyi;
		// [left,key-1] key [key+1,right]
		PartSort2(a, left, key - 1);
		PartSort2(a, key + 1, right);
	}
}

// 快速排序前后指针法
void PartSort3(int* a, int left, int right)
{
	if (left >= right)
		return;


	if ((left + right) < 10)
	{
		InsertSort(a + left, (right - left + 1));
	}
	else
	{
		int midi = GetMidi(a, left, right);
		Swap(&a[left], &a[midi]);

		int key = left;
		int prev = left;
		int cur = left + 1;
		while (cur <= right)
		{
			if (a[cur] < a[key])
			{
				prev++;
				Swap(&a[prev], &a[cur]);
			}
			cur++;
		}
		Swap(&a[prev], &a[key]);
		key = prev;
		// [left,key-1] key [key+1,right]
		PartSort3(a, left, key - 1);
		PartSort3(a, key + 1, right);
	}
}
相关推荐
梅茜Mercy2 小时前
数据结构:链表(经典算法例题)详解
数据结构·链表
88号技师2 小时前
2024年12月一区SCI-加权平均优化算法Weighted average algorithm-附Matlab免费代码
人工智能·算法·matlab·优化算法
IT猿手2 小时前
多目标应用(一):多目标麋鹿优化算法(MOEHO)求解10个工程应用,提供完整MATLAB代码
开发语言·人工智能·算法·机器学习·matlab
青春男大2 小时前
java栈--数据结构
java·开发语言·数据结构·学习·eclipse
88号技师2 小时前
几款性能优秀的差分进化算法DE(SaDE、JADE,SHADE,LSHADE、LSHADE_SPACMA、LSHADE_EpSin)-附Matlab免费代码
开发语言·人工智能·算法·matlab·优化算法
Zer0_on2 小时前
数据结构栈和队列
c语言·开发语言·数据结构
一只小bit2 小时前
数据结构之栈,队列,树
c语言·开发语言·数据结构·c++
马浩同学2 小时前
【GD32】从零开始学GD32单片机 | DAC数模转换器 + 三角波输出例程
c语言·单片机·嵌入式硬件·mcu
我要学编程(ಥ_ಥ)2 小时前
一文详解“二叉树中的深搜“在算法中的应用
java·数据结构·算法·leetcode·深度优先
埃菲尔铁塔_CV算法2 小时前
FTT变换Matlab代码解释及应用场景
算法