【排序】快速排序及其优化

1.交换函数

在排序中交换数字,达到排序的目的
由于代码是C语言写的,所以需要给出交换函数(如果是C++,那么就直接用交换函数)

void Swap(int *left, int* right)
{
	int temp = *left;
	*left = *right;
	*right = temp;
}

2.第一种排序

先标记基准值(这里先取最后一个元素为基准值,记录起来),之后定义两个指针,然后前后遍历,找到比基准值大的或者小的的元素的位置,然后进行标记,标记成功后进行交换,最后添加一个循环,此时的begin和end是在一个位置的,你要将begin和right-1(其实就是基准值的位置)位置的元素交换(将基准值放到中间,保证前面的数字小于基准值,后面的元素大于基准值

int Partion1(int* array, int left, int right)
{
	int begin = left;
	int end = right - 1;
	//设置基准值,取数组最右侧的元素
	int key = array[end];

	while (begin < end)
	{
		//寻找大于基准值的数
		while (begin < end && array[begin] <= key)
			begin++;

		while (begin < end && array[end] >= key)
			end--;

		if (begin < end)
			Swap(&array[begin], &array[end]);
	}

	//这里将基准值和begin(end)交换
	if (begin != right - 1)
		Swap(&array[begin], &array[right - 1]);

	return begin;//此时应该返回begin,key只是值(这里是下标操作)
}

3.第二种操作(俗称“挖坑法”)

这种还是先标记基准值,依旧是begin和end两个指针,然后begin先找比基准值大的元素,将其填写到right-1的位置上,此时的begin的位置就是一个坑,然后end从后开始遍历,找到比基准值小的元素将其填写到begin的位置,end的位置就是一个坑,循环以上操作,结束后就将标记起来的基准值填写到begin(end)的位置。

int Partion2(int* array, int left, int right)
{
	int begin = left;
	int end = right - 1;
	int key = array[end];//基准值


	while (begin < end)
	{
		//从头开始大于key的值的位置
		while (begin < end && array[begin] <= key)
			begin++;

		//将这个值填到基准值的位置
		if (begin < end)
		{
			array[end--] = array[begin];//这里的end一定要往前走一步
		}

		//从尾开始大于key的值得位置
		while (begin < end && array[end] >= key)
			end--;

		//填坑在begin的位置
		if (begin < end)
		{
			array[begin++] = array[end];
		}
	}
	//将基准值填写到begin的位置(此时的begin和end的位置是一样的)
	array[begin] = key;

	return begin;
}

4.第三种排序

先找基准值,然后cur标记left,prev标记cur-1,然后cur遍历,分为两个阶段:第一个是cur没找到比基准值大的,prev和cur一直紧挨着。第二种是找到了,然后cur++,继续遍历,找到比基准值小的,然后才让++prev,此时交换prev和cur位置的元素,cur继续遍历,循环结束,最后right-1和++prev位置交换,放好基准值的位置。

int Partion3(int* array, int left, int right)
{
	int cur = left;
	int prev = cur - 1;
	int key = array[right - 1];
	while (cur < right)
	{
		if (array[cur] < key && ++prev != cur)
			Swap(&array[cur], &array[prev]);

		cur++;
	}
	if (++prev != (right - 1))
		Swap(&array[prev], &array[right - 1]);

	return prev;
}

5.快排函数

调用上面写的三种任何一种方式都可。
不管上面哪种排序,每次交换完成一次之后,都需要对基准值进行交换。

void QuickSort(int* array, int left, int right)
{
	//right-left>1说明中间必有元素
	if (right - left > 1)
	{
		int div = Partion3(array, left, right);
		QuickSort(array, left, div);
		QuickSort(array, div + 1, right);
	}
}

6.打印函数

这个不用多说。

void Print(int* array, int size)
{
	for (int i = 0; i < size; i++)
	{
		printf("%d ", array[i]);
	}
	printf("\n");
}

7.测试代码

测试用例,可以多写一点。

#include "QuickSort.h"

int main()
{
	int array[] = { 9, 3, 8, 6, 7, 2, 1, 0, 4, 5 };
	Print(array, sizeof(array) / sizeof(array[0]));
	QuickSort(array, 0, sizeof(array) / sizeof(array[0]));
	Print(array, sizeof(array) / sizeof(array[0]));
	return 0;
}

8.优化取得的基准值

在进行三种排序的时候我们会发现一个事情,万一最右边的数字是最大或者最小该怎么办呢?
此时我们就要对取基准值进行优化,保证不至于偏差非常大

//三值取中法
int GetIndexOfMid(int* array, int left, int right)
{
	int mid = left + ((right - left) >> 1);
	if (array[left] > array[right - 1])
	{
		if (array[mid] > array[left])
			return left;
		else if (array[mid] < array[right - 1])
			return right;
		else
			return mid;
	}
	else
	{
		if (array[mid] < array[left])
			return left;
		else if (array[mid] > array[right - 1])
			return right;
		else
			return mid;
	}
}

记住:三值取中法返回的是下标

因为每次取的值不一定是最佳的,所以这里我们采用三个位置的值,选择一个最佳的位置。

	int ret = GetIndexOfMid(array, left, right);
	int key = array[ret];//基准值
	//将那个放到最后面,就可以和之前的代码连接起来
	Swap(&array[ret], &array[right - 1]);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值