quick select 算法:
LintCode
5. 第k大元素
题目:在数组中找到第k大的元素
样例
给出数组 [9,3,2,4,8]
,第三大的元素是 4
给出数组 [1,2,3,4,5]
,第一大的元素是 5
,第二大的元素是 4
,第三大的元素是 3
,以此类推
Solution:
class Solution {
/*
* @param k : description of k
* @param nums : array of nums
* @return: description of return
*/
public int kthLargestElement(int k, int[] nums) {
// write your code here
return quickSelect(nums, 0, nums.length - 1, k);
}
private int quickSelect(int[] nums, int left, int right, int k) {
//选择一个值作为支点,最后结果输出int为支点所在的位置,如果位置等于k,输出,否则继续自身调用
int pivot = nums[left];
int i = left, j = right;
while (i <= j) {
//寻找左侧小于支点的元素
while (i <= j && nums[i] > pivot) {
i++;
}
//寻找右侧大于支点的元素
while (i <= j && nums[j] < pivot) {
j--;
}
//将选择出来的i或j与支点互换(此时支点为i或j,即前两个while中其中一个等于支点直接跳出)
if (i <= j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
i++;
j--;
//对应下方left~j,i~right
}
}
//判断k的位置在支点的左或右,选择一部分执行
if (left + k - 1 <= j) {
return quickSelect(nums, left, j, k);
}
if (left + k - 1 >= i) {
return quickSelect(nums, i, right, k - (i - left));
}
return nums[j + 1];
}
}
(代码源自九章算法,注释自笔者)
快速选择算法与快速排序算法的区别在于,快速选择算法只会对支点的一侧进行排序,或者输出。
这种算法是不能有重复值的,因为每次都要与pivot交换,遇到与pivot相等的值会陷入死循环交换,故而这种方式不能用于快速排序。
快速排序:
public class QuickSortSolution {
public void sortArr(int[] source) {
sort(source,0,source.length-1);
}
private void sort(int[] nums, int left, int right) {
if(left>=right)
return;
int i = left;//后面先+1,这个做pivot
int j = right + 1;//因为后面要先+1
//两个位置都超出范围1个位置
int pivot = nums[left];
while (true) {
while(i+1<nums.length&&nums[++i]<pivot);
while(j>=0&&nums[--j]>pivot);
if(i>=j)
break;
else {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
nums[left] = nums[j];
nums[j] = pivot;
//将j+1=i j寻找到比pivot小的置换为pivot
//j指向pivot
sort(nums,left,j-1);
sort(nums,j+1,right);
}
}