《数据结构》习题刷刷刷2(第二章线性表的顺序表示)

文章目录

04.从有序顺序表中删除其值在给定值s与t之间(要求s<t)的所有元素,若s或t不合理或顺序表为空,则显示出错信息并退出运行。

错误示范:

bool Del_s_t(Sqlist &L,Elemtype s,Elemtype t){
    
    
if(s>=t||L.lengths == 0)
return false;
int k=0,i;
for(i=0;i<L.length-1;i++){
    
    
if(s<L.data[i]&&L.data[i]<t)
k++;
else
L.data[i-k]=L.data[i];
}
L.length = L.length-k;
return ture;
}

说实话,习题答案我看不懂(如下所示):

bool Del_s_t(Sqlist &L,Elemtype s,Elemtype t)
{
    
    
	int i,j;
	if(s>=t||L.length==0)
		return false;
	for(i=0;i<L.length&&L.data[i]<s;i++);//得i个小于s的元素
	if(i>=L.length)
	return false;
	for(j=i;j<L.length&&L.data[j]<=t;j++);//有;号,j=i,得j个既大于s又小于t的元素
	for(;j<L.length;i++,j++)
		L.data[i]=L.data[j];//j继续自加,相当于省略删除了符合题意的中间的元素
	L.length = i;
	return false;
}
05.从顺序表中删除其值在给定值s与t之间(包含s和t,要求s<t)的所有元素,若s或t不合理或顺序表为空,则显示出错信息并退出运行。
bool Del_s_t(Sqlist &L,Elemtype s,Elemtype t){
    
    
if(s>=t||L.lengths == 0)
return false;
int k=0,i;
for(i=0;i<L.length-1;i++){
    
    
if(L.data[i]>=s&&L.data[i]<=t)
	k++;
else
	L.data[i-k]=L.data[i];
}
L.length = L.length-k;
return ture;
}
06.从有序顺序表中删除所有其值重复的元素,使表中所有元素的值均不同。

错误示范:

bool Delete_Same(Sqlist &L)
{
    
    
if(L.length==0)
return false;
int sum_k = 0;
for(int i=0;i<L.length-1;i++)
{
    
    
	int k=0;
	for(int j=i+1;j<L.length;j++)
	{
    
    
		if(L.data[i]==L.length[j])
		{
    
    
			k++;
		}
		else
			L.data[j-k] = L.data[j];
	}
	sum_k +=k;
}
L.length -= sum_k;
}

说实话,习题答案我不太理解(如下所示代码):
因为是有序顺序表,则值相同的元素一定在连续的位置上。(同理,可理解04题的习题答案)(看到这句话后才有点思路)

bool Delete_Same(SeqList &L)
{
    
    
	if(L.length==0)
		return false;
	int i,j;
	for(i=0,j=1;j<L.length;j++)
		if(L.data[i]!=L.data[j])
			L.data[++i]=L.data[j];//知道遇到!=,i++才会被执行,否则i不动
	L.length=i+1;
	return true;
}
07.将两个有序顺序表合并为一个新的有序顺序表,并由函数返回结果顺序表。

错误示范(没考虑i,j是否访问越界,没考虑没有比较完的顺序表):

bool Merge(SeqList A,SeqList B,SeqList &C)
{
    
    
	if(A.length+B.length>C.MaxSize)
		return false;
	int i=0,j=0,k=0;//i,j谁所在数组元素赋给了C有序顺序表谁就自加1,否则不变。
for(k=0;k<A.length+B.length;k++)
{
    
    
	if(A.data[i]<=B.data[j])
				{
    
    
					C.data[k]=A.data[i];
					i++;
				}
	else
				{
    
    
					C.data[k]=B.data[j];
					j++
				}
}
C.length = k;//又忘记了
return true;
}

正确答案如下:

bool Merge(SeqList A,SeqList B,SeqList &C)
{
    
    
	if(A.length+B.length>C.MaxSize)
		return false;
	int i=0,j=0,k=0;
	while(i<A.length&&j<B.length)//满足相应条件,避免访问越界;两两比较,小者存入结果表
	{
    
    
		if(A.data[i]<=B.data[j])
			C.data[k++]=A.data[i++];//相当于先执行C.data[k]=A.data[j];在执行k++;i++;
		else
			C.data[k++]=B.data[j++];
	}
	while(i<A.length)//还剩一个没有比较完的顺序表
	{
    
    
		C.data[k++]=A.data[i++];
	}
	while(j<B.length)
	{
    
    
		C.data[k++]=B.data[j++];
	}
	C.length = k;
	return true;
}
08.已知在一维数组A[m+n]中依次存放两个线性表(a1,a2,a3,,am)和(b1,b2,b3,,bn,).编写一个函数,将数组中两个顺序表的位置互换,即将(b1,b2,b3,…,bn)放在(a1,a2,a3,…,am)的前面。
typedef int DataType;
void Reverse(DataType A[],int left,int right,int arraySize)
{
    
    
	if(left>=right||right>=arraySize)
		return;
	int mid=(left+right)/2;
	for(int i=0;i<mid-left;i++)
	{
    
    
		DataType temp = A[left+i];
		A[left+i]=A[right-i];
		A[right-i]=temp;
	}
}
void Exchange(DataType A[],int m,int n,int arraySize)
{
    
    
	Reverse(A,0,m+n-1,arraySize);//先将全部元素逆置
	Reverse(A,0,n-1,arraySize);//再将前n个元素逆置
	Reverse(A,n,m+n-1,arraySize);//再将后m个元素逆置,实现顺序表的位置互换
}
09.线性表(a1,a2,a3,…,an)中的元素递增有序且按顺序存储于计算机内。要求设计一个算法,完成用最少时间在表中查找数值为x的元素,若找到,则将其与后继元素位置相交换,若找不到,则将其插入表中并使表中元素仍递增有序

错误示范:

void SearchExchangeInsert(SeqList &L,int x)
{
    
    
	int i,temp,k;
	for(i=0;i<L.length;i++)
	{
    
    
		if(L.data[i]==x)
		{
    
    
			temp = L.data[i];
			L.data[i]=L.data[i+1];
			L.data[i+1]=temp;
			k++;
		}
	}
	int j,h;
	if(k==0||L.length<=MaxSize)
	{
    
    
		for(j=0;j<L.length;j++)
		{
    
    
			if(x<L.data[j])
				break;
		}
		for(h=L.length-1;h>j;h--)
		{
    
    
			L.data[h+1]=L.data[h];
		}
		L.data[j] = x;
		L.length += 1;
	}
}

正确答案:(题目要求用最少的时间在表中,查找数值为x的元素,应使用折半查找法)

void SearchExchangeInsert(ElemType A[],ElemType x)
{
    
    
	int low=0,high=n-1,mid;
	while(low<=high)
	{
    
    
		mid = (low+high)/2;//商取整
		if(A[mid]==x)
			break;
		else if(A[mid]<x) low = mid+1;
		else high = mid-1;
	}
	if(A[mid]==x&&mid!=n-1)//若最后一个元素与x相等,则不存在与其后继交换的操作
	{
    
    
		t = A[mid]; A[mid] = A[mid+1]; A[mid+1] = t;
	}
	if(low>high)//查找失败
	{
    
    
		for(i = n-1;i>high;i--;) A[i+1]=A[i];
		A[i+1]=x;
	}
}
10.【2010统考真题】设将n(n>1)个整数存放到一维数组R中。设计一个在时间和空间两方面都尽可能高效的算法。将R中保存的序列循环左移p(0<p<n)个位置,即将R中的数据由(X0,X1,…,Xn-1)变换为(化Xp,Xp+1,Xn-1,X0,X1,…,Xp-1.要求:1)给出算法的基本设计思想。2)根据设计思想,采用C或C+或Java语言描述算法,关键之处给出注释. 3)说明你所设计算法的时间复杂度和空间复杂度。

(1)算法思想:(规范算法思想的回答:创建大小为p的辅助数组S,将R中前p个整数依次暂存在S中,同时将R中后n-p个整数左移p个位置,,然后将S中暂存的p个数依次放回R中的后续单元。
(2)使用C语言描述算法如下:

viod Reverse(ElemType &R[],int p)//数组不需要引用吗?
{
    
    
	ElemType S[];
	int i,j,k=0;
	for(i=0;i<R.length;i++)
	{
    
    
		if(i<p) S[i]=R[i];
		else if(i>=p&&i<arraySzie) R[i-p]=R[i];
	}
	for(j=arraySize-1-p;j<arraySize;j++)
	{
    
    
		R[j]=S[k++];
	}
}

(3)算法的时间复杂度为O(n)和空间复杂度O(p)。
更加高效的算法如下:

void Reverse(int R[],int from,int to)
{
    
    	
	int i,temp;
	for(i=0;i<(to-from+1)/2;j++)
	{
    
    temp=R[from+i];R[from+i]=R[to-i];R[to-i]=temp;}
}
void Converse(int R[],int n,int p)
{
    
    
	Reverse(R,0,p-1);
	Reverse(R,p,n-1);
	Reverse(R,0,n-1);
}//时间复杂度为O(n),空间复杂度为O(1). 
11.【2011统考真题】一个长度为L(L≥1)的升序序列S,处在第「L/2个位置的数称为S的中位数.例如,若序列S1=(11,13,15,17,19),则S,的中位数是15,两个序列的中位数是含它们所有元素的升序序列的中位数。例如,若S2=(2,4,6,8,20),则S1和S2的中位数是11。现在有两个等长升序序列A和B,试设计一个在时间和空间两方面都尽可能高效的算法,找出两个序列A和B的中位数。要求:1)给出算法的基本设计思想。2)根据设计思想,采用C或C+或Java语言描述算法,关键之处给出注释.3)说明你所设计算法的时间复杂度和空间复杂度。

错误示范:

int Mid_Search(int A[],int B[])
{
    
    
	int R[];
	int i,j,k,mid;
	for(i=0;i<arraySizeA+arraySizeB-1;i++)
	{
    
    
		if(i<arraySizeA&&i<arraySizeB)
		{
    
    
			if(A[i]<=B[i]) R[i++]=A[j++];
			else R[i++]=B[k++];
		}
	}
	mid=R[arraySizeR/2];
	return mid;
}

题意是找出序列A和B的中位数,不用合并A和B。
(1)算法思想:分别求两个升序序列A、B的中位数,设为a、b,求序列A、B的中位数过程如下:
1.若a=b,则a或b就是所求中位数,算法结束;
2.若a<b,则舍弃A中较小的一半,同时舍弃B中较大的一半,要求两次舍弃的长度相等;
3.若a>b,则舍弃B中较小的一半,同时舍弃A中较大的一半,要求两次舍弃的长度相等;
在保留的两个升序序列中,重复1.2.3.,直到两个序列中均只含一个元素时为止,较小者则为所求中位数。
(2)用C语言描述算法

int M_Search(int A[],int B[],int n)
{
    
    
	int s1=0,d1=n-1;m1,s2=0,d2=n-1,m2;
	while(s1!=d1||s2!=d2)
	{
    
    
		m1=(s1+d1)/2;
		m2=(s2+d2)/2;
		if(A[m1]==A[m2]);
			return A[m1];
		if(A[m1]<B[m2])
		{
    
    
			if((s1+d1)%2==0)
				{
    
    s1=m1;d2=m2}
			else
				{
    
    s1=m1+1;d2=m2}
		}
		else
		{
    
    
			if((s2+d2)%2==0)
				{
    
    d1=m1;s2=m2}
			else
				{
    
    d1=m1;s2=m2+1}
		}
	}
	return A[s1]<B[s2]? A[s1]:B[s2];
}

(3)时间复杂度为O(log2n),空间复杂度为O(1).

12.【2013统考真题】已知一个整数序列A=(a0,a1,……,an-1),其中0≤ai<n(0≤i<n).若存在ap1=ap2=…=apm=x且m>n/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。要求:1)给出算法的基本设计思想,一2)根据设计思想,采用C或C++或Java语言描述算法,关键之处给出注释,3)说明你所设计算法的时间复杂度和空间复杂度。

(1)算法思想:
(2)用C语言描述算法:

int Majority(int A[]int n)
{
    
    
	int i,c,count = 1;//用c来存储主元素,count来计数
	c=A[0];//设置A[0]为候选主元素
	for(i=1;i<n;i++)//查找候选主元素
		if(A[i]==c)
			count++;//对A中的候选主元素计数
		else
			if(count>0)//处理不是候选主元素的情况
			count--;
			else {
    
    c = A[i];//更新候选主元素重新计数
			count = 1;}
	if(count>0)
		for(i=count=0;i<n;i++)//统计候选主元素实际出现的次数
			if(A[i]==c)
				count++;
	if(count>n/2) return c;//确认候选主元素
	else return -1;//不存在候选主元素
}

(3)时间复杂度是:O(n);空间复杂度是O(1)
说明:本题如果采用先排好序再统计的方法(时间复杂度为O(nlog2n),只要解答正确,最高能拿11分,即便是写出O(n^2)的算法,最高也能拿10分,因此对于统考算法题,花费大量时间去思考最优解法是得不偿失的。)

13.【2018统考真题】给定一个含n(n≥1)个整数的数组,请设计一个在时间上尽可能高效的算法,找出数组中未出现的最小正整数。例如,数组{-5,3,2,3}中未出现的最小正整数是1;数组{1,2,3)中未出现的最小正整数是4.要求:1)给出算法的基本设计思想,2)根据设计思想,采用C或C++语言描述算法,关健之处给出注释,3)说明你所设计算法的时间复杂度和空间复杂度。[。。。。。。]

1)算法的基本设计思想:

要求在时间上尽可能高效,因此采用空间换时间的办法。分配一个用于标记的数组B[],用

来记录A中是否出现了1~n中的正整数,B[0]对应正整数1,B[n-1】对应正整数n,初始化B中全部为0。由于A中含有n个整数,因此可能返回的值是1~n+1,当A中n个数恰好为1~n时返回n+1。当数组A中出现了小于等于0或大于n的值时,会导致1~n中出现空余位置,返回结果必然在1~n中,因此对于A中出现了小于等于0或大于n的值,可以不采取任何操作。

经过以上分析可以得出算法流程:从A[0]开始遍历A,若0<A[1】<=n,则令B[A[i]-1]=1:否则不做操作。对A遍历结束后,开始遍历数组B,若能查找到第一个满足B[1]==0的下标i,返回i+1即为结果,此时说明A中未出现的最小正整数在1~n之间。若B[i]全部不为0,返回i+1(跳出循环时i=n,i+1等于n+1),此时说明A中未出现的最小正整数是n+1。
(2)C语言描述算法:

int FindMissMin(int A[],int n)
{
    
    
	int i,*B;
	B = (int *)malloc(sizeof(int)*n);
	meset(B,0,sizeof(int)*n);
	for(i=0;i<n;i++)
		if(A[i]>0&&A[i]<=n)
			B[A[i]-1]=1;
	for(i=0;i<n;i++)
		if (B[i]==0) break;
	return i+1;
}

(3)时间复杂度是;空间复杂度是

14.【2020统考真题】定义三元组(a,b,c)(a、b、c均为正数)的距离D=a-b1+b-c+1c-d。给定3个非空整数集合S、S2和S,按升序分别存储在3个数组中。请设计一个尽可能高效的算法,计算并输出所有可能的三元组(a,b,c)(a∈S1,b∈S2,c∈S)中的最小距离。例如S1={-1,0,9},S2={-25,-10,10,11},S={2,9,17,30,41},则最小距离为2,相应的三元组为(9,10,9)。要求:1)给出算法的基本设计思想。2)根据设计思想,采用C语言或C++语言描述算法,关键之处给出注释。3)说明你所设计算法的时间复杂度和空间复杂度。

在这里插入图片描述
在这里插入图片描述
(3)C语言描述算法:

#define INT_MAX 0x7fffffff
int abs_(int a)
{
    
    
	if(a<0) return -a;
	else return a
}
bool xls_min(int a,int b,int c)
{
    
    
	if(a<=b&&a<=c) return true;
	return false;
}
int findMinofTrip(int A[],int n,int B[],int m,int C[],int p)
{
    
    
	int i=0,j=0,k=0,D_min=INT_MAX,D;
	while(i<n&&j<m&&k<p&&D_min>0)
	{
    
    
		D=abs_(A[i]-B[j])+abs_(B[j]-C[k]+abs_(A[i]+C[k])
		if(D<D_min) D_min=D;
		if(xls_min(A[i],B[j],C[k])) i++;
		else if(xls_min(B[j],A[i],C[k])) j++;
		else k++;
	}
	return D_min;
}

(3)设n=(|S1|+|S2|+|S3|),时间复杂度为O(n),空间复杂度为O(1).

猜你喜欢

转载自blog.csdn.net/qq_45926254/article/details/127060326