快速排序

时间:2024-02-20 10:41:31

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,

其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

// 假设按照升序对array数组中[left, right)区间中的元素进行排序
void QuickSort(int array[], int left, int right)
{
 if(right - left <= 1)
 return;

 // 按照基准值对array数组的 [left, right)区间中的元素进行划分
 int div = partion(array, left, right);

 // 划分成功后以div为边界形成了左右两部分 [left, div) 和 [div+1, right)
 // 递归排[left, div)
 QuickSort(array, left, div);

 // 递归排[div+1, right)
 QuickSort(array, div+1, right);
}

上述为快速排序递归实现的主框架,发现与二叉树前序遍历规则非常像,同学们在写递归框架时可想想二叉 树前序遍历规则即可快速写出来,后序只需分析如何按照基准值来对区间中数据进行划分的方式即可。

实现:

//快排
void QuickSort(int* a,int begin,int end) {
	if (begin >= end) {
		return;
	}
	int mid = GetMid(a, begin, end);
	Swap(&a[begin], &a[mid]);

	int left = begin, right = end;
	int key = begin;
	while (left < right) {
		//右边找小值
		while (left < right && a[right] >= a[left]) {
			right--;
		}
		//左边找大值
		while (left < right && a[left] <= a[key]) {
			left++;
		}
		//如果数组有序,找不到位置,那么此时就会左右相等,不进行交换
		Swap(&a[left], &a[right]);
	}
	Swap(&a[left],&a[key]);
	key = left;

	QuickSort(a,begin,key-1);
	QuickSort(a,key+1,end);
}

改进版:

void Swap(int* a,int* b) {
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

int GetMid(int* a, int begin, int end) {
	int mid = (end - begin) / 2;
	if (a[begin] < a[mid])
	{
		if (a[mid] < a[end])
			return mid;
		else if (a[begin] > a[end])
			return begin;
		else
			return end;
	}
	else 
	{
		if (a[mid] > a[end])
			return mid;
		else if (a[begin] < a[end])
			return begin;
		else
			return end;
	}
}

int PartSort1(int* a, int begin, int end)
{
	int mid = GetMid(a, begin, end);
	Swap(&a[mid], &a[begin]);

	int left = begin, right = end;
	int keyi = begin;

	if (end - begin + 1 < 10) {
		InsertSort(a+begin,end - begin + 1);
	}

	while (left < right)
	{
		// 右边找小
		while (left < right && a[right] >= a[keyi])
		{
			--right;
		}

		// 左边找大
		while (left < right && a[left] <= a[keyi])
		{
			++left;
		}

		Swap(&a[left], &a[right]);
	}

	Swap(&a[left], &a[keyi]);

	return left;
}

挖坑法:

void Swap(int* a,int* b) {
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

int GetMid(int* a, int begin, int end) {
	int mid = (end - begin) / 2;
	if (a[begin] < a[mid])
	{
		if (a[mid] < a[end])
			return mid;
		else if (a[begin] > a[end])
			return begin;
		else
			return end;
	}
	else 
	{
		if (a[mid] > a[end])
			return mid;
		else if (a[begin] < a[end])
			return begin;
		else
			return end;
	}
}

//挖坑法块排
int PartSort2(int* a,int begin,int end) {
	int mid = GetMid(a, begin, end);
	Swap(&a[begin], &a[mid]);

	int key = a[begin];
	int hole = begin;
	while (begin < end) {
		//右边找小值
		while (begin < end && a[end] >= key) {
			end--;
		}
		a[hole] = a[end];
		hole = end;
		//左边找大值
		while (begin < end && a[begin] <= key) {
			begin++;
		}
		a[hole] = a[begin];
		hole = begin;
	}

	a[hole] = key;
	return hole;
}

前后指针法:

void Swap(int* a,int* b) {
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

int GetMid(int* a, int begin, int end) {
	int mid = (end - begin) / 2;
	if (a[begin] < a[mid])
	{
		if (a[mid] < a[end])
			return mid;
		else if (a[begin] > a[end])
			return begin;
		else
			return end;
	}
	else 
	{
		if (a[mid] > a[end])
			return mid;
		else if (a[begin] < a[end])
			return begin;
		else
			return end;
	}
}

//前后指针
int PartSort3(int* a, int begin, int end) {
	int mid = GetMid(a, begin, end);
	Swap(&a[begin], &a[mid]);

	int pre = begin, cur = begin + 1;
	int key = begin;
	while (cur <= end) {
		//cur找小值
		if (a[cur] <= a[key] && ++pre != cur) {
			Swap(&a[pre], &a[cur]);
		}
		cur++;

	}
	Swap(&a[pre], &a[key]);

	return pre;
}

快速排序的特性总结:

  1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序

  2. 时间复杂度:O(N*logN)

  3. 空间复杂度:O(logN)

  4. 稳定性:不稳定