quick select 可以线性时间求第k小,注意同时也求出了top k,即A[0 : k],因为已经做了partition
思路一
1)partition,轴为i,i是相对于传进来的数组的
2) 如果 i == k - 1, A[i]就是所求;如果i > k - 1, 说明第k在前半部分,并且仍然是前半部分的第k;如果 i < k - 1,说明 第k在后半部分,且是后半部分的第 k - (i + 1)
int findK(int A[], int n, int k) {
if (!A || n < 1 || k > n) throw invalid_argument("invalid argument.");
int i = partition(A, n);
if (k - 1 < i) return findK(A, i, k);
else if(k - 1 > i) return findK(A + i + 1, n - i - 1, k - i - 1);
else return A[i];
}
invariant property 是原数组的第k 始终是当前子数组的第 k'
思路二
1) partition,返回轴为i,这里的i永远是相对原数组的index
2)如果 i == k - 1,A[i]就是第k;如果i > k - 1, 说明第k 在前半部分,end = i - 1;如果 i < k - 1,说明第k在后半部分,令start = i + 1;
3)invariant property 是数组第k必然在[start, end]中
int findK(int A[], int n, int k) {
if (n < k) throw invalid_argument("k bigger than array size.");
int l = 0, r = n - 1;
while (l <= r) {
int i = partition(A, l, r);
if (i == k - 1) return A[i];
if (i > k - 1) r = i - 1;
else l = i + 1;
}
}