计算机基础数据结构讲解第五篇-顺序表
本篇及下一篇文章介绍线性表,包括线性表的定义及顺序表和链表的表示和方法。有关b树的补充等到之后进行介绍。
一:线性表的定义和基本操作
线性表是具有相同数据类型数据元素的有限序列集合,当线性表内没有元素时,是一个空表用a(i)代表第i个数据元素,第一个元素为表头,最后一个元素为表尾。除第一个元素外,每个元素都有一个直接前驱;除最后一个元素外,每个元素都有一个直接后继。
线性表是一个逻辑结构,表示元素之间一一对应的关系;而顺序表和链式表是指存储结构。
线性表的基本操作是最基本的操作,包括:
InitList(&L):初始化一个空的线性表。
Length(L):求表长。
LocateElem(L,e):在表中查找给定关键字值的元素。
GetElem(L,i):在表中查找第i个位置的元素的值。
ListInsert(&L,i,e):在表中的第i个位置插入元素e。
ListDelete(&L,i,&e):删除表中第i个位置元素,并用e返回。
PrintList(L):输出线性表中的所有元素值。
Empty(L):判断线性表是否为空。
DestoryList(&L):销毁线性表,并释放线性表所占用的内存空间。
这里的"&"表示的是c++里面的引用调用,传入指针变量的时候要对传入的指针进行改变,则会用到指针变量的引用型。在C语言的采用指针的指针也可以达到同样的效果。
二:线性表的顺序存储
1.定义
线性表的顺序存储又称顺序表,用一组地址连续的存储单元依次存储线性表的数据元素,使逻辑上相邻的元素物理位置上也相邻。i为元素a(i)的位序,特点是表中的逻辑顺序与其物理顺序相同。
有关顺序表的基本模型和结构这里就不详细介绍了,主要是顺序表是依靠数组实现的,要注意的是:线性表中元素的位序是从1开始的,而数组中元素的位序是从0开始的。
2.顺序存储数据类型
由于顺序表是由数组实现的,我们知道一维数组可以是静态分配的,也可以是动态分配的。静态分配因为空间和大小有限,一旦占满,再加入新的数据将会产生溢出,导致程序崩溃;动态分配,数组空间是在需要时通过动态存储语句分配,可以不断开辟新的存储空间,扩充存储空间,所以更高效。
顺序存储数据类型实现的代码如下:
// 顺序表的静态存储
#define MaxSize 50 //顺序表最大长度
typedef struct{
ElemType data[MaxSize]; //顺序表数据元素
int length; //顺序表当前长度
}SqList; //顺序表结构体类型定义
//顺序表的动态存储
#define InitSize 100 //表长度的初始定义
typedef struct{
ElemType *data; //动态分配数组指针
int MaxSize;length; //数组最大容量和当前个数
}SeqList; //顺序表结构体类型定义
C语言初始动态分配语句是:
L.data= (ElemType)malloc(sizeof(ElemType)InitSize);
C++的动态分配语句是:
L.data = new ElemType(InitList);
3.顺序表基本操作的实现(代码写的是静态存储,动态存储类似)
(1)插入操作
在顺序表L的第i个位置插入新元素e。如果i的输入不合法,则返回false,表示插入失败;否则将原顺序表的第i个元素及其后面的所有元素右移一个位置,腾出一个空间插入新元素e。顺序表的长度加一,插入成功,返回true。插入位置范围从1到L.length+1,代码如下:
bool ListInsert(SqList &L,int i,ElemType e){
if(i < 1|| i > Length + 1)
return false;
if(L.length >= MaxSize) //当前存储空间已满,不能插入
return false;
for(int j = L.length;j >= i;j--){ //将i及之后的元素后移
L.data[j] = L.data[j-1];
}
L.data[i-1] = e; //数组从0开始
L.length++;
return true;
}
插入操作的最好情况是在表尾插,后移操作不再进行;最坏情况是在表头插,后移n次。而平均情况下,插入的平均时间复杂度是O(n)。
(2)删除操作
删除表中的第i个位置的元素,成功返回true,并将被删除的元素用引用变量e返回,否则返回false,也需要移动元素位置。删除位置范围从1到L.length,代码如下:
bool ListDelete(SqList &L,int i,ElemType &e){
if(i < 1|| i > Length)
return false;
e = L.data[i-1];
for(int j = i;j < L.length;j++){ //将i及之后的元素前移
L.data[j-1] = L.data[j];
}
L.length--;
return true;
}
插入操作的最好情况是在表尾插,前移操作不再进行;最坏情况是在表头插,前移n-1个数据元素。而平均情况下,删除的平均时间复杂度是O(n)。
(3)简单的按值查找
在顺序表中查找第一个元素值等于e的元素,并返回其位序。代码如下:
int LocateElem(SqList L,ElemType e){
int i;
for(i = 0;i < L.length;i++)
if(L.data[i] == e)
return i + 1; //位序从一开始
return 0;
}
最好情况在表头比较一次,在表尾或不存在比较n次,按值查找的平均时间复杂度为O(n)。
4.顺序表的特点
优点:随机访问,在O(1)的时间内找到指定的元素。存储密度高,每个结点只存储数据元素。
缺点:插入和删除操作需要移动大量元素。