18、快速排序(代码)

先分享个视频教学网址,讲的很nice! https://www.bilibili.com/video/BV1it41167v2?from=search&seid=7944545082422790984

  • 概念
快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
  • 思路:
快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:

1、从数列中挑出一个元素,称为 “基准”(pivot);
2、重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
3、递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
  • 代码
package Sort;

import java.util.Arrays;

public class QuickSort {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		QuickSort quickSort = new QuickSort();
		int[] arr = {9,6,0,2,5,2,7,1,8};
		quickSort.quickSort(arr, 0, arr.length - 1);
		System.out.println(Arrays.toString(arr));

	}
	
	/**
	 * 我们将数组的第一个元素当做基准 pivot
	 * @param arr   待排数组
	 * @param left  左边的索引值(最小的索引值)
	 * @param right 右边的索引值(最大的索引值)
	 */
	public void quickSort(int[] arr, int left, int right) {
		if(left > right) {
			return;
		}
		//定义基准值:规定将数组第一个元素当做基准pivot
		//此时,应该先进行右遍历,再进行左遍历,否则两个索引值相遇时,指向的元素比基准大。
		int pivot = arr[left];
		//首先定义一个变量,用来当左索引
		int i = left;
		//定义一个变量用来当右索引
		int j = right;
		//定义个临时变量,用于元素交换
		int temp;
		
		
		//开始进行右左索引
		while(i != j) {
			
			//先进行右索引,直到找到比pivot小的元素
			while(i < j && arr[j] >= pivot) {
				j--;
			}
			//然后进行左索引,直到找到比pivot大的元素
			while(i < j && arr[i] <= pivot) {
				i++;
			}
			
			//此时,两者应该同时找到符合要求的元素了,将i和j指向的元素进行交换
			temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;			
		}
		
		//此时,i和j指向同一个元素,将这个元素和基准元素进行交换
		arr[left] = arr[i];
		arr[i] = pivot;
		
		//此时,一遍快排完成,
		//同时,对由基准划分的左右两个数组分别进行快排
		quickSort(arr, left, i-1);
		quickSort(arr, i+1, right);	
	}

}
<think>首先,用户查询的是“用JavaScript实现快速排序代码并查看其图解”。所以我需要提供清晰的JavaScript代码和一个图解来解释快速排序的工作原理。 从系统指令: - 所有行内数学表达式使用$...$格式。但快速排序不涉及数学表达式,所以可能不需要。 - 独立公式使用$$...$$格式,但这里没有公式。 - LaTeX语法正确:确保任何数学内容正确。 - 使用中文回答。 - 生成相关问题:在回答末尾添加相关问题。 - 引用的段落末尾添加引用标识:例如[^1]。 用户提供了引用:[1], [2], [3]: - [1]:JavaScript经典排序方法图解及代码实现,包括冒泡排序和提到快速排序O(nlgn)。 - [2]:双指针法实现快速排序,解释基本思想。 - [3]:图解快速排序算法,不超过18代码Python和JavaScript实现,并提供了一个JavaScript代码示例。 我应该基于这些引用构建我的回答。用户指定了“JavaScript实现快速排序代码及图解”,所以我需要整合信息和提供图解。 结构我的回答: 1. **解释快速排序**:简要介绍快速排序的概念,参考[2]中的描述——“分而治之”的思想。 2. **提供JavaScript代码**:使用[3]中的代码作为示例,因为它是JavaScript实现。我可以复制或适配它。 - 代码在[3]中:quickSortASC函数。 3. **添加图解**:既然用户要求图解,我需要描述或引用一个图解。引用[1]提到“图解”,引用[3]说“图解快速排序算法”,所以我应该创建一个简单的文本描述或步骤图解。 - 由于文本回答,我可以描述关键步骤,类似于图解。 4. **确保回答真实可靠**:基于标准算法知识。 5. **格式**: - 代码块使用Markdown格式:```javascript ... ``` - 解释清晰。 6. **结尾添加相关问题**:根据指令,“生成相关问题”,并在最后以“§§相关问题§§”开始列表。 回答步骤: - 开头解释快速排序。 - 提供JavaScript代码示例。 - 描述图解(步骤可视化)。 - 末尾添加相关问题。 JavaScript代码从[3]: ```javascript function swap_arr(arr, i, j) { var tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } function quickSortASC(nums, start, end) { if (start < end) { var i = start; var j = end; var poit = nums[start]; // pivot element while (i < j) { while (i < j && poit <= nums[j]) { j--; } swap_arr(nums, i, j); while (i < j && poit >= nums[i]) { i++; } swap_arr(nums, i, j); } quickSortASC(nums, start, i); quickSortASC(nums, i + 1, end); } } // 示例用法 num_arr = [23, 34, 544, 234, 17, 554, 78, 656]; quickSortASC(num_arr, 0, 7); console.log(num_arr); // 输出排序后的数组 ``` 图解描述: - 我可以描述分治过程: 1. 选择 pivot(例如数组第一个元素)。 2. Partitioning:使用双指针i和j,从两端向中间移动,交换元素使得小于pivot的在一个子数组,大于的在另一个。 3. 递归排序子数组。 - 提供一个小例子,比如排序 [3, 1, 4, 2]。 相关问题: - 基于主题,如: 1. 快速排序的时间复杂度是多少? 2. 如何优化快速排序? 3. 快速排序与其他排序算法的比较? 添加引用标识: - 在解释或代码后添加[^1], [^2], [^3] 如果直接引用。 最终回答结构: 1. 介绍快速排序。 2. JavaScript代码实现。 3. 图解步骤描述。 4. 相关问题。 </think>以下是针对您查询“用JavaScript实现快速排序代码及图解”的详细解答。我将结合相关引用内容,逐步解释快速排序的原理、JavaScript实现代码,并通过文字图解描述其工作过程。快速排序的核心思想是“分而治之”,通过选择基准元素(pivot)将数组分割为子数组并递归排序[^2]。 ### 1. **JavaScript实现快速排序代码** 基于引用[3]中的优化实现,这是一个完整的JavaScript代码示例(使用双指针法,代码简洁高效): ```javascript function swap_arr(arr, i, j) { var tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } function quickSort(arr, start, end) { if (start < end) { // 初始化指针和基准(pivot) var i = start; var j = end; var pivot = arr[start]; // 选择数组第一个元素作为基准 while (i < j) { // 从右向左找第一个小于pivot的元素 while (i < j && pivot <= arr[j]) { j--; } swap_arr(arr, i, j); // 从左向右找第一个大于pivot的元素 while (i < j && pivot >= arr[i]) { i++; } swap_arr(arr, i, j); } // 递归排序左子数组和右子数组 quickSort(arr, start, i); quickSort(arr, i + 1, end); } return arr; } // 示例用法 var nums = [23, 34, 544, 234, 17, 554, 78, 656]; quickSort(nums, 0, nums.length - 1); console.log(nums); // 输出: [17, 23, 34, 78, 234, 544, 554, 656] ``` **代码说明**: - **`swap_arr`函数**:交换数组中两个元素的位置。 - **`quickSort`函数**: - **参数**:`arr`(待排序数组),`start`(起始索引),`end`(结束索引)。 - **基准选择**:使用数组第一个元素作为pivot(可优化为随机选择以避免最坏情况)。 - **双指针法**:`i`从左侧向右扫描,`j`从右侧向左扫描,确保左子数组元素≤pivot,右子数组元素≥pivot。 - **递归分割**:分区后递归排序左半部分(`start`到`i`)和右半部分(`i+1`到`end`)。 - **时间复杂度**:平均$O(n \log n)$,最坏$O(n^2)$(当数组已有序时)[^1]。 - **空间复杂度**:$O(\log n)$(递归栈深度)。 ### 2. **快速排序图解描述** 以下通过文字步骤图解展示快速排序对数组 `[3, 1, 4, 2]` 的排序过程(结合引用[3]的图解逻辑)。图解基于双指针分区操作: 1. **初始状态**: - 数组:<span style="color:blue;">[3]</span>, 1, 4, 2(蓝色为pivot)。 - 指针:`i=0`(左),`j=3`(右)。 2. **第一轮分区(Partitioning)**: - 步骤1:`j`从右向左扫描,找到第一个小于pivot(3)的元素2(索引3),交换位置: - 数组:2, 1, 4, <span style="color:blue;">[3]</span> - 步骤2:`i`从左向右扫描,找到第一个大于pivot(3)的元素4(索引2),交换位置: - 数组:2, 1, <span style="color:blue;">[3]</span>, 4 - 步骤3:`i`和`j`相遇(i=j=2),分区结束。左子数组:`[2, 1]`;右子数组:`[4]`。 3. **递归排序左子数组 `[2, 1]`**: - 选择pivot=2(第一个元素)。 - `j`从右扫描,找到1<2,交换:数组变为1, <span style="color:blue;">[2]</span>。 - `i`和`j`相遇,递归结束。排序后左子数组:`[1, 2]`。 4. **递归排序右子数组 `[4]`**: - 单元素数组,直接返回`[4]`。 5. **最终合并**: - 左子数组 `[1, 2]` + pivot `3` + 右子数组 `[4]` → 排序结果:`[1, 2, 3, 4]`。 **图解关键点**: - **基准作用**:pivot将数组分为两个独立部分。 - **双指针移动**:确保高效分区(平均时间复杂度$O(n)$)。 - **递归终止条件**:子数组长度≤1时停止递归[^2]。 ### 3. **性能与应用** - **高效场景**:大数据量排序(如前端数据处理),平均性能优于冒泡排序$O(n^2)$[^1]。 - **优化建议**:随机选择pivot或三数取中法避免最坏情况;小数组切换为插入排序。 - **实际应用**:JavaScript中常用于表格排序、数据可视化库(如D3.js)。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值