线性时间选择

线性时间选择问题:与排序问题类似的元素选择问题。元素选择问题的一般提法是:给定线性序集(无序的)中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语句的条件,跳出循环。

主要代码之二:

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,类似于快速排序算法的思想,对数组进行一次分割,分为两个子数组。
2,对其中之一进行递归处理。
3,1,2语句反复循环,直至满足Select()函数中while循环的终止条件,返回a[m]。

上图:以下两张图来自于 代码二


来自于 代码一
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值