知识点
- 线性表:具有相同数据类型的n( n ≥ 0 n\geq0 n≥0)个数据元素的有限序列。除第一个元素外,每个元素只有一个直接前驱;除最后一个元素外,每个元素只有一个直接后继;存在唯一的第一元素和最后元素。
- 线性表的基本操作:
(1) 初始化initList(&L)
(2) 求表长length(L)
(3) 按值查找操作locateElem(L,e)
(4) 按位查找操作getElem(L,i)
(5) 插入操作listInsert(&L,i,e)
(6) 删除操作listDelete(&L,i,&e)
(7) 输出操作print(L)
(8) 判空操作empty(L)
(9) 销毁操作destoryList(&L) - 顺序表(Sequential List):顺序存储的线性表
- 顺序表的结构:
数组下标 | 顺序表 | 内存地址 |
---|---|---|
0 | a 1 a_{1} a1 | loc(A) |
1 | a 2 a_{2} a2 | loc(A)+sizeof(ElemType) |
… | … | … |
i-1 | a i a_{i} ai | loc(A)+sizeof(ElemType)*(i-1) |
- 创建顺序表的方法
#define SUCCESS 1
#define ERROR -1
#define Maxsize 50
typedef ElemType int;
typedef struct{
ElemType data[Maxsize];//静态分配
int length;//当前表的长度,没有数据元素时是0
}sqList;
#define initSize 100
typedef struct{
ElemType *data;//动态分配
int Maxsize, length;//最大长度和当前长度
}sqList;
L.data = (ElemType*)malloc(sizeof(ElemType)*initSize);
- 顺序表的特点
(1)存取方式:随机存取(通过首地址或者序号可以在O(1) 内找到指定元素)
(2)存储密度:高(每个结点只存储数据元素)
(3)物理位置:与逻辑位置相符,需要一段连续的存储空间,不利于扩展
(4)操作:在删除、插入操作时需要移动大量元素 - 顺序表的插入
//i取0~L.length,即物理存储上的下标,非第几个
void listInsert(sqList &L,int i,ElemType e)
{
if(i<0 || i>L.length)//如果插入位置非法(可插在末尾)
return ERROR;
for(int j = L.length;j > i;j--)//移动数据
{
L.data[j] = L.data[j-1];
}
L.data[i] = e;
L.length ++;
return SUCCESS;
}
/*
*最好情况:在最后插入,不移动元素
*最坏情况:在第一个位置插入,移动n个元素
*所有情况的移动次数之和:0+1+...+n=n(n+1)/2
*一共有n+1种情况,除以n+1,因此平均时间复杂度为T(n)=O(n/2)=O(n)
*/
- 顺序表的删除
void listDelete(sqList &L, int i , ElemType &e)
{
if(i<0 || i > L.length-1)
return ERROR;
e = L.data[i];
for(int j = i ; j < L.length-1 ; j++)
{
L.data[j] = L.data[j+1];
}
L.length --;
return SUCCESS;
}
/*
*最好情况:删除最后一个,不移动元素
*最坏情况:删除第一个元素,移动n-1个元素
*所有情况的移动次数之和:0+1+...+n-1=n(n-1)/2
*一共有n种情况,除以n,因此平均时间复杂度为T(n)=O((n-1)/2)=O(n)
*/
- 顺序表的按值查找
int locateElem(sqList L, ElemType e)
{
for(int i = 0;i < L.length;i++)
{
if(L.data[i] == e)
return i;
}
return ERROR;
}
- 顺序表的按位查找
ElemType getElem(sqList L, int i)
{
if(i < 0 || i > L.length-1)
retrun ERROR;
return L.data[i];
}
11.扩展(合并两个有序顺序表)
int Merge(sqList A, sqList B, sqList &C)
{
if(A.length + B.length > Maxsize)
return ERROR;
int ai = 0, bi = 0, ci = 0;
while(ai < A.length && bi < B.length)
{
if(A.data[ai] > B.data[bi])
{
C.data[ci++] = B.data[bi++];
}
else
{
C.data[ci++] = A.data[ai++];
}
}
while(ai < A.length)
{
C.data[ci++] = A.data[ai++];
}
while(bi < B.length)
{
C.data[ci++] = B.data[bi++];
}
C.length = A.length + B.length;
return SUCCESS;
}
练习题
- (判断)线性表采用顺序存储结构表示时,必须占用一段连续的空间(✔)
- (单选)如果一个顺序表中第一个元素的存储地址是1000,每个元素占用4个存储单元,那么第6个元素的存储地址是(A)
A 、 1020 B 、 1010 C 、 1016 D 、 1024 A、1020\qquad B、1010\qquad C、1016\qquad D、1024 A、1020B、1010C、1016D、1024 - (单选)当需要随机查找线性表的元素时,宜采用(C)作为存储结构
A 、双向链表 B 、循环链表 C 、顺序表 D 、单链表 A、双向链表\qquad B、循环链表\qquad C、顺序表\qquad D、单链表 A、双向链表B、循环链表C、顺序表D、单链表 - (单选)在长度为n的顺序表的第i个位置插入一个元素(
0
≤
i
≤
n
0\leq i \leq n
0≤i≤n),元素的移动次数为(A)
A 、 n − i + 1 B 、 n − i C 、 i D 、 i − 1 A、n-i+1\qquad B、n-i\qquad C、i\qquad D、i-1 A、n−i+1B、n−iC、iD、i−1 - (单选)设顺序线性表中有n个数据元素,则删除表中第i个元素需要移动(A)个元素
A 、 n − i B 、 n − i − 1 C 、 n − i + 1 D 、 i A、n-i\qquad B、n-i-1\qquad C、n-i+1\qquad D、i A、n−iB、n−i−1C、n−i+1D、i - 对于顺序存储的线性表,访问结点,增加、删除的时间复杂度为(C)
A 、 O ( n ) O ( n ) B 、 O ( n ) O ( 1 ) C 、 O ( 1 ) O ( n ) D 、 O ( 1 ) O ( 1 ) A、O(n)O(n)\qquad B、O(n)O(1)\qquad C、O(1)O(n)\qquad D、O(1)O(1) A、O(n)O(n)B、O(n)O(1)C、O(1)O(n)D、O(1)O(1) - (判断)线性表的特点是每一个元素都有一个前驱和后继(✘)
- (单选)线性表的顺序存储结构是一种(A)的存储结构
A 、随机存取 B 、顺序存取 C 、索引存取 D 、散列存取 A、随机存取\qquad B、顺序存取\qquad C、索引存取\qquad D、散列存取 A、随机存取B、顺序存取C、索引存取D、散列存取 - (单选)下列(A)是顺序存储的优点
A 、存储密度大 B 、插入运算方便 A、存储密度大\qquad B、插入运算方便 A、存储密度大B、插入运算方便
C 、删除运算方便 D 、需要大片连续的存储空间 C、删除运算方便\qquad D、需要大片连续的存储空间 C、删除运算方便D、需要大片连续的存储空间 - (单选)两个有序顺序表分别具有n个元素和m个元素,且n<m,则将其合并成一个有序表,其最少的比较次数是(A)
A 、 n B 、 m C 、 n − 1 D 、 m + n A、n\qquad B、m\qquad C、n-1\qquad D、m+n A、nB、mC、n−1D、m+n - (判断)删除顺序表中第一个元素的时间复杂度是O(n)(✔)
- (单选)在n个结点的顺序表中,算法的时间复杂度是O(1)的是(A)
A、访问第i个结点和求第i个结点的直接前驱
B、在第i个结点后插入一个节点
C、删除第i个结点
D、将n个结点从小到大排序 - (单选)下面哪一个不是线性表的特性(D)
A、除第一个元素之外,每个元素都有前驱
B、除最后一个元素外,每个元素都有后继
C、线性表是数据元素的有限序列
D、线性表的长度时n,并且n不等于0 - (填空)二维数组A[10][20]按优先顺序存储,每个元素占四个存储单元,A[1][1]的存储地址是1000,A[5][6]的存储地址是(1340)
- (编程)已知长度为n的线性表采用顺序存储结构,写一个算法,删除线性表中所有值为x的元素。
//方法一:使用k记录等于x的个数
void del(sqList &L, ElemType 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 = L.length-k;
}
//方法二:使用k记录不等于x的个数
void del(sqList &L, ElemType x)
{
int k = 0;
for(int i = 0; i < L.length ; i++)
{
if(L.data[i] != x)
{
k++;
}
L.data[k] = L.data[i];
}
L.length = k;
}
- (编程)设计一个高效算法,将顺序表L所有元素逆置
int reverse(sqList &L)
{
int head = 0, tail = L.length-1;
while(head <tail)
{
ElemType temp = L.data[head];
L.data[head] = L.data[tail];
L.data[tail] = temp;
head++;
tail--;
}
return SUCCESS;
}