求旋转序列的最小值

一、问题描述:

设有非降序整数序列A=a1, a2, ..., an,则整数序列B=ak+1,..., an, a1,..., ak(1<=k<=n)是序列A的一个旋转序列,当k=n时序列B与序列A相同。给定一旋转序列a[0, 1, ..., n-1],求该序列的最小值。

二、问题求解:

直接二分法搜索。设头指针f,尾指针r,中间指针m=(f+r)/2,则有如下求解过程:

设f=0, r=n-1:

1. 若f小于r,则令m=(f+r)/2,转2;否则,返回a[f],算法结束;

2. 若a[m]大于a[r],则最小值指针pos必在m之后,此时应将f更新为m+1,转1;否则,最小值指针pos必在m或m之前,此时应将r更新为m,转1;

由于循环执行条件是f小于r,故每次循环后,必有f(变大)或r(变小)得到更新,故能保证算法结束。

三、代码实现:

各函数作用如下:

void swap(int &a,int &b);//交换变量a,b的值
int cmp(const void *a,const void *b);//比较a,b所指单元的值的大小,并将数组a非递减排列;
void reverse(int *a,int beg,int end);//将数组a的区间[beg,end]位置上的数据逆置;
void init_arr(int *a,int n);//初始化数组a,随机生成数据,并将数组a非递减排列;
void print_arr(int *a,int n);//打印数组a;
int min_arr(int *a,int n);//寻找旋转序列中的最小值;
void rotate_arr(int *a,int n,int k);//对数组a进行旋转,向右旋转k个单位;

<pre name="code" class="cpp">#include<cstdio>
#include<ctime>
#include<cstdlib>
#include<cassert>

void swap(int &a,int &b);
int cmp(const void *a,const void *b);
void reverse(int *a,int beg,int end);
void init_arr(int *a,int n);
void print_arr(int *a,int n);
int min_arr(int *a,int n);
void rotate_arr(int *a,int n,int k);
int main(int argc,char *argv[]){
	const int SIZE=20;
	int a[SIZE];

	init_arr(a,SIZE);
	print_arr(a,SIZE);
	printf("min:%d\n",min_arr(a,SIZE));
	rotate_arr(a,SIZE,5);
	print_arr(a,SIZE);
	printf("min:%d\n",min_arr(a,SIZE));
	return 0;
}

void swap(int &a,int &b){
	a^=b;b^=a;a^=b;
}

int cmp(const void *a,const void *b){
	return *(int*)a-*(int*)b;
}

void reverse(int *a,int beg,int end){
	while(beg<end){
		swap(a[beg++],a[end--]);
	}
}

void init_arr(int *a,int n){
	srand(time(NULL));
	for(int i=0;i<n;++i){
		a[i]=rand()%20;
	}
	qsort(a,n,sizeof(int),cmp);
}

void print_arr(int *a,int n){
	printf("##begin##\n");
	for(int i=0;i<n;++i){
		printf("%d ",a[i]);
	}
	printf("\n##end##\n");
}

int min_arr(int *a,int n){
	assert(a!=NULL&&n>0);
	int f=0,r=n-1,m;
	while(f<r){
		m=(f+r)>>1;
		if(a[m]>a[r]){
			f=m+1;
		}else{
			r=m;
		}
	}
	return a[f];
}

void rotate_arr(int *a,int n,int k){
	if(a==NULL||n<1||k<1||k>=n){
		return;
	}
	reverse(a,0,k-1);
	reverse(a,k,n-1);
	reverse(a,0,n-1);
}
 

四、测试结果:
<pre name="code" class="cpp">##begin##
0 1 2 3 3 3 4 6 6 7 7 9 9 13 13 13 17 17 18 18
##end##
min:0
##begin##
3 4 6 6 7 7 9 9 13 13 13 17 17 18 18 0 1 2 3 3
##end##
min:0

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值