Princeton Algorithms. QuickSort

11 篇文章 0 订阅

Algorithm

  1. 打乱数组;
  2. 随机挑选一个值(一般取第一个),使得它的左侧全部小于他,右侧全部大于他;(用两个指针,一个遍历找到小于它的,一个遍历找到大于它的, 如果发现未知反了,那么交换两个指针当前位置的值)
  3. 将左右部分递归,得出有序数组

Implementation:
4. 找到索引位置

private int partition(Comparable[] a, int lo, int hi) {
	int i = lo;
	int j = hi;
	while (true) {
		// 找到需要与j交换的index i的位置
		while (less(a[++i], a[lo])) {
			// 如果越界了,那么就break
			if (i == hi) {
				break;
			}
		}
		while (less(a[lo], a[j--])) {
			if (j == lo) {
				break;
			}
		}
		// index已经全部遍历,那么说明已经有序,直接终止循环
		if (i >= j) break;
		// 关于这里为什么要取j的位置,因为当j遍历的数大于lo时,j还会移动,j会一直移动到小于lo的数值的位置
		exch(a, lo, j);
		// 返回的是位置
		return j;
	}
}
  1. 排序
private void quickSort(Comparable[]a) {
	SdtRandom.shuffle(a);
	sort(a, 0, a.length - 1);
}
private void sort(Comparable[] a, int lo, int hi) {
	if (lo >= hi) return;
	int index = partition(a, lo, hi);
	sort(a, lo, index-1);
	sort(a, index+1, hi);
}

几个要点:
1 指针停止位置比较复杂,需要多次练习;
2 如果存在相等的值,索引位置最好停在和其相同的值;
3.如果数组已经有序,或者有很多相同的值,那么效率是非常低的;
4.比mergesort效率高39%,但是通常实行时候比mergesort要快,因为数据移动比较少;
5.不稳定

** 改进
如果partition之后长度小于等于10了,可以改为用InsertionSort;
或者去中位数作为pivot;

Selection

(Leetcode 215, Leetcode 378, Leetcode 692)

private static Comparable select(Comparable[] a, int k) {
	StdRandom.shuffle(a);
	int lo = 0;
	int hi = a.length - 1;
	while (hi > lo) {
		// 找到pivot
		int j = partition(a, lo, hi);
		if (j < k) lo = j + 1;
		if (j > k) hi = j - 1;
		if (j == k) return a[k];	
		
	}
	return a[k];
}

** 这样的话就不需要排序,只要通过partition来找出在k位置的pivot就可以

Duplicate keys

Partition: 把等于pivot的值全部连在一起,也就是把array分成了三个区间

private void sort(Comparable[] a, int lo, int hi) {
	if (hi <= lo) return;
	int lt = lo;
	int gt = hi;
	// pivot(partitioning item)
	Comparable v = a[lo];
	int i = lo;
	while (i <= gt) {
		// 移动i, 和v比较,如果小,交换位置
		int cmp = a[i].compareTo(v);
		if (cmp < 0) {
			exch(a,lt++,i++);
		}else if (cmp > 0) {
			exch(a, i, gt--);
		}else {
			i++;
		}
	}
	sort(a, lo, lt - 1);
	sort(a, gt + 1, hi);
}

注:

Q:Why does \verb#Arrays.sort()#Arrays.sort() in Java use mergesort instead of quicksort when sorting reference types ?

The Java API for Arrays.sort() for reference types requires that it is stable and guarantees n \log nnlogn performance. Neither of these are properties of standard quicksort.
Quicksort uses less memory and is faster in practice on typical inputs (and is typically used by \verb#Arrays.sort()#Arrays.sort() when sorting primitive types, where stability is not relevant).

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值