基于快速排序思想partition查找第K大的数或者第K小的数。
快速排序
下面是之前实现过的快速排序的代码。
function quickSort(a,left,right){ if(left==right)return; let key=partition(a,left,right);//选出key下标 if(left<key){ quickSort(a,left,key-1);//对key的左半部分排序 } if(key<right){ quickSort(a,key+1,right)//对key的右半部份排序 } } function partition(a,left,right){ let key=a[left];//一开始让key为第一个数 while(left<right){//扫描一遍 while(key<=a[right]&&left<right){//如果key小于a[right],则right递减,继续比较 right--; } [a[left],a[right]]=[a[right],a[left]];//交换 while(key>=a[left]&&left<right){//如果key大于a[left],则left递增,继续比较 left++; } [a[left],a[right]]=[a[right],a[left]];//交换 } return left;//把key现在所在的下标返回 }
明显我们可以看出快排的思想是每次找到一个基准数,将数组排列成基准数左边的每个数都比基准数大,右边的每个数都比基准数小的序列。 通过这个思想,我们可以稍微修改QuickSort函数,使它变成findKmax函数,使之拥有快速查找前k个最大的数。
基于快速排序思想查找第K大的数
function findKmax(a,k){ let left=0,right=a.length-1; let key=partition(a,left,right); let len=a.length-key; while(len!=k){ if(len>k){ key=partition(a,key+1,right); }else{ key=partition(a,left,key-1); } len=a.length-key; } return a[key]; } function partition(a,left,right){ let key=a[left];//一开始让key为第一个数 while(left<right){//扫描一遍 while(key<=a[right]&&left<right){//如果key小于a[right],则right递减,继续比较 right--; } [a[left],a[right]]=[a[right],a[left]];//交换 while(key>=a[left]&&left<right){//如果key大于a[left],则left递增,继续比较 left++; } [a[left],a[right]]=[a[right],a[left]];//交换 } return left;//把key现在所在的下标返回 }
重点是要注意判定边界条件,left,right,k三个都在变,因此需要检验
同理,还可以求第K小的数
function findKmin(a,k){//查找第K小的数 let left=0,right=a.length-1; let key=partition(a,left,right); while(key!=k-1){ if(key>k-1){ key=partition(a,left,key-1); }else{ key=partition(a,key+1,right); } } return a[key]; } function partition(a,left,right){ let key=a[left];//一开始让key为第一个数 while(left<right){//扫描一遍 while(key<=a[right]&&left<right){//如果key小于a[right],则right递减,继续比较 right--; } [a[left],a[right]]=[a[right],a[left]];//交换 while(key>=a[left]&&left<right){//如果key大于a[left],则left递增,继续比较 left++; } [a[left],a[right]]=[a[right],a[left]];//交换 } return left;//把key现在所在的下标返回 }