快速排序-前后指针法和左右指针法

1.快速排序的原理:

快速排序是先任取数组中的一个元素作为基准值(一般是首或者尾),遍历一遍数组,让比大的在其右边,比他小的在其左边,这样就完成了基准值的定位,再将其右边和左边的分别重复上操作,完成排序。

2.前后指针法:

先定义数组开头是begin,结尾是end。end向左找比key小的数,找到就停止,begin向右找比key大的数找到就停止,最后交换end和begin的数据。当end=begin时就和key交换数据。

 3.左右指针法

定义头数据位置为prev,第二个数据位置为cur,头数据为key。cur向右找比key小的数据,找到后停止,与++prev位置交换数据,然后++cur。循环上述操作,当cur跳出循环时,key与prev位置交换数据.

 4.快排的优化

4.1三数取中

当数组中的数据是有序的时候,快排的效率最低,因为每次取的key都是最大或者最小值,这样他排出的位置是边缘位置,效率极低,我们只需要取出数组左位置,右位置,中间位置中数据的中值,与左位置处交换,这样我们的key值就不会排到边缘位置

4.2小区间优化

这里我们介绍的快排都是递归形式的,其实递归越到后面占据的时间越多,在最后的几个小区间就要占据大部分时间来递归。我们这里拿500个数据举例子,其实后面的小区间递归占据了大部分时间

如果数据是1w或者100w个,那么最后的小区间如果还用递归的话,就大幅度增加了运行时间,其实最后的小区间我们可以直接采用简单的不需要递归的插入排序替我们完成,这样就可以大幅度减少时间

5.代码 

void InsertSort(int* a, int n)
{
	//假设【0-end】有序,将第end+1的数插排入【0-end+1】     0-(n-1)
	for (int i = 0; i < n - 1; i++)
	{
		int end = i;
		int tmp = a[end + 1];
		while (end >= 0)
		{
			if (a[end] > tmp)
			{
				a[end + 1] = a[end];
				--end;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;
	}

}
void Swap(int* a1, int* a2)
{
	int tmp = *a1;
	*a1 = *a2;
	*a2 = tmp;
}
int MidIndex(int* arr, int left, int right)
{
	int mid = (left + right) / 2;
	if (arr[left] < arr[mid])
	{
		if (arr[mid] < arr[right])
		{
			return mid;
		}
		else
		{
			return arr[left] < arr[right] ? right : left;
		}
	}
	else//left > mid
	{
		if (arr[right] < arr[mid])
		{
			return mid;
		}
		else
		{

			return arr[left] < arr[right] ? left : right;
		}

	}


}

int _PartSort(int* arr, int left, int right)//挖坑法
{
	int begin = left;
	int end = right;
	int key = arr[begin];
	int pivot = begin;
	while (begin < end)
	{
		while (begin < end && arr[end] >= key)
		{
			end--;
		}
		arr[pivot] = arr[end];
		pivot = end;
		while (begin < end && arr[begin] <= key)
		{
			begin++;
		}
		arr[pivot] = arr[begin];
		pivot = begin;
	}
	pivot = begin;
	arr[pivot] = key;
	return pivot;
}

int _PartSort1(int* arr, int left, int right)//左右指针法
{
	int keyi = left;
	int begin = left;
	int end = right;
	while (begin < end)
	{
		while (begin < end && arr[end] >= arr[keyi])
		{
			end--;
		}
		while (begin < end && arr[begin] <= arr[keyi])
		{
			begin++;
		}
		Swap(&arr[begin], &arr[end]);
	}
	Swap(&arr[begin], &arr[keyi]);
	return begin;
}
//前后指针法
int _PartSort2(int* arr, int left, int right)
{
	int keyi = left;
	int rev = left;
	int cur = left + 1;
	while (cur <= right)
	{
		if (arr[cur] < arr[keyi] && cur != (rev + 1))
		{
			Swap(&arr[cur], &arr[++rev]);
		}
		++cur;
	}
	Swap(&arr[keyi], &arr[rev]);
	return rev;
}
void QuickSort(int* arr, int left, int right)
{
	if (left > right)
	{
		return;
	}
	int  index = MidIndex(arr, left, right); // 三数取中
	Swap(&arr[index], &arr[left]);

	int pivot = _PartSort2(arr, left, right);

	if (pivot - 1 - left + 1 > 10)//进行小区间分出去排序
	{
		QuickSort(arr, left, pivot - 1);
	}
	else
	{
		InsertSort(arr + left, pivot - 1 - left + 1);
	}
	if (right - pivot - 1 + 1 > 10)
	{
		QuickSort(arr, pivot + 1, right);
	}
	else
	{
		InsertSort(arr + pivot + 1, right - pivot - 1 + 1);
	}
}

6.扩展:

用数据结构的栈模拟实现快排的递归

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值