快排的递归实现

快速排序是一种时间复杂度低,但会虽随着数组的顺序变化,因为其效率之高被称为快速排序,而

且其不稳定性也可以同过优化进行解决。

快速排序的实现有三种方法:

1.hoare版

其基本思想为:任取待排序元素序列中 的某元素作为基准值,按照该排序码将待排序集合分割成

两子序列,左子序列中所有元素均小于基准值右 子序列中所有元素均大于基准值,然后最左右

子序列重复该过程,直到所有元素都排列在相应位置上为止。

实现方法如图:

这幅图是将最左端的元素定为基准值, 先让基准值的另一边(right)开始走,找到比基准值小的

元素时停下,再让基准值(left)这一边开始走,找到比基准值大的元素停下,再将right和left对应

的元素进行交换,重复上述操作。如下图:

第一次交换:

第二次交换:

第二次交换后,right先走后left与right相遇将相遇的位置的元素与key的元素进行交换,此时

key的元素到了其排序好的最终元素的位置。 如下图:

这就是快速排序的单趟排序, 从上述图可以看出key将这个数组分为两部分,而左边和右边有可以

看为一个新的要排序的数组,而这又可以引用单趟排序,从而构成递归。

那么递归结束的条件是什么呢?是当(left == right)的时候吗?

当要拍序的数组本身有序的时候,我们会发现,可能会存在(left > right),所以递归结束的条件

应该为(left >= right)。

整体的代码如下:

//hoare法
int PartSort1(int* a, int left, int right)
{
	
	随机选k
	//int randi = left + (rand() % (right - left));
	//int key = left;
	//三数取中法
	int mid = FindMidNumi(a, left, right);
	if (mid != left)
	{
		Swap(&a[mid], &a[left]);
	}
	int key = left;

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

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

	return key;
}

void QuickSort(int* a, int left, int right)
{
	if (left >= right)
	{
		return;
	}
	
	int key = PartSort1(a, left, right);
	QuickSort(a, left, key - 1);
	QuickSort(a, key + 1, right);
	
}

2.挖坑法

此方法是hoare的一种变形,与上面的方法十分类似。

同样,我们把最左边的元素设为基准值,并将元素挖出来,用局部变量key将其存储如下图:

之后也是从右边先找到比key小的元素,并将此元素与坑位进行交换:

在从左边开始找比key大的元素,将其与坑位交换:

直到left与right相遇, 将key的值填回坑位。

从上述图可以看出key将这个数组分为两部分,而左边和右边有可以看为一个新的要排序的数组,

而这又可以引用单趟排序,从而构成递归。

 递归结束条件为:(left >= right)。

 代码如下:

//挖坑法
int PartSort2(int* a, int left, int right)
{
	//三数取中法
	int mid = FindMidNumi(a, left, right);
	if (mid != left)
	{
		Swap(&a[mid], &a[left]);
	}
	int key = a[left];
	int hole = left;
	while (left < right)
	{
		//右边找小
		while (left < right && a[right] >= key)
		{
			right--;
		}
		a[hole] = a[right];
		hole = right;
		//左边找大
		while (left < right && a[left] <= key)
		{
			left++;
		}
		a[hole] = a[left];
		hole = left;

	}
	a[hole] = key;

	return hole;
}

void QuickSort(int* a, int left, int right)
{
	if (left >= right)
	{
		return;
	}
	
	int key = PartSort2(a, left, right);
	QuickSort(a, left, key - 1);
	QuickSort(a, key + 1, right);
	
}

3.前后指针法:

前后指针法是快排的一种进阶方法:

分为两个指针:一个是当前位置(cur)一个是前一个位置(prev),其排序方法如下:

同样,我们把最左边的元素设为基准值

1,如果cur的值比key小,++prev,并将cur1的元素和prev的元素进行交换,++cur。

2,如果cur的值比key大,++cur。

3,当cur超过数组范围后,将prev的值和key交换。

从上述图可以看出key将这个数组分为两部分,而左边和右边有可以看为一个新的要排序的数组,

而这又可以引用单趟排序,从而构成递归。

 递归结束条件为:(left >= right)。

代码如下:

int PartSort3(int* a, int left, int right)
{
	// 三数取中法
	int mid = FindMidNumi(a, left, right);
	if (mid != left)
	{
		Swap(&a[mid], &a[left]);
	}
	int keyi = left;
	int prev = left;
	int cur = left + 1;
	/*while (cur <= right)
	{
		if (a[cur] < a[keyi])
		{
			++prev;
			Swap(&a[cur], &a[prev]);
			++cur;
		}
		else
		{
			++cur;
		}
	}*/
	//更简明,但是不好懂
	while (cur <= right)
	{
		if (a[cur] < a[keyi] && ++prev != cur)
		{
			Swap(&a[cur], &a[prev]);
		}
		cur++;
	}
	Swap(&a[prev], &a[keyi]);
	keyi = prev;

	return keyi;
}

void QuickSort(int* a, int left, int right)
{
	if (left >= right)
	{
		return;
	}
	
	int key = PartSort3(a, left, right);
	QuickSort(a, left, key - 1);
	QuickSort(a, key + 1, right);
	
}

我们刚开始提到时间复杂度随着数组的顺序变化,是因为当快速排序排有序的数组时,应为本身

就在最终位置,所以导致快排需要将所有元素都遍历一遍,从而使时间复杂度升高,而我们的解

决办法是三数取中法:

取数组最左,最右,中间三个元素来进行比较,取出最中间的元素,将其与最左边的元素进行交

换,从而使key的值在数组中处在一个居中的位置,代码如下(前面的代码都加了三数取中法):

//三数取中法
int FindMidNumi(int* a, int left, int right)
{
	int mid = (left + right) / 2;
	if (a[left] > a[mid])
	{
		if (a[mid] > a[right])
		{
			return mid;
		}
		else if (a[left] > a[right])
		{
			return right;
		}
		else
		{
			return left;
		}
	}
	else
	{
		if (a[mid] < a[right])
		{
			return mid;
		}
		else if (a[left] > a[right])
		{
			return left;
		}
		else
		{
			return right;
		}
	}
}

这样就可以让快排的时间复杂度稳定在O(n*logn)了,快排还是有些难度的,不过上述方法大家

可以只掌握一种,会写出快速排序即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Python 中的快速排序算法可以使用内置的 `sorted()` 函数实现,例如: ``` numbers = [5, 2, 9, 1, 5, 6] sorted_numbers = sorted(numbers) print(sorted_numbers) # Output: [1, 2, 5, 5, 6, 9] ``` 你也可以使用自定义的比较函数来控制排序的方式,例如: ``` numbers = [5, 2, 9, 1, 5, 6] sorted_numbers = sorted(numbers, key=lambda x: -x) print(sorted_numbers) # Output: [9, 6, 5, 5, 2, 1] ``` 如果你想手动实现快排算法,可以使用以下代码: ``` def quick_sort(arr): if len(arr) <= 1: return arr pivot = arr[len(arr) // 2] left = [x for x in arr if x < pivot] middle = [x for x in arr if x == pivot] right = [x for x in arr if x > pivot] return quick_sort(left) + middle + quick_sort(right) numbers = [5, 2, 9, 1, 5, 6] sorted_numbers = quick_sort(numbers) print(sorted_numbers) # Output: [1, 2, 5, 5, 6, 9] ``` 希望这对你有帮助! ### 回答2: 快速排序是一种高效的排序算法,它的核心思想是分治法。具体实现快排的步骤如下: 1. 选择一个基准元素,将待排序序列分为两部分,左边的元素小于基准元素,右边的元素大于基准元素。 2. 对左右两个子序列递归地进行快速排序。 3. 当子序列长度小于等于1时,递归结束,排序完成。 以下是用Python实现快速排序的代码: def quick_sort(arr): if len(arr) <= 1: # 当序列长度小于等于1时,直接返回 return arr pivot = arr[len(arr) // 2] # 选择基准元素,可以选择任意位置的元素 left = [x for x in arr if x < pivot] # 将小于基准元素的元素放在左边 middle = [x for x in arr if x == pivot] # 将等于基准元素的元素放在中间 right = [x for x in arr if x > pivot] # 将大于基准元素的元素放在右边 return quick_sort(left) + middle + quick_sort(right) # 递归地对左右两个子序列进行快速排序 arr = [5, 3, 8, 6, 2, 7, 1, 4] sorted_arr = quick_sort(arr) print(sorted_arr) 以上代码首先定义了一个快速排序的函数`quick_sort`,它接收一个待排序的列表作为参数,并返回排序后的新列表。在`quick_sort`函数内部,通过递归的方式不断对左右子序列进行快速排序,最终将排序完成的左子序列、中间元素和右子序列拼接在一起返回。 对于输入列表`arr = [5, 3, 8, 6, 2, 7, 1, 4]`,经过快速排序后,输出为`[1, 2, 3, 4, 5, 6, 7, 8]`。 ### 回答3: 快速排序(Quick Sort)是一种高效的排序算法,其基本思想是通过分治法将数组分成两个子数组,并通过递归地排序子数组,最终得到完全有序的数组。 在Python中,可以通过以下代码实现快速排序: ```python def quick_sort(arr): if len(arr) <= 1: return arr pivot = arr[len(arr) // 2] # 选择数组中间的元素作为基准值 less, equal, greater = [], [], [] # 分别用来存放小于、等于和大于基准值的元素 for num in arr: if num < pivot: less.append(num) elif num == pivot: equal.append(num) else: greater.append(num) return quick_sort(less) + equal + quick_sort(greater) # 递归地对小于和大于基准值的两个子数组进行排序,并将结果连接起来 ``` 在上述代码中,我们首先判断数组的长度是否小于等于1,如果是,则直接返回。然后选择数组中间的元素作为基准值(pivot)。接下来,通过循环遍历整个数组,将小于、等于和大于基准值的元素分别放入三个不同的数组(less、equal、greater)中。最后,递归地对小于和大于基准值的两个子数组进行排序,并将结果连接起来,得到最终的有序数组。 快速排序的平均时间复杂度为O(nlogn),在最坏情况下为O(n^2),空间复杂度为O(logn)。由于快速排序是一种原地排序算法,所以不需要额外的空间进行排序。快速排序的优势在于其递归的特性,使得其在实现上比较简单且易于理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值