数据结构刷题——数组

选择题

数据的存取结构

1、线性表的顺序存储结构是一种()
A.随机存取的存储结构 B.顺序存取的存储结构
C.索引存取的存储结构 D.散列存取的存储结构
错选:B
正选:A
分析:把存储方式和存取方式弄混,存储方式分为顺序、随机(链式、索引和散列),存取方式分为顺序(必须按照存储顺序读取)、随机(自由访问)

链表的特点

1、单链表中,增加一个头结点的目的是
A、是单链表中至少有一个结点 B、标识表结点中首结点的位置
C、方便运算的实现 D、说明单链表是线性表的链式存储
错选:B
正选:C
分析:增加头结点是为了使空链表和非空链表、首结点和其他结点处理一致,即方便运算。

应用题

数组逆序思想应用

1、已知在一位数组A[m+n]中一次存放两个线性表(a1…am)(b1…bn),将数组中两个顺序表的位置互换,即将(b1…bn)放在(a1…am)前面。

分析:两数组长度不一,直接逆序比较混乱,可以先将a逆序为(am…a1),再将b逆序为(bn…b1),这样A中变成为(am…a1)(bn…b1),可以直接将A逆序,得到结果

typedef int  DataType;
void Reserve(DataType A[],int start,int end,int length){
	if(start>=end||start<0||end>=length){
		return;
	}
	int mid=(end-start+1)/2;
	for(int i=0;i<mid;i++){
		int temp=A[start+i];
		A[start+i]=A[end-i];
		A[end-i]=temp;
	}
}
void Exchange(DataType A[],int m,int n,int length){
	Reserve(A,0,m-1,length);
	Reserve(A,m,m+n-1,length);
	Reserve(A,0,m+n-1,length);
}

2、设将n(n>1)个整数存放到一个一维数组R中。设计一个在时间和空间两方面都尽可能高效的算法。将R中保存的序列循环左移p(0<p<n)个位置,即将R中的数据由(X0,X1,…,Xn-1)变换为(Xp,Xp+1,…,Xn-1,X0,X1,…,Xp-1)

分析:直接交换涉及三个以上的数据,观察数据和变换后的循序,可以R分为两部分(X0,X1,…,Xp-1)(Xp,Xp+1,…,Xn-1),将两部分分别逆序得到(Xp-1,…,X1,X0)(Xn-1,…,Xp+1,Xp),再将整体逆序得到(Xp,Xp+1,…,Xn-1)(X0,X1,…Xp-1)

void Reverse(int R[],int start,int end,int length){
	if(start>=end||start<0||end>=length)
		return;
	int mid=(end-start+1)/2;
	for(int i=0;i<mid;i++){
		int temp=R[start+i];
		R[start+i]=R[end-i];
		R[end-i]=R[start-i];
	}
}

void Converse(int R[],int n,int p){
	if(n<=0||p<=0||p>n)
		return ;
	Reverse(R,0,p-1,p);
	Reverse(R,p,n-1,n-p);
	Reverse(R,0,n-1,n);
}

二分查找

1、线性表(a1,a2,…,an)中的元素递增有序且按顺序存储于计算机内,要求设计一个算法完成用最少时间再表中查找数值为x的元素,若找到,则将其与后继元素位置相交换,若找不到,则将其插入表中并使表中元素仍递增有序

分析:有序表查找可以使用二分。需要注意二分时,如果时偶数个数据时,如果移动左右标点到中间位置,可能会造成死循环。所以在移动标点位置时,需要在中间数据的基础上加或减一

void Search(ElemType A[],ElemType x,int& n){
	if(n<0)
		return;
	if(n==0){
		A[0]=x;
		n++;
		return;
	}
	int start=0;
	int end=n-1;
	int mid=0;
	while(start<=end){
		mid=(start+end)/2;
		if(A[mid]==x)
			break;
		if(A[mid]>x){
			end=mid-1;
		}else{
			start=mid+1;
		}
	}
	if(start>end){
		for(int i=n-1;i>end
	}
}

查找中位数

1、一个长度为L(L>=1)的升序序列S,处在第[L/2]个位置的数成为S的中位数。例如,若序列S1=[11,13.15,17,19],则S1的中位数是15,两个序列的中位数是含它们所有元素的升序序列的中位数。例如,若S2=[2,4,6,8,20],则S1和S的中位数是11。现在有两个等长升序序列A和B,试设计一个在时间和空间两方面都尽可能高效的算法,找出两个序列A和B的中位数。

分析:可以采用先排序再求中位数,也可以采用算法。分别取两序列A、B的中位数比较,若一致则为所求中位数;不一致时,较大者的右侧一定位于所求中位数的右侧,较小者的左侧一定位于所求中位数的左侧。故可以在A、B中去除等数量的较大者右侧和较小者左侧,然后重复分别取中比较行为。需要注意的是,如果取中位数的序列个数为偶数个2n时,取中位数下标为n,此时左侧有n-1个数,右侧有n个数,在删去数据时,较小者删去n-1个数,较大者删去n个数,会造成删减后数据个数不一致,则可以通过判断再将较小者中位数一并删去(已经确定不是中位数),使较小者也删去n个,序列删减后数据个数一致

int Search(int A[],int B[],int length){
	//A、B序列待处理的开始和结束位置
	int start1=0;
	int end1=length-1;
	int start2=0;
	int end2=length-1;
	
	//A、B序列待处理的中位数
	int mid1=0;
	int mid2=0;
	
	while(start1<end1||start2<end2){
		mid1=(start1+end1)/2;
		mid2=(start2+end2)/2;
		if(A[mid1]==B[mid2]){
			return A[mid1];
		}
		
		if(A[mid1]<B[mid2]){
			if((start1+end1)%2==0){
				start1=mid1;
				end2=mid2;
			}else{
				start1=mid1+1;
				end2=mid2;
			}
		}else{
			if((start2+end2)%2==0){
				start2=mid2;
				end1=mid1;
			}else{
				start2=mid2+1;
				end1=mid1;
			}
		}
	}
	return A[start1]<B[start2]?A[start1]:B[start2];
}

求主元素

1、已知一个整数序列A=[a1,a2,…,an-1],其中0<=ai<n(0<=i<n)。若存在ap1=ap2=…=apm=x且m>m/2(0<=pk<n,1<=k<m),则称x为A的主元素。例如A=[0,5,5,3,5,7,5,5],则5为主元素;又如A=[0,5,5,3,5,1,5,7],则A中没有主元素。假设A中的n个元素保存在一个一维数组中,请设计一个尽可能高效的算法,找出A的主元素。若存在主元素,则输出该元素;否则输出-1。

分析:所谓主元素是指序列中数量大于序列长度一半的相同数据。可以采用先排序再查找。但还有更加高效的做法,可以采用扫描计数的方法。对于一个主元素占据多于一半的序列,如果去掉两个不一样的数据,主元素的数量依旧多于一半

int Majority(int A[],int n){
	//记录候选主元素的值和数量,设置A中第一个元素为候选主元素
	int c=A[0];
	int count=1;
	for(int i=1;i<n;i++){
		if(A[i]==c){
			count++;
		}else{
			if(count>0){
				count--;
			}else{
				count=1;
				c=A[i];
			}
		}
	}
	count=0;
	if(count>0){
		for(int i=0;i<n;i++){
			if(A[i]==c)
				count++;
		}
	}
	if(count>n/2)
		return c;
	else return -1;
}

求最短距离

1、定义三元组(a,b,c)(a,b,c均为正数)的距离D=|a-b|+|b-c|+|c-a|。给定三个非空整数集合S1、S2和S3,按升序分别存储在三个数组中。请设计一个尽可能高效的算法。例如S1={-1,0,9},S2={-25,-10,10,11},S3={2,9,17,30,41},则最小距离为2,相应的三元组为(9,10,9)。

分析:集合元素均为升序,可以采用暴力但是时间复杂度很高。由于最小距离实际上是三点中最大值和最小值的距离的两倍,所以最小值的影响因素只有最大值和最小值,而数组元素都是升序排列,移动最大值的点不能达到缩短最短距离的效果,只能移动最小值的点,使其不断逼近。

//找到三点中最大点
int maxOne(int a,int b,int c){
	if(a>=b&&a>=c){
		return a;
	}else if(b>=a&&b>=c){
		return b;
	}else{
		return c;
	}
}
//找到三点中最小点
int minOne(int a,int b,int c){
	if(a<=b&&a<=c){
		return a;
	}else if(b<=a&&b<=c){
		return b;
	}else{
		return c;
	}
}
int findMin(int A[],int B[],int C[],int m,int n,int l){
	//max、min记录最大和最小点,i,j,k移动三个三元组的下标,min_len记录最短距离
	int i=0,j=0,k=0;
	int min=minOne(A[0],B[0],C[0]);
	int max=maxOne(A[0],B[0],C[0]);
	int min_len=2*(max-min);
	//每次移动最小点,更新最短距离
	while(i<m&&j<n&&k<l){
		min=minOne(A[i],B[j],C[k]);
		max=maxOne(A[i],B[j],C[k]);
		int len=2*(max-min);
		min_len=min_len<len?min_len:len;
		if(A[0]==min)
			i++;
		else if(B[0]==min)
			j++;
		else k++;
	}
	return min_len;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值