快速排序

快速排序也是一种基于分治法的排序方法,简单的说,就是每次从序列中找出一个关键字,然后利用Partition的过程,将这个关键字放置到它在最终排好序的序列中的最终位置,并且保证在该位置左边的元素都小于它,右边的元素都大于等于它。然后递归的使用快速排序对左右两个子序列继续排序,直到子序列大小为1或者为空。

快速排序的速度取决于每次选出的那个关键字(pivot),简单的做法是取第一个元素,麻烦点的做法是取中间位置的元素。

代码如下:

void QuickSort(int* pData,int length)
{
	DoQuickSort(pData,0,length-1);
}

void DoQuickSort(int* pData,int low,int high)
{
	if(low >= high)
		return;

	int pivotIndex = FindPivotIndex(pData,low,high);
	if(pivotIndex != low)
	{
		int temp = pData[low];
		pData[low] = pData[pivotIndex];
		pData[pivotIndex] = temp;
	}

	int k = QuickSortPartition(pData,low,high);
	DoQuickSort(pData,low,k-1);
	DoQuickSort(pData,k+1,high);
}


int FindPivotIndex(int* pData,int low,int high)
{
	int middle = (low+high) / 2;

	if((pData[low] >= pData[middle] && pData[low] <= pData[high]) ||(pData[low] >= pData[high] && pData[low] <= pData[middle]))
	{
		return low;
	}
	else if((pData[middle] >= pData[low] && pData[middle] <= pData[high]) ||(pData[middle] >= pData[high] && pData[middle] <= pData[low]))
	{
		return middle;
	}
	else
	{
		return high;
	}
}

int QuickSortPartition(int* pData,int low,int high)
{
	int pivotValue = pData[low];
	while(low<high)
	{
		while(low<high && pData[high] >= pivotValue)
			--high;
		pData[low] = pData[high];
		while(low<high && pData[low] <= pivotValue)
			++low;
		pData[high] = pData[low];
	}

	if(low != high)
	{
		throw logic_error("low is not equal to high");
	}
	else
	{
		pData[low] = pivotValue;
	}

	return low;
}

主要的算法就是Partition方法里面,Partition的方法有很多,上面的方法是,先将low元素保存在pivot临时变量中,方便在最后插入到合适的位置,然后开始以low和high为下标,从两边向中间来和pivot值比较。比较的思路是,low的左边的所有元素都是小于或者等于pivot的元素,high右边的元素都是大于等于pivot的值,low和high之间的元素是还没有比较过的部分,而low或者high中,总是有一个位置是一个空位,即可以用来放置pivot的候选位置,而另一个所指的就是当前需要和pivot比较的位置。low和high逐渐的向中间靠拢,直到最后low和high指向同一个位置而退出循环,那个位置就是pivot的最后位置。

下面是另外一个Partition的方式:

int QuickSortPartition2(int* start,int low,int high)
{
	int pivot = start[low];
	int i;
	int lastSmall = low;
	int temp;

	for(i=low+1;i<=high;++i)
	{
		if(start[i] < pivot)
		{
			++lastSmall;
			temp = start[i];
			start[i] = start[lastSmall];
			start[lastSmall] = temp;
		}
	}

	temp = start[lastSmall];
	start[lastSmall] = start[low];
	start[low] = temp;
	return lastSmall;
}

这种方式的循环不变式,是lastSmall指向最后一个小于pivot的元素,它的左边直到low都是小于pivot的元素。i指向第一个没有比较过的元素,它的右边直到high都是没有比较过的,而i的左边到lastSmall的右边这中间的元素就是大于等于pivot的元素。当发现i元素小于pivot,那就lastSmall增加1从而指向第一个大于等于pivot的元素,然后交换i和lastSmall元素,然后递增i,从而恢复循环不变式。当循环结束后,互换lastSmall和low位置的元素,就可以了。起始时,lastSmall指向low也就是pivot,表示小于pivot的序列式空,i指向low+1,代表从low+1到high位置的所有元素都是未比较的,i和lastSmall之间没有元素,因此大于等于pivot的序列也是空的,因此满足循环不变式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值