1、逆置顺序表
题目:设计一个算法,将顺序表L中的一段连续元素逆置,要求算法的空间复杂度为O(1)。
思路:使用两个参数记录需要逆置的元素段的起始位置和末尾位置。设定一个辅助变量t,使用一个循环遍历该数组段的一半,将其与对称位置的元素调换,实现逆置。这里因为辅助变量只有一个,故满足空间复杂度要求。
void Reverse(int *T,int head,int tail){ //逆置函数
int t;
for(int i=0;i<((tail-head)/2);i++){
t=T[i+head];
T[i+head]=T[tail-i];
T[tail-i]=t;
}
}
2、循环移动顺序表元素
题目:设将n(n>1)个整数存放到一维数组R中。设计一个在时间和空间两方面都尽可能高效的算法。将R中保存的序列循环左移p(0<p<n)个位置,即将R中的数据由变換为
。
解法1:创建一个长度为p的临时数组P,将原数组的前p位元素先存进P里,再将原数组的后n-p位元素向左移动p位,最后把P里的p个元素放回数组末尾。这样算法的时间复杂度为O(n),空间复杂度为O(p)。
代码如下:
#include <iostream>
using namespace std;
void Assign(int *R,int n) { //赋值函数
for(int i=0;i<n;i++)
cin>>R[i];
}
void Movement(int *T,int n,int p){ //移动函数
int *P=new int[p]; //临时辅助数组
int i;
for(i=0;i<p;i++) //储存前p个
P[i]=T[i];
for(i=0;i<n-p;i++) //移动前n-p个
T[i]=T[i+p];
for(i=0;i<p;i++) //赋值后p个
T[i+n-p]=P[i];
delete[] P;
}
int main(){
int n,p;
cin>>n>>p;
int *R=new int[n];
Assign(R,n); //赋值
Movement(R,n,p); //移动
for(int i=0;i<n;i++) //输出
cout<<R[i];
delete[] R;
return 0;
}
解法2:给出一个示例ABCDEF,左移一位变成BCDEF A,移两位变为CDEF AB,移三位变为DEF ABC。观察可以得到,如果把数组的前p位假设为数组a,后n-p位假设为数组b,则移动p位等同于将ab变为ba。那么如何将ab变为ba呢?这里可以用到数组处理的一种常用方法,即将数组逆置。通过观察可以发现,这里的
为求逆操作,即将一维数组逆置。
这种方法看起来更复杂了一点,但是由于数组逆置算法的空间复杂度为O(1),事实上降低了空间复杂度。
代码如下:
#include <iostream>
using namespace std;
void Assign(int *R,int n) { //赋值函数
for(int i=0;i<n;i++)
cin>>R[i];
}
void Reverse(int *T,int head,int tail){ //逆置函数
int t;
for(int i=0;i<((tail-head)/2);i++){
t=T[i+head];
T[i+head]=T[tail-i];
T[tail-i]=t;
}
}
int main(){
int n,p;
cin>>n>>p;
int *R=new int[n];
Assign(R,n); //赋值函数
Reverse(R,0,n-p-1); //逆置前n-p个
Reverse(R,n-p,n-1); //逆置后p个
Reverse(R,0,n-1); //整体逆置
for(int i=0;i<n;i++)
cout<<R[i];
delete[] R;
return 0;
}
3、删除顺序表定值元素
题目:对长度为 n的顺序表L,编写一个时间复杂度为 O(n)、空间复杂度为 O(1)的算法,该算法删除顺序表中所有值为x的数据元素。
思路:在一次循环中遍历顺序表的所有元素,使用一个参数k记录至当前位置需要被删除的元素的个数,k初值为0。若遇到值为x的元素,则k加1,顺序表长度-1;若遇到非x的元素,将其前移k位。
代码如下:
#include <iostream>
using namespace std;
#define InitSize 50
typedef struct{ //定义顺序表
int *data;
int MaxSize,length;
}Sqlist;
void InitSqlist(Sqlist &L){ //初始化
L.MaxSize=InitSize;
L.data=new int[L.MaxSize];
L.length=0;
}
void Assign(Sqlist &L,int n) { //赋值函数
for(int i=0;i<n;i++){
cin>>L.data[i];
L.length++;
}
}
void Delete(Sqlist &L,int x,int n){ //删除函数
int k=0; //统计当前需删除的个数
for(int i=0;i<n;i++) {
if (L.data[i]==x) {
k++; //当前需删除的个数+1,顺序表的长度-1
L.length--;
}
else if (L.data[i]!=x) //将不需要删除的元素前移k位
L.data[i-k]=L.data[i];
}
}
void Output(Sqlist L){ //输出顺序表
for(int i=0;i<L.length;i++)
cout<<L.data[i]<<" ";
}
int main(){
int n,x;
cin>>n>>x;
Sqlist R; //定义结构体
InitSqlist(R); //初始化顺序表
Assign(R,n); //顺序表赋值
Delete(R,x,n); //调用删除函数
Output(R); //调用输出函数
return 0;
}
4、删除给定范围内顺序表元素
题目:从顺序表中删除其值在给定值s和t之间(包含s和t,要求s<t)的所有元素,若s或不合理或顺序表为空,则显示出错信息并退出运行。
思路:与上一题基本一致,加一个判定条件。
代码如下:
#include <iostream>
using namespace std;
#define InitSize 50
typedef struct{ //定义顺序表
int *data;
int MaxSize,length;
}Sqlist;
void InitSqlist(Sqlist &L){ //初始化
L.MaxSize=InitSize;
L.data=new int[L.MaxSize];
L.length=0;
}
void Assign(Sqlist &L,int n) { //赋值函数
for(int i=0;i<n;i++){
cin>>L.data[i];
L.length++;
}
}
void Delete(Sqlist &L,int n,int s,int t){ //删除函数
if(s>=t||L.length==0){
cout<<"input false"<<endl;
return;
}
int k=0; //统计当前需删除的个数
for(int i=0;i<n;i++) {
if (L.data[i]>=s&&L.data[i]<=t) {
k++; //当前需删除的个数+1,顺序表的长度-1
L.length--;
}
else //将不需要删除的元素前移k位
L.data[i-k]=L.data[i];
}
}
void Output(Sqlist L){ //输出顺序表
for(int i=0;i<L.length;i++)
cout<<L.data[i]<<" ";
}
int main(){
int n,s,t;
cin>>n>>s>>t;
Sqlist R; //定义结构体
InitSqlist(R); //初始化顺序表
Assign(R,n); //顺序表赋值
Delete(R,n,s,t); //调用删除函数
Output(R); //调用输出函数
return 0;
}