CHAPTER 2 线性表
算法题命题重点,实现容易代码量少,要求最优性能。
2.2 线性表的顺序表示
定义
特点:表中元素逻辑顺序及其物理顺序相同
假定元素类型为ElemType,线性表顺序存储类型描述为:
#define MaxSize 50
typedef struct{
ElemType data[MaxSize]; // 顺序表元素
int length ; // 顺序表长度
}SqList;
这是静态分配,同样可以动态分配:
#define InitSize 50
typedef struct{
ElemType *data; // 指示动态分配数组的指针
int MaxSize, length ; // 数组最大容量和当前个数
}SeqList;
C++ 初始动态分配的语句:L.data = new ElemType[InitSize] ;
注意:动态分配同样属于顺序存储结构,而非链式存储,依然是随机存储方式,只是分配的空间大小可以在运行时动态决定。
基本操作实现
- 插入操作 O(n)
bool ListInsert(SqList &L, int i, ElemType e){
if(i < 1 || i > L.length + 1) return false ;
if(L.length >= MaxSize) return false ;
for(int j = L.length ; j >= i ; j --){
L.data[j] = L.data[j - 1] ;
}
L.data[i - 1] = e ; //第 i 个元素下标为 i - 1
L.length ++ ;
return true ;
}
e 插到第 i 个元素的位置。
- 删除操作 O(n)
bool(SqList& L, int i, ElemType e){
if(i < 1 || i > L.length) return false ;
e = L.data[i - 1] ;
for(int j = i ; j < L.length ; j ++){
L.data[j - 1] = L.data[j] ;
}
L.length -- ;
return true ;
}
删除第 i 个位置的元素,并返回 e 。
- 按值查找
int Locate(SqList& L, ElemType e){
int i ;
for(int i = 0 ; i < L.length ; i ++){
if(L.data[i] == e) return i + 1 ;
}
return 0 ;
}
返回第一个值为 e 的元素元素下标。
习题
单选
Q:线性表的顺序存储结构是一种随机存取的存储结构。
存取方式指的是读写方式。
01
- 从顺序表中删除具有最小值的元素(假设唯一)并由函数返回被删元素的值。空出的位置由最后一个元素填补,若空,则显示错误信息并退出。
bool FindMinDel(SqList& L, ElemType e){ // 01
if(L.length == 0) return false ;
e = L.data[0]; int index = 0 ;
for(int i = 1 ; i < L.length ; i ++){
if(L.data[i] < e) {
index = i ;
e = L.data[i] ;
}
}
L.data[index] = L.data[length - 1] ;
L.length -- ;
return true ;
}
02
- 将顺序表L所有元素逆置,要求算法空间复杂度O(1)。
void SwapAll(SqList& L){
int l = 0 , r = L.length - 1 ;
while(l < r){ //swap()
ElemType tmp = L.data[l] ;
L.data[l] = L.data[r] ;
L.data[r] = tmp ;
l ++ ; r -- ;
}
return ;
}
双指针,或者swap(L.data[i] , L.data[L.length - i - 1])
。
03
- 删除线性表中所有值为x的数据元素,要求时O(n),空O(1)
void (SqList& L, ElemType x){ // visit unx
int k = 0 ;
for(int i = 0 ; i < L.length ; i ++){
if(L.data[i] != x){
L.data[k] = L.data[i] ;
k ++ ;
}
}
L.length = k ;
}
法一,记录不是x的数个数 k ,每次把第 i 个移到第 k 个位置。有点妙。
void (SqList& L, ElemType x){ // visit x
int k = 0 ;
for(int i = 0 ; i < L.length ; i ++){
if(L.data[i] == x) k ++ ;
else L.data[i - k] = L.data[i] ;
}
L.length -= k ;
}
法二,记录x的个数k,不是x的往前挪k个位置。
04
- 从有序顺序表中删除其值在给定值 s,t 之间(s < t)的所有元素,若s,t不合理或表空,返回错误信息并退出运行。
bool Delst(SqList& L, ElemType s, ElemType t){
if(s >= t || L.length == 0) return false ;
for(int i = 0 ; i < L.length ; i ++){
int k = 0 ;
if(L.data[i] < s || L.data[i] > t){
L.data[k] = L.data[i] ;
k ++ ;
}
}
L.length = k ;
return true ;
}
由于是有序顺序表,s 到 t 是一整段,并不需要用到 03 的方法。
bool Delst(SqList& L, ElemType s, ElemType t){
if(s >= t || L.length == 0) return false ;
int index , num = 0;
for(int i = 0 ; i < L.length ; i ++){
if(L.data[i] >= s){
index = i ; break ;
}
}
for(int i = indexs ; i < L.length ; i ++){
if(L.data[i] > t){
L.data[index] = L.data[i] ;
index ++ ;
num ++ ;
}
}
L.length -= num ;
return true ;
}
找到第一个和最后一个s,t间的数,后继向前挪。
虽然答案用的这种方法,但感觉不如 03 好使,反正都是O(n)。
06
- 从有序顺序表中删除所有其值重复的元素
bool DelRepetion(SqList& L){
if(L.length == 0) return false ;
int k = 1 ;
for(int i = 1 ; i < L.length() ; i ++){
if(L.data[i] != L.data[i - 1]){
L.data[k] = L.data[i] ;
k ++ ;
}
}
L.length = k ;
return true ;
}
07
- 将两个有序顺序表合成一个新的有序顺序表
void Bin(SqList a, SqList b, SqList& L){
int i = 0 , j = 0, k = 0 ;
while(i < a.length || j < b.length){
if (i < a.length && j < b.length){
if (a.data[i] < b.data[j]){
L.data[k] = a.data[i] ;
i ++ ; k ++ ;
}
else {
L.data[k] = b.data[j] ;
j ++ ; k ++ ;
}
}
else if (i < a.length){
L.data[k] = a.data[i] ;
i ++ ; k ++ ;
}
else (j < b.length){
L.data[k] = b.data[j] ;
j ++ ; k ++ ;
}
}
L.length = k ;
}
08
- 已知在 A[m,n] 中依次存放两个线性表 a[m] b[n] ,编写一个函数,互换ab位置