【排序】快速排序实现

目录

一、快速排序是什么?

二、左右指针法

1.实现原理

2.代码如下:

三、挖坑法

1.实现原理

2.代码如下: 

四、前后指针法

1.实现原理

2.代码如下:

五、三数取中

1.实现思想

2.代码如下:

 3.使用方法

总结



前言

        快排是公认的排序效率之王,加上三数取中小区间优化更是无人能敌。


一、快速排序是什么?

        快排分为三种实现方式:

        ①左右指针法

        ②挖坑法

        ③前后指针法

        其中左右指针与挖坑法实现原理差不多一样:(只是挖坑法多创建一个临时变量存储坑中的数据)它们俩都是选大的的通过自己的方式放在后面,选出小的通过自己的方式放前面,通过递归就可将整个数组进行排序。

        前后指针法同样是选大的放后面,选小的放前面,但是与上面两个不同的是它只从一头开始遍历。

二、左右指针法

1.实现原理

       ① 定义两个指针,一个从左边遍历,一个从右边遍历。

       ② 定义一个key值用来做比较的基准值。

       ③ 如果key是最左边的值,那么就让right先向左找小值,反之,就让left先找大值。

        目的:在left与right相遇时,在与key值交换时能够交换大值(小值),否则会出现数据错误。

       ④ 假定key值定义为最左边的数字,

        right向左走找比key值大的数据,找到后停下,

        left向右走找比key值小的数据,找到后停下,

        此时交换left与right对应的值,循环往复直至left与right相遇。

       ⑤ 相遇后,将相遇点与keyi对应的数据进行交换,此时数组将会达到key左边的数字都小于key,右边的数字都大于key,后续通过递归可实现整个数组的排序。

2.代码如下:

#include <stdio.h>

void swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}
// 左右指针法
void QuickSort1(int* arr, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	int left = begin;
	int right = end;
	int keyi = left;

	while (left < right)
	{
		// right向左找小
		while (left < right && arr[right] >= arr[keyi])
		{
			right--;
		}
		while (left < right && arr[left] <= arr[keyi])
		{
			left++;
		}
		// key的大值与小值进行换位
		swap(&arr[left], &arr[right]);
	}
	// 左右指针相遇,与key换位
	int meeti = left;
	swap(&arr[meeti], &arr[keyi]);

	QuickSort1(arr, begin, meeti - 1);
	QuickSort1(arr, meeti + 1, end);
}
int main()
{
	int arr[] = { 5,3,6,9,8,7,2,0,1,4 }; 
	size_t len = sizeof(arr) / sizeof(arr[0]);
	QuickSort1(arr, 0, len - 1);
	return 0;
}

三、挖坑法

1.实现原理

        挖坑法与左右指针法大致相同。

        ① 选出一个key值,并将其所在的位置定为坑(坑可被覆盖 -> 放数据,坑中的数据被保存在了key中)

        ② 定义两个指针,一个从左边遍历,一个从右边遍历。

        ③同左右指针法相同,

如果key是最左边的值,那么就让right先向左找小值,反之,就让left先找大值。

        目的:在left与right相遇时,在与key值交换时能够交换大值(小值),否则会出现数据错误。

        ④ 假定key值定义为最左边的数字:

        right找到比key值大的数据停下,将此数入坑,同时right所在的位置变为新坑;

        left向右走找比key值小的数据,找到后停下,将此数入坑,同时left所在的位置变为新坑;

        循环此过程直至两指针相遇。

        ⑤ 将key值入坑,此时数组将会达到key左边的数字都小于key,右边的数字都大于key,后续通过递归可实现整个数组的排序。

2.代码如下: 

// 挖坑法
void QuickSort2(int* arr, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	int left = begin;
	int right = end;
	int key = arr[left];
	int pivot = left;

	while (left < right)
	{
		// right向左找小
		while (left < right && arr[right] >= key)
		{
			right--;
		}
		// 入坑,更新坑位
		arr[pivot] = arr[right];
		pivot = right;

		// left向右找大
		while (left < right && arr[left] <= key)
		{
			left++;
		}
		arr[pivot] = arr[left];
		pivot = left;
	}
	// 相遇,key值入坑
	arr[pivot] = key;

	QuickSort2(arr, begin, pivot - 1);
	QuickSort2(arr, pivot + 1, end);
}// 挖坑法
void QuickSort2(int* arr, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	int left = begin;
	int right = end;
	int key = arr[left];
	int pivot = left;

	while (left < right)
	{
		// right向左找小
		while (left < right && arr[right] >= key)
		{
			right--;
		}
		// 入坑,更新坑位
		arr[pivot] = arr[right];
		pivot = right;

		// left向右找大
		while (left < right && arr[left] <= key)
		{
			left++;
		}
		arr[pivot] = arr[left];
		pivot = left;
	}
	// 相遇,key值入坑
	arr[pivot] = key;

	QuickSort2(arr, begin, pivot - 1);
	QuickSort2(arr, pivot + 1, end);
}
int main()
{
	int arr[] = { 5,3,6,9,8,7,2,0,1,4 }; 
	size_t len = sizeof(arr) / sizeof(arr[0]);
	QuickSort1(arr, 0, len - 1);
	return 0;
}

四、前后指针法

1.实现原理

        ① 定义两个指针,一前(cur)一后(prev)。

        ② 定义一个key值,用来作为单趟排序的基准值。

        ② 让前面的指针继续向前遍历,如果找到比key值小的,++prev后与其交换。

        ③ 重复②直至cur到达数组末尾,交换prev与keyi对应的数据。

        ④ 此时数组将会达到key左边的数字都小于key,右边的数字都大于key,后续通过递归可实现整个数组的排序。

2.代码如下:
 

// 前后指针法
void QuickSort3(int* arr, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	int left = begin;
	int right = end;
	int key = arr[left];
	int prev = left;
	int cur = prev + 1;
	while (cur <= end)
	{
		if (arr[cur] < key && ++prev != cur)// 减少不必要的swap
		{
			swap(&arr[prev], &arr[cur]);
		}
		++cur;
	}
	swap(&arr[prev], &arr[begin]);

	QuickSort3(arr, begin, prev - 1);
	QuickSort3(arr, prev + 1, end);
}

int main()
{
	int arr[] = { 5,3,6,9,8,7,2,0,1,4 }; 
	size_t len = sizeof(arr) / sizeof(arr[0]);
	QuickSort3(arr, 0, len - 1);
	return 0;
}

五、三数取中

1.实现思想

        当待排序数组本来是逆序时,快排效率将降到最低,为O(N2),每次都许哟啊对每个数进行交换位置2次,所以产生了三数去中的方法:

        取得数组最开始、最末尾、最中间中的中间值来平衡key值。

2.代码如下:

// 三数取中
int GetMidIndex(int* arr, int begin, int end)
{
	int mid = (end - begin) / 2 + begin;
	if (arr[begin] < arr[end])
	{
		// begin < end < mid
		if (arr[mid] > arr[end])
		{
			return end;
		}
		// mid < begin < end
		else if (arr[mid] < arr[begin])
		{
			return begin;
		}
		// begin < mid < end
		else
		{
			return mid;
		}
	}
	// end < begin
	else
	{
		// mid < end < begin
		if (arr[mid] < arr[end])
		{
			return end;
		}
		//end < begin < mid
		else if(arr[mid] > arr[begin])
		{
			return begin;
		}
		else
		{
			return mid;
		}
	}
}

 3.使用方法

        在取key值时仍可继续取left位置的值,但是在此之前做一次交换即可。

int index = GetMidIndex(arr, begin, end);
	swap(&arr[index], &arr[left]);
	int key = arr[left];

总结

        抓住快排的思想要点,加上调试即可快速实现出排序算法。

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值