分而治之思想:快速排序算法(debug)

快速排序

快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod,即D&C)。

基本思想:

快速排序使用分治的思想,从待排序序列中选取一个记录的关键字为pivot(基准值),通过一趟排序将待排序列分割成两部分,其中一部分记录的关键字不大于pivot,另一部分记录的关键字不小于pivot,之后分别对这两部分记录继续进行排序,以达到整个序列有序的目的。

快速排序算法的基本步骤为(默认升序):

  1. 选择关键字:从待排序序列中,按照某种方式选出一个元素作为 pivot 作为关键字(也叫基准)。
  2. 置 pivot 分割序列:通过某种方式将关键字置于一个特殊的位置,把序列分成两个子序列。此时,在关键字 pivot 左侧的元素小于或等于 pivot,右侧的元素大于 pivot(这个过程称为一趟快速排序)。
  3. 对分割后的子序列按上述原则进行分割,直到所有子序列为空或者只有一个元素。此时,整个快速排序完成。

最优的分割方法:当每次选择恰当的基准值后,可使得分割后两边的长度尽可能相等时,此时的算法复杂度可以由O( n 2 n^2 n2)缩小到O(nlogn). 由此可见,基准值的选取直接影响了算法的速度,这是快排算法中十分重要的一环。

BUG版本

void quick_sort(int arr[], int size, int left, int right)
{
	int pivot = set_pivot_1(arr,size,left,right);
	int i = left;//第一次找到比基准数大的元素索引
	int j = right;;//第一次找到比基准数小的元素索引
	
	 //基线条件
	if (left >= right)
	//left=right说明该区块只含有一个元素,left>right说明该区块为空
	{
		return;
	}
	//递归条件
	while (i < j)//实行分区
	{
		while (arr[j] >= pivot && i < j) 
		{
			j--;
		}
		while (arr[i] <= pivot && i < j)
		{
			i++;
		}
		if (i < j)
		{
			swap(&arr[i], &arr[j]);
		}
	}
	swap(&arr[i], &arr[left]);
	quick_sort(arr, size, left, i - 1);
	quick_sort(arr, size, i + 1, right);
}

2020.4.21日 BUG:
对于头尾基准值法,代码可行。
但是对于随机基准值法和三数求中基准值法,代码出现了bug。
(会出现莫名其妙的数据???

int set_pivot_1(int arr[], int size,int left,int right)
{
	//头尾基准值法
	return arr[left];
}
int set_pivot_2(int arr[], int size,int left,int right)
{
	//三数求中基准值法
	int mid = left + (right - left)/2; 
	if (arr[left] > arr[mid])
	{
		swap(&arr[left], &arr[mid]);
	}
	if (arr[left] > arr[right])
	{
		swap(&arr[left], &arr[right]);
	}
	if (arr[mid] > arr[right])
	{
		swap(&arr[mid], &arr[right]);
	}
	swap(&arr[left], &arr[mid]);
	return arr[left];
}
int set_pivot_3(int arr[], int size,int left,int right)
{
	//随机基准值法
	srand((unsigned)time(NULL));
	int key = rand() % (right - left) + left;
	swap(&arr[key], &arr[left]);
	return arr[left];
}

我是BUG收割机(自嗨

请允许吃完晚饭后的我小小的自恋一下——我是debug王!!
对于三数取中基准数的算法错误,终于找到原因啦
在这里插入图片描述
问题出在主函数上:
分析:倘若是如此,先取基准值,在判断基线条件的话。因为有可能出现
left > right的情况,也就是该区块为空的时候。
此时,按照三数取中基准数的算法:

int mid = left + (right - left)/2; 

此时的mid可能为负值,这样就会造成对内存的非法访问,程序自然就会报错了,like this:在这里插入图片描述
对于随机中基准数的算法错误,原因也逐渐浮现出来:

int key = rand() % (right - left) + left;

这里要考虑 left=right,所属区块为空的情况下,right - left = 0 ,而数字%0的运算是无定义的,所以自然会出错啦~

正确版本

所以正确版本应该是先判断基准条件,在来确定基准值

void quick_sort(int arr[], int size, int left, int right)
{
	//基线条件
	if (left >= right)
	//left=right说明该区块只含有一个元素,left>right说明该区块为空
	{
		return;
	}
	int pivot = set_pivot_1(arr,size,left,right);//头尾基准值法
	int i = left;//第一次找到比基准数大的元素索引
	int j = right;;//第一次找到比基准数小的元素索引
	//递归条件
	while (i < j)//实行分区
	{
		while (arr[j] >= pivot && i < j) 
		{
			j--;
		}
		while (arr[i] <= pivot && i < j)
		{
			i++;
		}
		if (i < j)
		{
			swap(&arr[i], &arr[j]);
		}
	}
	swap(&arr[i], &arr[left]);
	quick_sort(arr, size, left, i - 1);
	quick_sort(arr, size, i + 1, right);
}

大功告成!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值