线性时间选择问题:与排序问题类似的元素选择问题。元素选择问题的一般提法是:给定线性序集(无序的)中n个元素和一个整数k,1≤k≤n,要求找出这n个元素中第k小(或大)的元素,即如果将这n个元素依其线性排序时,排在第k个位置的元素即为要找的元素。
代码一:
不同于快排,线性时间选择只对划分出的子数组之一进行递归处理。
基本思想:即对输入的数组进行递归划分。
基本思想:即对输入的数组进行递归划分。
主要代码之一:
int Select(int a[],int n,int x){
int m;//fun()函数的返回值
int k=x;//第K小元素
int L=0;
int r=n-1;
while(1){
m=fun(a,L,r);//对数组进行一次分割
if(m+1==k)//循环结束条件
return a[m];
else if(m+1>k){//进行递归调用,直至满足while()循环的终止条件
r=m-1;
}
else{
L=m+1;
}
}
}
1,调用Select()函数,以数组长度n和第x小元素作为函数形参。
2,与快排类似:通过调用fun()函数对数组进行分割,并返回基准的在结束while循环后的下标m。运用if语句将m+1与第k小元素的比较,判断是否再一次进行递归调用。运用while()语句无限循环,直至满足if语句的条件,跳出循环。
2,与快排类似:通过调用fun()函数对数组进行分割,并返回基准的在结束while循环后的下标m。运用if语句将m+1与第k小元素的比较,判断是否再一次进行递归调用。运用while()语句无限循环,直至满足if语句的条件,跳出循环。
主要代码之二:
int fun(int a[],int L,int r)
{
int x=a[L];//选取最左端元素作为基准值
int i=L;//数组最左端元素的下标值
int j=r+1;//
while(1){
while(a[++i]<x&&i<r);//1,从数组最左端开始遍历,直到寻找到第一个小于基准值的数,当且仅当i<r
while(a[--j]>x);//2,从数组最右端开始遍历,直到寻找到第一个大于基准值的元素
if(i>=j)//循环结束条件
break;
swap(a,i,j);//语句1中左端第一个小于基准值的元素与语句2中右端第一个大于基准值的元素进行值交换
}
swap(a,j,L);//while()循环之后将j记录的最后一个大于基准值的元素与基准进行值交换
return j;//返回最后一个大于基准的元素的下标
}
与快速排序算法相类似,对数组进行一次分割:以数组在左端元素作为基准,实现基准以左的各个元素值均大于基准值,基准以右的元素的值均小于基准值。返回基准值在值交换后的下标。
补充:
//有关于swap()
void swap(int a[],int x,int y){
int t;
t=a[x];
a[x]=a[y];
a[y]=t;
}
完整代码:
#include<stdio.h>
#define N 20
void swap(int a[],int x,int y){
int t;
t=a[x];
a[x]=a[y];
a[y]=t;
}
int fun(int a[],int L,int r){
int x=a[L];
int i=L;
int j=r+1;
while(1){
while(a[++i]<x&&i<r);
while(a[--j]>x);
if(i>=j)
break;
swap(a,i,j);
}
swap(a,j,L);
return j;
}
int Select(int a[],int n,int x){
int m;
int k=x;
int L=0;
int r=n-1;
while(1){
m=fun(a,L,r);
if(m+1==k)
return a[m];
else if(m+1>k){
r=m-1;
}
else{
L=m+1;
}
}
}
int main(){
int a[N]={8,31,60,33,17,4,51,57,49,35,11,43};
int b[N]={4,8,11,17,31,33,35,43,49,51,57,60};
int i,x;
int m;
int n=12;
printf("排序前:\n");
for(i=0;i<n;i++)
printf("%d",a[i]);
printf("\n排序后:\n");
for(i=0;i<n;i++)
printf("%d",b[i]);
printf("\n查询第几小数字:\n");
scanf("%d",&x);
m=Select(a,n,x);
printf("该值为:\n");
printf("%d\n",m);
}
代码二:调用rand()函数随机生成x;
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define N 20
void swap(int a[],int x,int y)
{
int t;
t=a[x];
a[x]=a[y];
a[y]=t;
}
int fun(int a[],int L,int r)
{
int x=a[L];
int i=L;
int j=r+1;
while(1){
while(a[++i]<x&&i<r);
while(a[--j]>x);
if(i>=j)
break;
swap(a,i,j);
}
swap(a,j,L);
return j;
}
int Select(int a[],int n,int x)
{
int m;
int k=x;
int L=0,r=n-1;
while(1){
m=fun(a,L,r);
if(m+1==k)
return a[m];
else if(m+1>k){
r=m-1;
}
else{
L=m+1;
}
}
}
int main(){
int a[N]={8,31,60,33,17,4,51,57,49,35,11,43};
int b[N]={4,8,11,17,31,33,35,43,49,51,57,60};
int i,x;
int m;
int n=12;
printf("排序前:\n");
for(i=0;i<n;i++)
printf("%d ",a[i]);
printf("\n排序后:\n");
for(i=0;i<n;i++)
printf("%d ",b[i]);
printf("\n查询第几小数字:\n");
srand((unsigned)time(NULL));
x=rand()%n+1;
printf("随机生成的x的值:%d\n",x);
m=Select(a,n,x);
printf("第%2d小的值为%2d\n",x,m);
}
总结:
1,类似于快速排序算法的思想,对数组进行一次分割,分为两个子数组。
1,类似于快速排序算法的思想,对数组进行一次分割,分为两个子数组。
2,对其中之一进行递归处理。
3,1,2语句反复循环,直至满足Select()函数中while循环的终止条件,返回a[m]。
3,1,2语句反复循环,直至满足Select()函数中while循环的终止条件,返回a[m]。
上图:以下两张图来自于
代码二


来自于
代码一:
