对于给定的n 个元素的数组A (1 : n ),要求从中找出第k小的元素。如果划分元素v测定在A(j)的位置上,则有j-1个元素小于或等于A(j),且有n-j个元素大于或等于A(j)。因此,若k<j,则第k小元素在A(1:j-1)中;若k=j,则A(j)就是第k小元素;若k>j,则第k小元素是A(j+1:n)中第(k-j)小元素。所导出的算法如果成SELECT。此过程把第k小元素放在A(k),并划分剩余的元素,使得A(i)≤A(k),1≤i<k且A(i)≥A(k),k<i≤n。
算法1.3 找第k小元素
procedure SELECT(A,n,k)
//在数组A(1),…,A(n)中找第k小元素s并把它放在位置k,假设1≤k≤n。将剩下的元素按如下方式重新排列,使A(k)=t,对于1≤m<t,有A(m)≤t;对于k<m≤n,有A(m)≥t。A(n+1)=+ //
integer n,k,m,r,j;
m<—1 ; r<— n+1; A(n+1) <—+无穷 ;
loop //每当进入这一循环时,1≤m≤k≤n+1//
j r //将剩余元素的最大下标加1后置给j//
call PARTITION(m,j) //返回j,它使得A(j)是第j小的值//
case
:k=j:return
:k<j:r j //j是新的上界//
:else:m j+1 //j+1是新的下界//
endcase
repeat
end SELECT
C语言代码:
/*选择问题:找第K小的元素*/
#include <stdio.h>
/*快速排序中的划分函数,其中数组array的最后一个数要为无穷大,last为这个数的下标加一,也就是最后一个元素的下标加一;first为数组的第一个元素的下标*/
int partition (int array[], int first, int last){
int v = array[first];
int m = first;
int n = last;
while (1) {
m = m + 1;
while (v > array[m]) {
m++;
}
n = n - 1;
while (v < array[n]) {
n--;
}
if (m < n) {
int temp = array[m];
array[m] = array[n];
array[n] = temp;
}else{
break;
}
}
array[first] = array[n];
array[n] = v;
return n;
}
/*选择函数,其中n为数组元素个数*/
int select1(int array[],int n, int k){
int first = 0;
int last = n;
int j;
while (1) {
j = partition(array, first, last);
if (j == k-1) {
break;
}else if((k-1) < j){
last = j;
}else{
first = j+1;
}
}
return array[j];
}
int main(int argc, char ** argv){
int arr[7] = {3,5,7,4,1,2,90};
printf("%d\n",partition(arr, 0, 7));
for (int i = 0; i < 7; i++) {
printf("%d ",arr[i]);
}
printf("\n%d", select1(arr, 7,1));
return 0;
}