代码和解析全手打,难免手误,如有问题,欢迎私信或评论~
静态分配
#define MaxSize 30
typedef struct{
ElemType data[MaxSize];
int Lenth;
}SqList;
动态分配
#define InitSize 50
typedef struct{
ElemType *data;
int MaxSize,Lenth;
}SeqList;
1、从顺序表中删除最小值元素(假设唯一)并由函数返回被删除的元素的值,空出的位置由最后一个元素填补,若顺序表为空则显示出错信息并退出运行
bool Del_Min(SqList &L,ElemType &e){
if(L.Lenth<1) return false;
int pos=0;
e=L.data[0];
for(int i=0;i
2、设计一个高效算法,将顺序表L的所有元素逆置,要求空间复杂度为O(1)
解析:空间复杂度O(1),也就是不使用额外的辅助空间
方法1:(这我自己写的方法
void reverse(SqList &L){
for(int i=0,j=L.Lenth-1;i>j;i++,j--){
ElemType t=L.data[i];
L.data[i]=L.data[j];
L.data[j]=t;
}
}
方法2:(这是书上答案给的方法
void reverse(SqList &L){
ElemType t;
for(int i=0;i
3、对长度为n的顺序表L,编写一个时间复杂度为O(n)、空间复杂度O(1)的算法,删除线性表中所有值为x的数据元素
解析:符合条件的元素一步一移,注意这个思想,删除线性表我们都可以用这个套路
对比下边第四题 第五题 第六题 看下
void Del_x(SqList &L,ElemType x){
int i,j;
for(i=j=0;i
4、从有序顺序表中删除其值在给定值s和t之间的所有元素(s
解析:注意这个题给定的是有序表,也就是说我们要删除的元素都在一起,是一个区间
所以我们可以考虑一种方法,也是书上给的方法
历记录下要删除的区间起始和结束的地方,计算出区间长度k,将后边的元素直接前移k个单位就好了
但我这里采用的方法是对符合条件的元素一步一移,比刚才说的方法多做了一些移动和比较的操作
没有第一种方法效率高,但从复杂度角度考虑,两者都是O(n)的复杂度
但是后者这个算法的优点是兼容性强
后者可以解决的不仅仅的有序表,无序顺序表删除也可以O(n)内完成
所以在这里我写的是这个算法
bool Del_s_t (SqList &L,ElemType s,ElemType t){
if(s>=t|| L.Lenth==0) return false;
int i,j;
for(i=j=0;i=t){
L.data[j++]=L.data[i];
}
}
L.Lenth=j;
return true;
}
5、从有序顺序表中删除其值在给定值s和t之间的所有元素,包括s和t(s
如果s或t不合理或表空,则显示错误信息并退出
解析:题目给定的依然是有序表,参照我上一题给的解析,这里我用的算法同理
bool Del_s_t (SqList &L,ElemType s,ElemType t){
if(s>=t|| L.Lenth==0) return false;
int i,j;
for(i=j=0;it){
L.data[j++]=L.data[i];
}
}
L.Lenth=j;
return true;
}
6、从有序顺序表中删除所有其值重复的元素,使表中所有元素值均不同
void unique(SqList &L){
int i,j;
for(i=j=1;i
7、两个有序顺序表合并成一个新的有序顺序表,并由函数返回顺序表
关于这个算法的复杂度分析,还考过一个题,可以看这篇 点解跳转--合并两个升序链表复杂度分析(链表顺序表一样
bool merge(SqList L1,SqList L2,SqList &L){
if(L1.Lenth+L2.Lenth>L.Lenth) return false;
int i=0,j=0,k=0;
while(i
8、已知一维数组A[m+n]中依次存放两个线性表(a1,a2,...,am)(b1,b2,...,bn)
编写一个程序,将两个顺序表位置互换
//先写一个函数,实现将数组中left到right区间逆置
bool Reverse(DataType A[],int left,int right,int MaxSize){
if(left>=right||right>=MaxSize) return false;
int mid=(left+right)/2;
for(int i=0;i
9、线性表(a1,a2,...an)递增有序,顺序存储。 要求设计一个算法:
最少的时间找到表中值为x的元素,将其与其后继元素交换位置,若找不到,则插入x,并使线性表仍然有序
void funtion(ElemType A[],ElemType x){
int l=0,r=n-1,mid; //折半查找
while(l=l;i--) A[i+1]=A[i];
A[l]=x;
}
}
10、(2010真题)n个整数存放在一维数组R中,设计一个在时间和空间两方面都尽可能高效的算法 (Xp,Xp+1,...,Xn-1,X0,X1,...,Xp-1)
将R中的序列循环左移P个位置(0
1)给出算法的设计思路
2)用c/c++/java描述算法
3)说明空间复杂度和时间复杂度
解析:
仔细观察可以发现,所谓的循环左移,其实也就是交换数组中两子列的位置
前边我们做过这样的题(第8题),利用逆置
设计思路:
循环左移操作可以看作将数组分为两部分,ab,将其变为ba
我们设Reverse函数实现逆置操作,则完成循环左移需要
Reverse(R,0,p-1);
Reverse(R,p,n-1);
Reverse(R,0,n-1);
描述算法:
bool Reverse(int A[],int l,int r,int maxsize){
if(l>=r||r>maxize) return false;
for(int i=0;i<(r-l+1)/2;i++){
int temp=A[i+l];
A[l+i]=A[r-i];
A[r-i]=temp;
}
return true;
} //逆置
void Converse(int R[],int p,int n){
Reverse(R,0,p-1,n);
Reverse(R,p,n-1,n);
Reverse(R,0,n-1,n);
}
复杂度:
逆置的复杂度是n/2
故0到p-1的逆置复杂度为O(p/2) p到n-1的为O((n-p)/2) 再整体逆置是O(n/2)
加起来 时间复杂度是O(n) 空间复杂度为O(1)
11、(2011年真题)长度为L的升序序列S,在第(L/2)个位置的数称为S的中位数,(注意:向上取整,也就是L=5,则第三个是中位数),两个序列的中位数是指两个序列合并后的的中位数
现给出等长升序序列A和B,试着设计算法,找出A和B的中位数
1)给出算法的设计思路
2)用c/c++/java描述算法
3)说明空间复杂度和时间复杂度
这个算法如果不太懂,可以看这一篇博客,关于这道题的详细解析-->戳一戳~~
设计思路:
分别求出两个升序序列A、B的中位数a、b
1、若a=b 则a,b即为所求的中位数
2、若ab 则舍弃B中较小的一半,同时舍去A中较大的一半,要求两次舍弃的长度相等
在保留下来的两个升序序列中,重复上述三个步骤,直到两个序列中都只上一个元素为止,
较小的就是所求的中位数
算法描述:
int M_search(int A[],int B[],int n){
int s1=0,d1=n-1,s2=0,d2=n-1,m1,m2; //起点 终点 中间点
while(s1!=d1||s2!=d2){
m1=(s1+d2)/2;
m2=(s2+d2)/2;
if(A[m1]==B[m2]) return A[m1]; //若相等
if(A[m1]b 与上边同理 互换操作即可
if((s2+d2)%2==0){
d1=m1;
s2=m2;
}
else{
d1=m1;
s2=m2+1;
}
}
}
return A[s1]
复杂度分析:
时间复杂度O(logn)
空间复杂度O(1)
12、(2013真题) 已知整数序列A=(a0,a1,...,an-1),其中0<=ai
大概就是说,A里面如果有值相同的元素个数超过n/2,则这个值就是主元素
设计算法找主元素。其实就是找众数,且次数大于n/2
如图
设计思路:
因为题目要求,这个数必须出现次数多与总数一半,所以我们可以把所有不一样的
数字互相抵消,最终一定会剩下这个数字
当然还存在无解的情况,所以我们抵消到最后,剩下的,不一定是要求的,需要再扫描验证下
算法描述:
void Sreach(int A[],int n){
int k,cnt=0; //k存数 cnt计数
for(int i=0;i0){
cnt=0;
for(int i=0;in/2) return k; //返回结果
else return -1; //无解
}
else return -1; //无解
}
复杂度分析:
时间复杂度O(2n)=O(n)
空间复杂度O(1)
注意:先排序,再扫描。时间复杂度是O(nlogn)
但是我看答案上居然说写出O(n^2)的复杂度都可以拿到10分!!(那还学啥,别学了~
看来算法不需要太好,关键是要写正确!
13、(2018真题)给定n个整数的数组,设计一个时间上尽可能高效的算法
找出数组中未出现的最小正整数
注意:数组中可能有负数 例如A{-5,3,2,3} 答案是1
1)给出算法的设计思路
2)用c/c++/java描述算法
3)说明空间复杂度和时间复杂度
设计思路:
题上说了时间上尽可能高效,大概就是暗示你空间不需要太省
那么我们再开一个数组B用来打标记,扫描A数组,遇到值在(0,n+1)之间的,把b中对应位置置为1
算法描述:
int findmin(int A[],int n){
int i,*B;
B=(int *)malloc(sizeof(int)*n);
memset(B,0,sizeof(int)*n);
for(int i=0;i0&&A[i]
复杂度:
时间复杂度:O(2n)=O(n)
空间复杂度:O(n)
这个题虽然简单,但是有一些需注意的点:
利用另一个数组计数,这叫桶计数,或叫桶排序
需要注意的是数组的长度是有限的,你可以对比第十二题,
第十二题让我们找众数,原理上来说我们也可以采用这种方法,但是注意题目要求,第十二题给你的是一个序列,长度为n,又没说n的大小,所以你不能用这种方法,因为可能数字太大,数组存不下
而这道题,注意,我们用的方法是只针对值在(0,n+1)之间的数字处理,不在范围的的不用管
而且,题目上说了,给的是A数组,n是数组长度,所以说明n是可以开数组的
基于此,我们才可以开n长度的数组,并且用桶计数
然后再注意,我数组长度开的是n,那下标就是0到(n-1)
极端情况下A中n个数,恰好是1-n,所以存的时候,要错开存
且极端情况下扫描到第n-1个数还没找到,则答案是n+1,所以注意 i 要声明在外边,因为需要用到它的值!