快速排序(Quick Sort)

关键思想

由两端向中间交替搜索直至重合。

时间复杂度

Time ComplexityValue
最优时间复杂度 O ( n l o g 2 n ) O(nlog_{2}n) O(nlog2n)
最差时间复杂度 O ( n 2 ) O(n^{2}) O(n2)
平均时间复杂度 O ( n l o g 2 n ) O(nlog_{2}n) O(nlog2n)

解析:
1)最优时间复杂度:每一轮快速排序所选的关键值正好将序列几乎等分成两部分,经过 l o g 2 n log_{2}n log2n轮划分便可使得所有子表的长度是 1 1 1。因为每轮划分所需的时间与元素个数成正比即 c n cn cn,其中 c c c是常数。
2)最差时间复杂度:每一轮快速排序所选的关键值是序列中最大值或最小值,一共需要经过 n − 1 n-1 n1轮才可结束。具体而言,即第 i i i轮快速排序比较 n − i + 1 n-i+1 ni+1次,则共比较 ∑ i = 2 n = n ( n + 1 ) 2 − 1 \displaystyle\sum_{i=2}^{n}=\frac {n(n+1)} 2-1 i=2n=2n(n+1)1次。
3)平均时间复杂度:统计意义而言,每轮快速排序所选择的关键值是最大值或最小值的概率较小。

空间复杂度

Space ComplexityValue
空间复杂度 O ( n l o g 2 n ) O(nlog_{2}n) O(nlog2n)

注意:部分资料查阅空间复杂度是 O ( 1 ) O(1) O(1)

稳定性 ×

解析:
不稳定性:若原序列中数 i i i位于数 j j j前面,且 i = j i=j i=j,整个排序过程结束之后数 i i i可能位于数 j j j后面。

实例:[12 5 4 19 25 1 34 7 10 23 8 5](Java)

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		System.out.println("请键盘输入整数序列[例如:12 5 4 19 25 1 34 7 10 23 8 5 end]");  // 从键盘接收输入信息
		Scanner list = new Scanner(System.in);
		ArrayList<Integer> inputArray = new ArrayList<Integer>();
		while (list.hasNextInt()) {
			inputArray.add(list.nextInt());
		}  // 输入--非数字--结束输入过程
		list.close();
        System.out.println("输入:" + inputArray);
        Quick_Sort(inputArray, 0, inputArray.size() - 1);
	}
	public static int k = 1;  // 第k轮快速排序
	public static void Quick_Sort(ArrayList<Integer> inputArray, int low, int high) {
		if (low < high) {
			System.out.print("第" + k + "轮" + "快速排序:");
			k += 1;
	// Case1: Start = KEY
		  /*Output(inputArray, low);  // 关键帧位置 
			int key = StartEqualKey(inputArray, low, high);*/
	// Case2: End = KEY
		  /*Output(inputArray, high);  // 关键帧位置
			int key = EndEqualKey(inputArray, low, high); */
			int index = (int)(Math.random() * (high - low)) + low;  // Random = KEY  
			Output(inputArray, index);
			int value = inputArray.get(index);  // 关键值
	// Case3: Random = KEY + Case1
		  /*inputArray.set(index, inputArray.get(low));
			inputArray.set(low, value);  // 将关键值与起始元素互换位置,即问题转化为Case1
			int key = StartEqualKey(inputArray, low, high);*/
	// Case4: Random = KEY + Case2
		  /*inputArray.set(index, inputArray.get(high));
			inputArray.set(high, value);  // 将关键值与末尾元素互换位置,即问题转化为Case2
			int key = EndEqualKey(inputArray, low, high);*/
	// Case5: Random = KEY + IMPROVE
			System.out.print("<" + value + ">" + "与" + inputArray.get(high) + "交换:");
			inputArray.set(index, inputArray.get(high));
			inputArray.set(high, value);  // 将关键值与末尾元素互换位置
			Output(inputArray, high);
			int key = RandomEqualKey(inputArray, low, high);
			// 递归--左子序列和右子序列
			Quick_Sort(inputArray, low, key - 1);  // 递归:左子序列
			Quick_Sort(inputArray, key + 1, high);  // 递归:右子序列
		}
	}

Case1:Start = KEY(从小到大排序)

步骤:

  1. 选择序列中起始元素作为关键值;
  2. 从后往前搜索:若元素值大于等于关键值则保持不变,反之前置;
  3. 从前往后搜索:若元素值小于等于关键值则保持不变,反之后置;
  4. 重复2和3直至两端搜索重合。

第1轮-第2轮
第3轮-第5轮
第6轮-第9轮

// Case1: Start = KEY
	/**  步骤:
			1)选择序列中起始元素作为关键值;
			2)从后往前搜索:若元素值大于等于关键值则保持不变,反之前置;
			3)从前往后搜索:若元素值小于等于关键值则保持不变,反之后置;
			4)重复2)和3)直至两端搜索重合。
	 */
	public static int StartEqualKey(ArrayList<Integer> inputArray, int low, int high) {
		int value = inputArray.get(low);  // 起始元素作为关键值
		while (low < high) {
			// step1:从后往前搜索
			while ((inputArray.get(high) >= value) && (low != high)) {  // 若元素值大于等于关键值则保持不变
				if (inputArray.get(high) == value)
					System.out.print(inputArray.get(high) + "=" + value + " → 不交换 → ");
				else
					System.out.print(inputArray.get(high) + ">" + value + " → 不交换 → ");
				Output(inputArray, low);
				high -= 1;
			}
			if ((inputArray.get(high) < value) && (low != high)) {  // 若元素值小于关键值则前置
				System.out.print(inputArray.get(high) + "<" + value + " → 交换 → ");
				inputArray.set(low, inputArray.get(high));
				inputArray.set(high, value);
				Output(inputArray, high);		
				low += 1;
			}
			// step2:从前往后搜索
			while ((inputArray.get(low) <= value) && (low != high)) {  // 若元素值小于等于关键值则保持不变
				if (inputArray.get(low) == value)
					System.out.print(inputArray.get(low) + "=" + value + " → 不交换 → ");
				else
					System.out.print(inputArray.get(low) + "<" + value + " → 不交换 → ");
				Output(inputArray, high);
				low += 1;
			}
			if ((inputArray.get(low) > value) && (low != high)) {  // 若元素值大于关键值则后置
				System.out.print(inputArray.get(low) + ">" + value + " → 交换 → ");
				inputArray.set(high, inputArray.get(low));
				inputArray.set(low, value);
				Output(inputArray, low);		
				high -= 1;
			}		
		}	
		System.out.print("End: ");
		Output(inputArray, low);
		return low;  // 返回关键值位置=low
	}

Case2:End = KEY(从小到大排序)

步骤:

  1. 选择序列中末尾元素作为关键值;
  2. 从前往后搜索:若元素值小于等于关键值则保持不变,反之后置;
  3. 从后往前搜索:若元素值大于等于关键值则保持不变,反之前置;
  4. 重复2和3直至两端搜索重合。

第1轮-第3轮
第4轮-第7轮

// Case2: End = KEY
	/**  步骤:
			1)选择序列中末尾元素作为关键值;
			2)从前往后搜索:若元素值小于等于关键值则保持不变,反之后置;
			3)从后往前搜索:若元素值大于等于关键值则保持不变,反之前置;
			4)重复2)和3)直至两端搜索重合。
	 */
	public static int EndEqualKey(ArrayList<Integer> inputArray, int low, int high) {
		int value = inputArray.get(high);  // 末尾元素作为关键值
		while (low < high) {
			// step1:从前往后搜索
			while ((inputArray.get(low) <= value) && (low != high)) {  // 若元素值小于等于关键值则保持不变
				if (inputArray.get(low) == value)
					System.out.print(inputArray.get(low) + "=" + value + " → 不交换 → ");
				else
					System.out.print(inputArray.get(low) + "<" + value + " → 不交换 → ");
				Output(inputArray, high);
				low += 1;
			}
			if ((inputArray.get(low) > value) && (low != high)) {  // 若元素值大于关键值则后置
				System.out.print(inputArray.get(low) + ">" + value + " → 交换 → ");
				inputArray.set(high, inputArray.get(low));
				inputArray.set(low, value);
				Output(inputArray, low);		
				high -= 1;
			}
			// step2:从后往前搜索
			while ((inputArray.get(high) >= value) && (low != high)) {  // 若元素值大于等于关键值则保持不变
				if (inputArray.get(high) == value)
					System.out.print(inputArray.get(high) + "=" + value + " → 不交换 → ");
				else
					System.out.print(inputArray.get(high) + ">" + value + " → 不交换 → ");
				Output(inputArray, low);
				high -= 1;
			}
			if ((inputArray.get(high) < value) && (low != high)) {  // 若元素值小于关键值则前置
				System.out.print(inputArray.get(high) + "<" + value + " → 交换 → ");
				inputArray.set(low, inputArray.get(high));
				inputArray.set(high, value);
				Output(inputArray, high);		
				low += 1;
			}
		}	
		System.out.print("End: ");
		Output(inputArray, high);
		return high;  // 返回关键值位置=high
	}

Case3:Random = KEY【优化Case1】(从小到大排序)

思考:如果先随机选择序列中某一元素作为关键值,再将关键值与起始元素互换位置。

Case4:Random = KEY【优化Case2】(从小到大排序)

思考:如果先随机选择序列中某一元素作为关键值,再将关键值与末尾元素互换位置。

Case5:Random = KEY + IMPROVE(从小到大排序)

步骤:

  1. 随机选择序列中某一元素作为关键值;
  2. 将关键值与末尾元素互换位置,形成新的序列;
  3. 从前往后搜索:若元素值小于等于关键值则保持不变,反之后置(与关键值前 面的元素依次互换位置,而非与关键值互换位置);
  4. 重复2和3直至从前往后搜索一轮结束;
  5. 将关键值插入中间位置。

第1轮-第2轮
第3轮-第4轮
第5轮-第7轮

// Case5: Random = KEY + IMPROVE
	/**  步骤:
			1)随机选择序列中某一元素作为关键值;
			2)将关键值与末尾元素互换位置,形成新的序列;
			3)从前往后搜索:若元素值小于等于关键值则保持不变,反之则后置(与关键值前面的元素依次互换位置,而非与关键值互换位置);
			4)重复2)和3)直至从前往后搜索一轮结束;
			5)将关键值插入中间位置。
	 */
	public static int RandomEqualKey(ArrayList<Integer> inputArray, int low, int high) {
		int value = inputArray.get(high);  // 随机选择某一元素作为关键值
		int locationValue = high;  // 关键值位置
		while (low < high) {
			// 从前往后搜索
			while ((inputArray.get(low) <= value) && (low < (high - 1))) {  // 若元素值小于等于关键值则保持不变
				if (inputArray.get(low) == value)
					System.out.print(inputArray.get(low) + "=" + value + " → 不交换 → ");
				else
					System.out.print(inputArray.get(low) + "<" + value + " → 不交换 → ");
				Output(inputArray, locationValue);
				low += 1;
			}
			if ((inputArray.get(low) > value) && (low < (high - 1))) {  
				// 若元素值大于关键值则后置(与关键值前面的元素依次互换位置,而非与关键值互换位置)
				System.out.print(inputArray.get(low) + ">" + value + " → " + inputArray.get(low) 
						+ "与" + inputArray.get(high - 1) + "位置交换 → ");
				int temp = inputArray.get(high - 1);
				inputArray.set(high - 1, inputArray.get(low));
				inputArray.set(low, temp);
				Output(inputArray, locationValue);		
				high -= 1;
			}
			// 某一轮快速排序中剩余的最后一个元素与关键值比较
			if ((inputArray.get(low) > value) && (low == (high - 1))) {  // 当该元素大于关键值时
				System.out.print(inputArray.get(low) + ">" + value + " → " + inputArray.get(low) 
						+ "与<" + value + ">位置交换 → ");
				inputArray.set(locationValue, inputArray.get(low));
				inputArray.set(low, value);
				Output(inputArray, low);
				high -= 1;
			}
			if ((inputArray.get(low) <= value) && (low == (high - 1))) {  // 当该元素小于关键值时
				if (inputArray.get(low + 1) == value) {
					if (inputArray.get(low) == value)
						System.out.print(inputArray.get(low) + "=" + value);
					else
						System.out.print(inputArray.get(low) + "<" + value);
					System.out.print(" → " + inputArray.get(low + 1) + "与<" + value + ">位置不交换 → ");
				}
				else {
					if (inputArray.get(low) == value)
						System.out.print(inputArray.get(low) + "=" + value);
					else
						System.out.print(inputArray.get(low) + "<" + value);
					System.out.print(" → " + inputArray.get(low + 1) + "与<" + value + ">位置交换 → ");
					inputArray.set(locationValue, inputArray.get(low + 1));
					inputArray.set(low + 1, value);
				}
				Output(inputArray, low + 1);
				low += 1;
			}
		}		
		System.out.print("End: ");
		Output(inputArray, high);
		return high;  // 返回关键值位置=high
	}

附录

	public static void Output(ArrayList<Integer> inputArray, int location) {  // 具体每一步骤细节输出
		System.out.print("[");
		if (location == inputArray.size() - 1) {  // 关键值位于序列末端
			for (int num = 0; num < inputArray.size() - 1; num++) {
				System.out.print(inputArray.get(num) + ", ");
			}
			System.out.print("<" + inputArray.get(location) + ">");
		}
		else {  // 关键值位于序列中间(包括起始位置)
			for (int num = 0; num < inputArray.size() - 1; num++) {
				if (num == location)
					System.out.print("<" + inputArray.get(location) + ">, ");
				else
					System.out.print(inputArray.get(num) + ", ");
			}
			System.out.print(inputArray.get(inputArray.size() - 1));
		}
		System.out.println("]");
	}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值