快速排序

快速排序,纵观各类技术博客,关于快速排序,方法很多,各有千秋,但是,我拙见:

快速排序需要用递归,二分,分治的思想去操作,那么在这其中,就需要找一个基准,通过这个基准,把序列分开,达到可以用分治的思想取解决的目的;

能看到这里的,基本对快排都有个了解,不多说,盗了几个图看看,更方便记忆:

    

动态图只能理解个意思,主要还是理解第一张图,说的很明白了,结合代码,分析:

#pragma once

//方法一:
void swap(int* a, int left, int right)
{
	int temp = a[left];
	a[left] = a[right];
	a[right] = temp;
}

int partitionNumOne(int* a, int left, int right)
{
	//The selected benchmark example :left
	int markKey = a[left];
	int mark = left;

	while (left < right)
	{
		while (left < right && a[right] >= markKey)
			right--;
		while (left < right && a[left] <= markKey)
			left++;
		swap(a, left, right);
	}

	swap(a,mark,left);
	return left; //or right because left == right
}

void QuickSortNumOne(int* a, int left, int right)
{
	if (left >= right)
		return;
	int position = partitionNumOne(a, left, right);
	QuickSortNumOne(a, left, position - 1);
	QuickSortNumOne(a, position + 1, right);
}

void SortNumOne(int* a,int size)
{
	assert(a);
	QuickSortNumOne(a, 0, size - 1);
}

//方法二:

int part(int* a, int left, int right)
{
	int markKey = a[left];
	
	while (left < right)
	{
		while (left < right && a[right] >= markKey)
			right--;
		a[left] = a[right];   //小的直接覆盖左边
		while (left < right && a[left] <= markKey)
			left++;
		a[right] = a[left];
	}
	
	a[left] = markKey;
	return left;
}

void QuickSortNumTwo(int* a, int left, int right)
{
	if (left >= right)
		return;

	int pos = part(a,left,right);
	QuickSortNumTwo(a,left,pos-1);
	QuickSortNumTwo(a,pos+1,right);
}

void SortNumTwo(int* a, int size)
{
	assert(a);

	QuickSortNumTwo(a,0,size-1);
}


//方法三:
//计算中间那个位置 一边都大于他 一边都小于他
int Partition(int *a, int left, int right)
{
	int key = a[right];
	int begin = left;
	int end = right - 1;

	while (begin < end)
	{

		//key是自己选
		while (a[begin] < key && begin < end) //也就是说 key左边的都比key小 右边的都比key大
		{
			++begin;
		}

		while (a[end] > key && end > begin)//处理右边
		{
			--end;
		}

		//但凡上边任何一个循环跳出来,都是因为遇到条件 下面判断
		if (begin < end)
		{
			swap(a[begin], a[end]);
		}
	}

	if (a[begin] < key)
	{
		return right;
	}

	else
	{
		swap(a[begin], a[right]);
		return begin;
	}
}

void QuickSortOne(int *a, int left, int right)
{
	assert(a);
	if (left <= right)
	{
		int tmp = Partition(a, left, right); //单趟排序
		QuickSortOne(a, left, tmp - 1);
		QuickSortOne(a, tmp + 1, right);
	}
}

//方法四:
void QsortMedianOfThree(int* a, int low, int high)
{
	if (low >= high) return;                        //递归出口
	PartitionMedianOfThree(a, low, high);         //三数取中
	int partition = Partition(a, low, high);      //将 >= x 的元素交换到右边区域,将 <= x 的元素交换到左边区域
	QsortMedianOfThree(a, low, partition - 1);
	QsortMedianOfThree(a, partition + 1, high);
}


// 三数取中确定基准元,将确定好的基准元与第一个数交换,无返回值
        
void PartitionMedianOfThree(int* a, int low, int high)
{
	int mid = low + (high + -low) / 2;
	if (a[mid] > a[high])
	{
		swap(a, mid, high);
	}
	if (a[low] > a[high])
	{
		swap(a, low, high);
	}
	if (a[mid] > a[low])
	{
		wap(a, mid, low);
	}                                                //将中间大小的数与第一个数交换
}
三种方法,都测试通过,前两种都是按图中方案写的代码,第二种方法优化了一点,不同第一种方法的地方是,第二种不用交换,直接覆盖,节省了时间;

之后:快速排序是不稳定的,其时间平均时间复杂度是O(nlgn)。

附一张图:


赐教!

原文地址:https://www.cnblogs.com/melons/p/5791841.html