快排

static void Swap(int *arr, int low, int high) 
{
	int tmp = arr[low];
	arr[low] = arr[high];
	arr[high] = tmp;
}

static int Pivotkey(int *arr, int low, int high)//三数取中
{
	int mid = (high - low) / 2 + low;

	if (arr[low] > arr[high])
	{
		Swap(arr, low, high);
	}
	if (arr[mid] > arr[high])
	{
		Swap(arr, mid, high);
	}
	//经过以上两步,high大于low和mid
	if (arr[mid] > arr[low])
	{
		Swap(arr, mid, low);
	}
	//经过以上三步,mid <= low <= high
	return arr[low];
}

static int Partition(int *arr, int low, int high, int *pleftlen, int *prightlen)//三数取中加处理相等的数据
{
	int pivot = Pivotkey(arr, low, high);

	//这两个给交换到基准旁时使用
	int first = low;
	int last = high;

	//这两个给放两边时使用
	int left = low;
	int right = high;
	

	while (low < high)
	{
		while ((low < high) && arr[high] >= pivot)
		{
			if (arr[high] == pivot)
			{
				Swap(arr, high, right);
				right--;
				(*prightlen)++;
			}
			high--;
		}
		arr[low] = arr[high];
		while ((low < high) && arr[low] <= pivot)
		{
			if (arr[low] == pivot)
			{
				Swap(arr, low, left);
				left++;
				(*pleftlen)++;
			}
			low++;
		}
		arr[high] = arr[low];
	}
	arr[low] = pivot;

	//将两边相等的移到low的两边
	int i = first;
	int j = low - 1;
	while (i < left && arr[j] != pivot)
	{
		Swap(arr, i, j);
		i++;
		j--;
	}

	i = low + 1;
	j = last;
	while (j > right && arr[i] != pivot)
	{
		Swap(arr, i, j);
		i++;
		j--;
	}

	return low;
}

static void Quick(int *arr, int low, int high)
{
	if (low < high)
	{
		int leftlen = 0;
		int rightlen = 0;

		int par = Partition(arr, low, high, &leftlen, &rightlen);

		Quick(arr, low, par - 1 - leftlen);
		Quick(arr, par + 1 + rightlen, high);
	}
}

void QuickSort(int *arr, int len)//快排
{
	Quick(arr, 0, len - 1);
}
上面的快排是优化过的,对于有序数据及相同数据的优化。
三数取中,这样可以在数据有序时,时间复杂度不至于沦为O(n^2)。
但是当数据重复时,三数取中,取得那个基准还是那个数,这样每次的分割,还是只能分出去一个数,时间复杂度还是O(n^2)。
于是就有了这个优化:每次的partition,都将跟pivotkey相等的数据放在pivotkey两边,下来的递归不将与pivotkey相等的数据算在内。
代码本身不难理解,主要就是快排的时间复杂度的理解不好理解。理想状态下为什么是O(nlogn),最差状态下为什么是O(n^2)。
其实这样理解快排的话,时间复杂度就好理解了。快排就是将数据切成一个一个的,这也就意味着,怎样数据切的越快,那它的时间复杂度就越低。
显然,一半一半得切,最快。一个一个得切,最慢。
一半一半得切,需要切logn次;一个一个得切,需要切n次。
所以,如果每次切,都将数据切成两半了,那就是最好的了。这样时间复杂度就为O(nlogn),空间复杂度为O(logn)。
相反,如果每次切,都只能切一个,那就是最差情况了。这样的时间复杂度为O(n^2),空间复杂度为O(n);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值