28.顺序表练习题目(2)(2023王道数据结构2.2.3节9-14题)

试题9:

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

注意:如果折半查找找不到的话,最后退出while循环的时候,low指针指向的是高于x的第一个元素,high指针指向的是低于x的最后一个元素。如下:

#include<iostream>
#include<algorithm>

using namespace std;
#define MaxSize 10
#define ElemType int

//顺序表的建立 
typedef struct{
	int data[MaxSize];  //存储空间的基地址
	int length;  //当前长度 
}SqList;
	 
//顺序表的初始化
void InitList(SqList &L){
	L.length = 0;
	cout<<"顺序表初始化完成"<<endl; 
} 
		
//顺序表传值 
void CreatList(SqList &L,int n){
	cout<<"请传入数值"<<endl; 
	for(int i=0;i<n;i++){
		cin>>L.data[i];
		L.length++;
	}
}
	
//打印顺序表 
int Print(SqList L){
	cout<<"目前顺序表为:"<<endl;
	if (L.length == 0){
	    return 0;
	}
	for (int k = 0; k < L.length; k++){  //输出顺序表 
	    cout<<L.data[k]<<"\t";	
	}
	cout<<endl;
}

SqList SearchExchangeInsert(SqList &L,ElemType x){
//查找,找到就与后继元素交换,找不到就插入
	int low = 0;
	int high = L.length - 1;
	int mid;  //折半查找法
	while(low < high){
		mid = (low + high) / 2;  //向下取整
		if(L.data[mid] == x)
			break;  //找到就退出
		else if(L.data[mid] < x)  //修改high或low指针
			low = mid + 1; 
		else
			high = mid - 1;
	}
	if(L.data[mid] == x && mid < L.length - 1){  //找到,与后继元素交换
		ElemType t;
		t = L.data[mid];
		L.data[mid] = L.data[mid + 1];
		L.data[mid + 1] = t;
	}
	else{
		int i = L.length - 1;
		L.length = L.length + 1;  //插入元素,长度加1
		for (; i > high;i--){  //当i=high时退出循环
			L.data[i + 1] = L.data[i];
		}
		L.data[i + 1] = x; //将x插入high指针后一个位置
	}
	return L;
} 

int main(){
	int n,x;
	cout<<"请输入顺序表L长度"<<endl;
	cin>>n;	 //输入数组的长度n
	SqList L;
	InitList(L);  //顺序表的初始化
	CreatList(L,n);	 //顺序表传值 
	Print(L);  //打印顺序表
	cout<<"请输入插入或交换的元素x"<<endl;
	cin>>x;	 //输入元素x
	Print(SearchExchangeInsert(L,x));  //打印输出交换之后的顺序表
	return 0;
}

输出:

请输入顺序表L长度
5
顺序表初始化完成
请传入数值
1 3 5 7 9
目前顺序表为:
1       3       5       7       9
请输入插入或交换的元素x
4
目前顺序表为:
1       3       4       5       7       9

请输入顺序表L长度
5
顺序表初始化完成
请传入数值
1 3 5 7 9
目前顺序表为:
1       3       5       7       9
请输入插入或交换的元素x
5
目前顺序表为:
1       3       7       5       9

试题10:(2010年联考真题)此题和题8几乎完全一样,不多解释。

试题11:(2011年联考真题)

一个长度为L (L>=1)的升序序列S,处在第\left \lceil L/2 \right \rceil个位置的数称为S的中位数。例如,若序列S1=(11, 13, 15, 17, 19),则S1的中位数是15,两个序列的中位数是含它们所有元素的升序序列的中位数。例如,若S2= (2, 4,6,8, 20),则S1和S2的中位数是11。现在有两个等长升序序列A和B,试设计一个在时间和空间两方面都尽可能高效的算法,找出两个序列A和B的中位数。要求:
(1)给出算法的基本设计思想。
(2)根据设计思想,釆用C或C++或Java语言描述算法,关键之处给出注释。
(3)说明你所设计算法的时间复杂度和空间复杂度。

我的解答:使用试题7的方法暴力求解:

//前面同之前,省略

ElemType Get2listsofmiddle(SqList L1,SqList L2){
//此函数用来查找两个等长升序序列L1,L2的中位数
	int i = 0, j = 0, k = 0;
	SqList L;
	L.length = L1.length;
	while (k < L1.length)
	{
		if(L1.data[i] <= L2.data[j]){
			L.data[k] = L1.data[i];
			k = k + 1;
			i = i + 1;
		}
		else{
			L.data[k] = L2.data[j];
			k = k + 1;
			j = j + 1;
		}
	}
	return L.data[k-1];	
} 

int main(){
	int n,x;
	cout<<"请输入升序顺序表L1,L2的长度"<<endl;
	cin>>n;	 //输入数组的长度n
	SqList L1;
	InitList(L1);  //顺序表的初始化
	CreatList(L1,n);	 //顺序表传值 
	Print(L1);  //打印顺序表L1
	SqList L2;
	InitList(L2);  //顺序表的初始化
	CreatList(L2,n);	 //顺序表传值 
	Print(L2);  //打印顺序表L2
	x = Get2listsofmiddle(L1, L2);
	cout << x << endl;
	return 0;
}

输出:

请输入升序顺序表L1,L2的长度
5
顺序表初始化完成
请传入数值
11 13 15 17 19
目前顺序表为:
11      13      15      17      19
顺序表初始化完成
请传入数值
2 4 6 8 20
目前顺序表为:
2       4       6       8       20
11

这种解法显然不是最优的,答案的解法:

  1. 若a = b,则a或b即为所求中位数,算法结束。
  2. 若a < b,则舍弃序列A中较小的一半,同时舍弃序列B中较大的一半,要求两次舍弃的长度相等。
  3. 若a > b,则舍弃序列A中较大的一半,同时舍弃序列B中较小的一半,要求两次舍弃的长度相等。

这里需要说明几点:对于一个有序线性表,去掉最高和最低的元素之后(头尾),序列的中位数不会发生变化;推广之,去掉等量的最高和最低的元素之后,序列的中位数不会发生变化。此外,两个等长度L的线性表,它们合并成有序表的长度一定是偶数。处在第\left \lceil L/2 \right \rceil个位置的数是中位数,也就是合并成有序表之后的第L个元素就是中位数。

#include<iostream>
#include<algorithm>

using namespace std;
#define MaxSize 10
#define ElemType int

//顺序表的建立 
typedef struct{
	int data[MaxSize];  //存储空间的基地址
	int length;  //当前长度 
}SqList;
	 
//顺序表的初始化
void InitList(SqList &L){
	L.length = 0;
	cout<<"顺序表初始化完成"<<endl; 
} 
		
//顺序表传值 
void CreatList(SqList &L,int n){
	cout<<"请传入数值"<<endl; 
	for(int i=0;i<n;i++){
		cin>>L.data[i];
		L.length++;
	}
}
	
//打印顺序表 
int Print(SqList L){
	cout<<"目前顺序表为:"<<endl;
	if (L.length == 0){
	    return 0;
	}
	for (int k = 0; k < L.length; k++){  //输出顺序表 
	    cout<<L.data[k]<<"\t";	
	}
	cout<<endl;
}

ElemType Get2listsofmiddle(SqList L1,SqList L2){
//此函数用来查找两个等长升序序列L1,L2的中位数
	int s1 = 0, m1, d1 = L1.length - 1;
	int s2 = 0, m2, d2 = L2.length - 1;
	while(s1 != d1||s2 != d2){
		m1 = (s1 + d1) / 2;  //求中位数
		m2 = (s2 + d2) / 2;
		if(L1.data[m1] == L2.data[m2]){  //情况1
			return L1.data[m1];
		}
		else if(L1.data[m1] < L2.data[m2]){  //情况2
			if((s1 + d1) % 2 == 0){  //原表长是奇数,直接取中间
				s1 = m1;
				d2 = m2;
			}
			else{  //原表长是偶数
				s1 = m1 + 1;
				d2 = m2;
			}	
		}
		else{  //情况3
			if((s2 + d2) % 2 == 0){  //原表长是奇数,直接取中间
				s2 = m2;
				d1 = m1;
			}
			else{  //原表长是偶数
				s2 = m2 + 1;
				d1 = m1;
			}
		}
	}
	if(L1.data[s1] < L2.data[s2]) 
		return L1.data[s1];
	else
		return L2.data[s2];
} 

int main(){
	int n;
	cout<<"请输入升序顺序表L1,L2的长度"<<endl;
	cin>>n;	 //输入数组的长度n
	SqList L1;
	InitList(L1);  //顺序表的初始化
	CreatList(L1,n);	 //顺序表传值 
	Print(L1);  //打印顺序表L1
	SqList L2;
	InitList(L2);  //顺序表的初始化
	CreatList(L2,n);	 //顺序表传值 
	Print(L2);  //打印顺序表L2
	cout << Get2listsofmiddle(L1, L2) << endl;
	return 0;
}

输出:

请输入升序顺序表L1,L2的长度
5
顺序表初始化完成
请传入数值
11 13 15 17 19
目前顺序表为:
11      13      15      17      19
顺序表初始化完成
请传入数值
2 4 6 8 20
目前顺序表为:
2       4       6       8       20
11

特别注意:偶数部分不能写成:

else if(L1.data[m1] < L2.data[m2]){  //情况2
	if((s1 + d1) % 2 == 0){  //原表长是奇数,直接取中间
		s1 = m1;
		d2 = m2;
	}
	else{  //原表长是偶数
		s1 = m1;
		d2 = m2 + 1;
	}	

否则会陷入死循环。读者可以拿d-s=1(也就是表中只剩两个元素)的情况检验一下。

试题12(2013年联考真题):

暴力解:注意到0\leqslant a_i < n,构造辅助数组存放0到n-1的个数。

int GetmainElem(SqList L){
//此函数用来寻找主元素,若找不到,返回-1
	SqList L0;  //L0辅助数组
	L0.length = L.length;
	for (int i = 0; i < L0.length; i++){  //L0的所有元素置零
		L0.data[i] = 0;
	}
	for (int i = 0; i < L.length; i++){  //统计里面的元素个数
		L0.data[L.data[i]]++;
	}
	for (int i = 0; i < L.length; i++){  //看里面有无大于L.length/2个数的元素
		if (L0.data[i]>L.length/2){
			return i;
		}
	}
	return -1;
}

int main(){
	int n;
	cout<<"请输入顺序表L的长度"<<endl;
	cin>>n;	 //输入数组的长度n
	SqList L;
	InitList(L);  //顺序表的初始化
	CreatList(L,n);	 //顺序表传值 
	cout << GetmainElem(L) << endl;
	return 0;
}

优解:扫描法。两两相互抵消。如果数组中存在大于一半的相同元素,首先假设第一个元素为主元素的候选元素【统计个数为1】,如果目前元素统计的个数大于0,遇到相同的数字——个数加1,不同的数字——个数减1;当元素统计的个数为0时,将遇到的数字变更为候选的主元素。循环结束时。c可能是主元素,也可能不是。遍历整个数组来统计候选主元素在数组中的个数,如果大于n/2,则存在主元素,反之则不存在。

#include<iostream>
#include<algorithm>

using namespace std;
#define MaxSize 10
#define ElemType int

//顺序表的建立 
typedef struct{
	int data[MaxSize];  //存储空间的基地址
	int length;  //当前长度 
}SqList;
	 
//顺序表的初始化
void InitList(SqList &L){
	L.length = 0;
	cout<<"顺序表初始化完成"<<endl; 
} 
		
//顺序表传值 
void CreatList(SqList &L,int n){
	cout<<"请传入数值"<<endl; 
	for(int i=0;i<n;i++){
		cin>>L.data[i];
		L.length++;
	}
}
	
//打印顺序表 
int Print(SqList L){
	cout<<"目前顺序表为:"<<endl;
	if (L.length == 0){
	    return 0;
	}
	for (int k = 0; k < L.length; k++){  //输出顺序表 
	    cout<<L.data[k]<<"\t";	
	}
	cout<<endl;
}

int GetmainElem(SqList L){
//此函数用来寻找主元素,若找不到,返回-1
	int c = L.data[0]; // 存储主元素
	int count = 1;  //计数
	for (int i = 1; i < L.length;i++){
		if(L.data[i] != L.data[i-1]){
			count--;
			if(count == 0){
				c = L.data[i];
				count = 1;
			}
		}
		else{
			count++;
		}
	}
	int countc = 0;
	for (int i = 0; i < L.length;i++){
		if(L.data[i] == c)
			countc++;
	}
	if(countc>L.length/2)
		return c;
	else
		return -1;
}

int main(){
	int n;
	cout<<"请输入顺序表L的长度"<<endl;
	cin>>n;	 //输入数组的长度n
	SqList L;
	InitList(L);  //顺序表的初始化
	CreatList(L,n);	 //顺序表传值 
	cout << GetmainElem(L) << endl;
	return 0;
}

输出:

请输入顺序表L的长度
8
顺序表初始化完成
请传入数值
0 5 5 3 5 7 5 5
5

请输入顺序表L的长度
8
顺序表初始化完成
请传入数值
0 5 5 3 5 1 5 7
-1

试题13(2018年联考真题):

暴力求解法:这个数肯定不会超过L.length+1,所以从1开始暴力搜索。当搜索完全表都没找到整数则返回。

//前面的依旧省略

int Getlistofsmall(SqList L){
//此函数用来查找未出现的最小正整数,该正整数不会超过L.length+1
	for (int i = 1; i <= L.length; i++)
	{
		int j = 0;
		while(L.data[j] != i && j < L.length){
			j++;
		}
		if(j == L.length)
			return i;
	}
	return L.length + 1;
} 

int main(){
	int n;
	cout<<"请输入顺序表L的长度"<<endl;
	cin>>n;	 //输入数组的长度n
	SqList L;
	InitList(L);  //顺序表的初始化
	CreatList(L,n);	 //顺序表传值 
	cout << Getlistofsmall(L) << endl;
	return 0;
}

时间复杂度最低的解法:用空间换时间,构造辅助数组解决。

#include<iostream>
#include<algorithm>

using namespace std;
#define MaxSize 10
#define ElemType int

//顺序表的建立 
typedef struct{
	int data[MaxSize];  //存储空间的基地址
	int length;  //当前长度 
}SqList;
	 
//顺序表的初始化
void InitList(SqList &L){
	L.length = 0;
	cout<<"顺序表初始化完成"<<endl; 
} 
		
//顺序表传值 
void CreatList(SqList &L,int n){
	cout<<"请传入数值"<<endl; 
	for(int i=0;i<n;i++){
		cin>>L.data[i];
		L.length++;
	}
}
	
//打印顺序表 
int Print(SqList L){
	cout<<"目前顺序表为:"<<endl;
	if (L.length == 0){
	    return 0;
	}
	for (int k = 0; k < L.length; k++){  //输出顺序表 
	    cout<<L.data[k]<<"\t";	
	}
	cout<<endl;
}

int Getlistofsmall(SqList L){
//此函数用来查找未出现的最小正整数,该正整数不会超过L.length+1
	int a[L.length];  //构造辅助数组a
	for (int i = 0; i < L.length; i++)
	{
		a[i] = 0; //把数组a初始化
	}
	for (int i = 0; i < L.length; i++){
		if (L.data[i] > 0 && L.data[i] <= L.length){
			a[L.data[i] - 1] = 1;
		}
	}
	for (int i = 0; i < L.length; i++){
		if (a[i] == 0){
			return i + 1;
		}
	}
	return L.length + 1;
} 

int main(){
	int n;
	cout<<"请输入顺序表L的长度"<<endl;
	cin>>n;	 //输入数组的长度n
	SqList L;
	InitList(L);  //顺序表的初始化
	CreatList(L,n);	 //顺序表传值 
	cout << Getlistofsmall(L) << endl;
	return 0;
}

输出:

请输入顺序表L的长度
4
顺序表初始化完成
请传入数值
-5 3 2 3
1

请输入顺序表L的长度
3
顺序表初始化完成
请传入数值
1 2 3
4

试题14(2020年联考真题):

暴力求解:

int abs(int a){
	if(a>=0)
		return a;
	else
		return -a;
}

int GetDmin(SqList L1,SqList L2,SqList L3){
//此函数用来求解三元组最小距离D=|a-b|+|b-c|+|c-a|.
	int D_Min = 10000;
	int m, n, t;  //记录最小值对应的元素
	for (int i = 0; i < L1.length;i++){
		for (int j = 0; j < L2.length;j++){
			for (int k = 0; k < L3.length;k++){
				int D = abs(L1.data[i] - L2.data[j]) + abs(L2.data[j] - L3.data[k]) + abs(L3.data[k] - L1.data[i]);
				if(D<D_Min){
					D_Min = D;
					m = i;
					n = j;
					t = k;
				}
			}
		}
	}
	return D_Min;
	cout<<L1.data[m]<<L2.data[n]<<L3.data[t]<<endl;
} 

int main(){
	int n1,n2,n3;
	cout<<"请输入顺序表L1的长度"<<endl;
	cin>>n1;	 //输入数组的长度n1
	SqList L1;
	InitList(L1);  //顺序表的初始化
	CreatList(L1,n1);	 //顺序表传值 
	cout<<"请输入顺序表L2的长度"<<endl;
	cin>>n2;	 //输入数组的长度n1
	SqList L2;
	InitList(L2);  //顺序表的初始化
	CreatList(L2,n2);	 //顺序表传值
	cout<<"请输入顺序表L3的长度"<<endl;
	cin>>n3;	 //输入数组的长度n1
	SqList L3;
	InitList(L3);  //顺序表的初始化
	CreatList(L3,n3);	 //顺序表传值
	cout<<"最小距离D_Min是"<<endl;
	cout << GetDmin(L1,L2,L3) << endl;
	return 0;
}

输出:

请输入顺序表L1的长度
3
顺序表初始化完成
请传入数值
-1 0 9
请输入顺序表L2的长度
4
顺序表初始化完成
请传入数值
-25 -10 10 11
请输入顺序表L3的长度
5
顺序表初始化完成
请传入数值
2 9 17 30 41
最小距离D_Min是
2

最优解法:实际上D就是2倍的最大值减去最小值。每次只更新最小值可以回避掉大量的试错成本:

#include<iostream>
#include<algorithm>

using namespace std;
#define MaxSize 10
#define ElemType int

//顺序表的建立 
typedef struct{
	int data[MaxSize];  //存储空间的基地址
	int length;  //当前长度 
}SqList;
	 
//顺序表的初始化
void InitList(SqList &L){
	L.length = 0;
	cout<<"顺序表初始化完成"<<endl; 
} 
		
//顺序表传值 
void CreatList(SqList &L,int n){
	cout<<"请传入数值"<<endl; 
	for(int i=0;i<n;i++){
		cin>>L.data[i];
		L.length++;
	}
}
	
//打印顺序表 
int Print(SqList L){
	cout<<"目前顺序表为:"<<endl;
	if (L.length == 0){
	    return 0;
	}
	for (int k = 0; k < L.length; k++){  //输出顺序表 
	    cout<<L.data[k]<<"\t";	
	}
	cout<<endl;
}

int abs(int a){
	if(a>=0)
		return a;
	else
		return -a;
}

bool ifamin(int a,int b,int c){  //判断第一个元素是不是三元组的最小值
	if(a <= b && a <= c){
		return true;
	}
	else{
		return false;
	}
}

int GetDmin(SqList L1,SqList L2,SqList L3){
//此函数用来求解三元组最小距离D=|a-b|+|b-c|+|c-a|.
	int D_Min = 10000;
	int i = 0, j = 0, k = 0;
	int m, n, t;  //记录最小值对应的元素
	while (i<L1.length&&j<L2.length&&k<L3.length)
	{
		int D = abs(L1.data[i] - L2.data[j]) + abs(L2.data[j] - L3.data[k]) + abs(L3.data[k] - L1.data[i]);
		if(D<D_Min){
			D_Min = D;
			m = i;
			n = j;
			t = k;
			if(ifamin(L1.data[i],L2.data[j],L3.data[k])){
				i = i + 1;
			}
			else if (ifamin(L2.data[j],L1.data[i],L3.data[k])){
				j = j + 1;
			}
			else{
				k = k + 1;
			}
		}
	}
	return D_Min;
	cout<<L1.data[m]<<L2.data[n]<<L3.data[t]<<endl;
} 

int main(){
	int n1,n2,n3;
	cout<<"请输入顺序表L1的长度"<<endl;
	cin>>n1;	 //输入数组的长度n1
	SqList L1;
	InitList(L1);  //顺序表的初始化
	CreatList(L1,n1);	 //顺序表传值 
	cout<<"请输入顺序表L2的长度"<<endl;
	cin>>n2;	 //输入数组的长度n1
	SqList L2;
	InitList(L2);  //顺序表的初始化
	CreatList(L2,n2);	 //顺序表传值
	cout<<"请输入顺序表L3的长度"<<endl;
	cin>>n3;	 //输入数组的长度n1
	SqList L3;
	InitList(L3);  //顺序表的初始化
	CreatList(L3,n3);	 //顺序表传值
	cout<<"最小距离D_Min是"<<endl;
	cout << GetDmin(L1,L2,L3) << endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北京地铁1号线

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值