几种快速排序的几点疑问

大学学的快速排序,现在已经忘了,重新学一遍.

最近学习了一篇快速排序的文章:

http://www.importnew.com/8445.html#comment-13445

发现里面双基准排序有点问题.修正如下:

package test;

import java.util.Arrays;

public class QuickSortDualPivot extends QuickSort {

	public static void main(String[] args) {
		int[] arr = new int[] { 3, 4, 2, 1, 3 };
		QuickSortDualPivot test = new QuickSortDualPivot();
		System.out.println(Arrays.toString(arr));
		test.sort(arr);
		System.out.println(Arrays.toString(arr));
	}

	public void sort(int[] input) {
		sort(input, 0, input.length - 1);
	}

	private void sort(int[] input, int lowIndex, int highIndex) {

		if (highIndex <= lowIndex)
			return;

		int pivot1 = input[lowIndex];
		int pivot2 = input[highIndex];

		if (pivot1 == pivot2) {
			int temI = lowIndex;
			while (pivot1 == pivot2 && temI < highIndex) {
				temI++;
				pivot1 = input[temI];
			}
			exchange(input, lowIndex, temI);
		}

		if (pivot1 > pivot2) {
			exchange(input, lowIndex, highIndex);
			pivot1 = input[lowIndex];
			pivot2 = input[highIndex];
		}

		int i = lowIndex + 1;
		int lt = lowIndex + 1;
		int gt = highIndex - 1;

		while (i <= gt) {

			if (less(input[i], pivot1)) {
				exchange(input, i++, lt++);
			} else if (less(pivot2, input[i])) {
				exchange(input, i, gt--);
			} else {
				i++;
			}

		}

		exchange(input, lowIndex, --lt);
		exchange(input, highIndex, ++gt);

		sort(input, lowIndex, lt - 1);
		sort(input, lt + 1, gt - 1);
		sort(input, gt + 1, highIndex);
	}
}


用以下代码测试耗时:

		int RANGE = 1000;
		int SIZE = 1000 * 10000;
		int[] data = new int[SIZE];
		Random rdm = new Random();
		for (int i = 0; i < SIZE; i++) {
			data[i] = rdm.nextInt() % RANGE;
		}
		int[] tem = Arrays.copyOf(data, data.length);
		long start = System.currentTimeMillis();
		new QuickSortBasic().sort(tem);
		System.out.println("basic:" + (System.currentTimeMillis() - start));
		tem = Arrays.copyOf(data, data.length);
		start = System.currentTimeMillis();
		new QuickSort3Way().sort(tem);
		System.out.println("3 way:" + (System.currentTimeMillis() - start));
		tem = Arrays.copyOf(data, data.length);
		start = System.currentTimeMillis();
		new QuickSortDualPivot().sort(tem);
		System.out.println("dual privot:" + (System.currentTimeMillis() - start));

结果大约是:

RANGE/SIZE

100,000/10,000,000
basic:1150
3 way:1006
dual privot:1382

1,000/10,000,000
basic:1009
3 way:679
dual privot:23569

100/10,000,000
basic:949
3 way:430
Exception in thread "main" java.lang.StackOverflowError

1,000,000/1,000,000

basic:151
3 way:147
dual privot:115

发现在重复数据多的时候,还是三路快速排序效率高.双基准排序只有在重复数据不够多的情况下效率才会超过三路排序.

对这些算法不是很熟.只是根据那篇文章学到的.如果有问题,就评论一下.谢谢!


下面把剩下两个算法记一下,以便以后学习:

快速排序基本排序:

package test;

public class QuickSortBasic extends QuickSort {

	public void sort(int[] input) {
		sort(input, 0, input.length - 1);
	}

	private void sort(int[] input, int lowIndex, int highIndex) {
		if (highIndex <= lowIndex) {
			return;
		}

		int partIndex = partition(input, lowIndex, highIndex);

		sort(input, lowIndex, partIndex - 1);
		sort(input, partIndex + 1, highIndex);
	}

	private int partition(int[] input, int lowIndex, int highIndex) {
		int i = lowIndex;
		int pivotIndex = lowIndex;
		int j = highIndex + 1;

		while (true) {

			while (less(input[++i], input[pivotIndex])) {
				if (i == highIndex)
					break;
			}

			while (less(input[pivotIndex], input[--j])) {
				if (j == lowIndex)
					break;
			}

			if (i >= j)
				break;

			exchange(input, i, j);

		}

		exchange(input, pivotIndex, j);

		return j;
	}
}


快速排序三路排序:

package test;

public class QuickSort3Way extends QuickSort {

	public void sort(int[] input) {
		sort(input, 0, input.length - 1);
	}

	public void sort(int[] input, int lowIndex, int highIndex) {
		if (highIndex <= lowIndex)
			return;

		int lt = lowIndex;
		int gt = highIndex;
		int i = lowIndex + 1;

		int pivotIndex = lowIndex;
		int pivotValue = input[pivotIndex];

		while (i <= gt) {

			if (less(input[i], pivotValue)) {
				exchange(input, i++, lt++);
			} else if (less(pivotValue, input[i])) {
				exchange(input, i, gt--);
			} else {
				i++;
			}

		}

		sort(input, lowIndex, lt - 1);
		sort(input, gt + 1, highIndex);
	}
}


<think>好的,用户现在让我讲解快速排序算法的C++实现。首先,我需要回忆一下快速排序的基本原理和步骤。快速排序是一种分治算法,核心思想是选择一个基准元素,将数组分成两部分,一部分小于基准,另一部分大于基准,然后递归地对这两部分进行排序。 接下来,我要确定用户的需求。他们可能正在学习算法,或者需要在实际项目中使用快速排序。考虑到用户提到C++,可能需要具体的代码示例和解释。用户可能对时间复杂度、稳定性以及实现细节感兴趣,比如如何选择基准,如何处理重复元素等。 我需要判断用户的知识水平。他们可能是初学者,所以应该避免使用过于复杂的术语,保持解释的简洁性。同时,提供代码示例时,要确保代码结构清晰,注释明确,便于理解。 然后,我要组织内容的结构。通常,讲解算法可以分为以下几个部分:算法思想、步骤详解、代码实现、复杂度分析、优缺点以及可能的优化方法。此外,针对C++的实现,可能需要强调递归的使用和分区过程。 在编写代码示例时,需要注意变量命名和代码风格,使其符合C++的惯例。例如,使用vector而不是原始数组,这样更符合现代C++的实践。同时,解释分区函数的作用和循环不变量,帮助用户理解每个步骤的目的。 可能存在的疑问点包括基准的选择对性能的影响,如何处理重复元素,以及递归的终止条件。需要提前预见到这些问题,并在讲解中做出说明,例如解释随机选择基准的好处,或者如何避免栈溢出问题。 另外,用户可能想知道快速排序在实际应用中的表现,比如与其他排序算法的比较。因此,在复杂度分析部分,应该提到最好、最坏和平均情况的时间复杂度,以及空间复杂度,特别是递归调用带来的栈空间消耗。 最后,需要检查内容是否准确,代码是否正确。确保分区函数正确地将元素分为两部分,递归调用正确分割子数组。如果有优化方法,比如三数取中法或者尾递归优化,可以作为额外内容提及,但根据用户的水平,可能暂时不需要深入,避免信息过载。 总结下来,回答需要涵盖快速排序的基本原理,C++实现的具体代码,详细的步骤解释,复杂度分析,以及可能的注意事项和优化建议。确保内容结构清晰,语言通俗易懂,帮助用户全面理解快速排序的实现和应用。</think>以下是对快速排序算法及其 C++ 实现的详细讲解: --- ### **快速排序核心思想** 快速排序(Quick Sort)是一种**分治算法**(Divide and Conquer),核心步骤为: 1. **选基准**:从数组中选一个元素作为基准(pivot)。 2. **分区**:将数组分为两部分,小于基准的放左边,大于基准的放右边。 3. **递归**:对左右两个子数组重复上述过程,直至排序完成。 --- ### **C++ 实现代码** ```cpp #include <vector> using namespace std; // 分区函数:将数组分为左右两部分,返回基准的最终位置 int partition(vector<int>& arr, int low, int high) { int pivot = arr[high]; // 选最后一个元素为基准(可优化为随机选择) int i = low - 1; // 指向“小于基准”区域的末尾 for (int j = low; j < high; j++) { if (arr[j] <= pivot) { i++; swap(arr[i], arr[j]); // 将小于基准的元素交换到左侧 } } swap(arr[i + 1], arr[high]); // 将基准放到正确的位置 return i + 1; } // 递归排序函数 void quickSort(vector<int>& arr, int low, int high) { if (low < high) { int pi = partition(arr, low, high); // 获取基准位置 quickSort(arr, low, pi - 1); // 递归处理左半部分 quickSort(arr, pi + 1, high); // 递归处理右半部分 } } // 示例用法 int main() { vector<int> arr = {10, 7, 8, 9, 1, 5}; quickSort(arr, 0, arr.size() - 1); return 0; } ``` --- ### **关键步骤解析** 1. **分区过程(核心)**: - 选择 `arr[high]` 作为基准(可优化为随机选择避免最坏情况)。 - 遍历数组,将所有小于等于基准的元素移到左侧。 - 最后将基准交换到中间位置,此时基准左侧均小于等于它,右侧均大于它。 2. **递归终止条件**: - 当子数组长度 `low >= high` 时停止递归(即只剩一个元素或无元素)。 --- ### **时间复杂度分析** | 场景 | 时间复杂度 | 说明 | |-------------|------------|--------------------------| | 平均情况 | O(n log n) | 每次分区大致平衡 | | 最坏情况 | O(n²) | 数组已有序,基准总选最值 | | 空间复杂度 | O(log n) | 递归调用栈的深度 | --- ### **优化方向** 1. **基准选择优化**: - 随机选择基准:`swap(arr[high], arr[random(low, high)])`。 - 三数取中法:选头、中、尾的中位数作为基准。 2. **减少递归深度**: - 对小数组改用插入排序(如长度 < 15)。 3. **处理重复元素**: - 三向切分(荷兰国旗问题):将数组分为 `<`、`=`、`>` 三部分。 --- ### **示例运行过程** 假设初始数组为 `[3, 1, 4, 2]`: 1. 选基准 `2` → 分区后变为 `[1, 2, 3, 4]`(基准位置为索引1)。 2. 递归处理左子数组 `[1]`(已有序)和右子数组 `[3, 4]`。 3. 右子数组选基准 `4` → 分区后为 `[3, 4]`,递归完成。 --- ### **与其他排序对比** | 算法 | 平均时间复杂度 | 稳定性 | 适用场景 | |------------|----------------|--------|------------------------| | 快速排序 | O(n log n) | 不稳定 | 通用排序,数据量大 | | 归并排序 | O(n log n) | 稳定 | 需要稳定性或链表排序 | | 堆排序 | O(n log n) | 不稳定 | 内存受限场景 | --- 如果有具体疑问(如特定代码逻辑、优化细节),欢迎进一步提问!
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值