线性表:零个或多个数据元素的有限序列,由n(n>=0 )个数据特性相同的元素构成的有限序列;当n=0时,线性表为空表。
线性结构示意图:
对于非空的线性表或线性结构,其特点是:
- 存在唯一的一个被称作“第一个”的数据元素;
- 存在唯一一个被称作“最后一个”的数据元素;
- 除第一个之外,结构中的每个数据元素均只有一个前驱;
- 除最后一个之外,结构中的每个数据元素均只有一个后继。
线性表的抽象数据类型定义如下:
ADT List(线性表)
{
Data(数据)
{
数据对象:{a1,a2,……,an}; 每个元素的类型均为DataType。
数据关系:一对一的关系,每个元素有一个或零个前驱或后继。
}
Operation(基本操作)
{
InitList(&L): 初始化操作,建立一个空线性表L。
ListEmpty(L): 若线性表为空,返回true,否则返回false。
ClearList(&L): 将线性表L清空,表长为0。
GetElem(L,i,&e): 将线性表L中第i个元素的值赋给e。
LocateElem(L,e): 在线性表中查找与给定值e相等的元素,如果查找成功,返回
该元素在表中序号表示成功,否则返回0表示失败。
ListInsert(&L,i,e): 在线性表L中第i个位置插入新元素e,表长加1。
ListDelete(&L,i): 删除线性表L中第i个位置的元素,表长减1。
}
}
线性表的顺序存储表示:
线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素,逻辑上相邻的数据元素,其物理次序也是相邻的。如下图所示:
地址计算方法:假设线性表中每个元素需要占用c个存储单元,并以所占的第一个单元的存储地址作为数据元素的存储起始位置。则线性表中第i+1个数据元素与第i个数据元素的关系如下:
LOC() = LOC() + c
一般来说,线性表的第i个数据元素的存储位置为:
LOC()=LOC()+(i - 1) * c
如图所示:
由此,只要确定了存储线性表的起始位置,那么线性表中的任一元素我们都可以对其进行增、删、改的操作,所以线性表的顺序存储结构是一种随机存取的存储结构。
由于高级程序设计语音的数组类型也有随机存取的特性,因为通常用数组来描述数据结构中的顺序存储结构。
在此,由于线性表长度可变,且所需存储空间也随问题不同而不同,所以我们用动态分配一维数组来表示线性表。
开始之前我们规定一下预定义常量及类型:
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;
顺序表的伪码存储结构描述:(以下语言都为类C伪码,除具体实现代码以外)
#define MAXSIZE 100 //顺序表可达到的最大长度
typedef struct
{
EelmType *elem; //存储空间的基地址
int length; //当前长度
}Sqlist; //顺序表的结构类型为Sqlist
顺序表中的基本操作实现:
1.顺序表的初始化
【算法步骤】
- 为顺序表L分配一个预定义大小为MAXSIZE的数组空间
- 将表的当前长度设为0
Status InitList(Sqlist &L)
{
L.elem=new ElemType[MAXSIZE]; //初始分配一个大小为MAXSIZE的空间
if(!L.elem) exit(OVERFLOW); //分配失败退出
L.length=0; //空表长度为0
return OK;
}
2.顺序表的取值 O(1)
【算法步骤】
- 判断指定的位置序号i值是否合理(1<= i <= L.length),若不合理,则返回ERROR
- 若i值合理,则将第i个数据元素L.elem[i-1]赋给参数e,通过e返回第i个数据元素的传值
Status GetElem(Sqlist L,int i,ElemType &e)
{
if(i<1||i>L.length) //判断i是否合理
return ERROR;
e=L.elem[i-1]; //elem[i-1]存储第i个元素
return OK;
}
3.顺序表的查找 O(n)
【算法步骤】。
- 从第一个元素开始依次和e相比较,查找顺序表中第一个与e相等的元素。查找成功返回位置序号,否则,返回0
- 若查遍整个顺序表在表中的序号都没有找到,则查找失败,返回0
int LocateElem(Sqlist L,ElemType e)
{
for(int i=0;i<L.length;i++) //遍历整个顺序表
if(L.elem[i]==e) return i+1; //如果查到,返回i+1
return 0; //没有查到,返回0
}
4.顺序表的插入 O(n)
【算法步骤】
- 判断插入位置是否合法(1 <= i <= n+1),若不合法则返回ERROR
- 判断顺序表是否已满,若满返回ERROR
- 将第n个至第i个位置的元素依次向后移动一个位置,空出第i个位置(i=n+1时无需移动)
- 将要插入的新元素e放入第i个位置
- 表长加1
Status ListInsert(Sqlist &L,int i,ElemType e)
{
if(i<1||i>L.length+1) //i不合法
return ERROR;
if(L.length==MAXSIZE) //表满
return ERROR;
for(int j=L.length-1;j>=i-1;j--)
L.elem[j+1]=L.elem[j]; //插入位置及之后元素后移
L.elem[i-1]=e; //新元素赋值
L.length++; //表长加一
return OK;
}
5.顺序表的删除 O(n)
【算法步骤】
- 判断位置是否合法(1 <= i <= n),若不合法返回ERROR
- 将第i+1个至第n个元素依次向前移动一个位置(i=n时,无需移动)
- 表长减1
Status ListDelete(Sqlist &L,int i)
{
if(i<1||i>L.length+1) //i不合法
return ERROR;
for(int j=i;j<L.length;j++)
L.elem[j-1]=L.elem[j]; //被删 元素前移
L.length--; //表长减1
return OK;
}
6.判断顺序表是否为空 O(1)
【算法步骤】
- 判断表长是否等于0,如果等于0,则返回OK;反之 ERROR
bool ListEmpty(Sqlist L)
{
if(L.length==0)
return OK;
return ERROR;
}
7.将线性表清空 O(1)
【算法步骤】
- 将表长赋值为0
void ClearList(Sqlist &L)
{
L.length=0;
}
线性表的顺序存储结构的优缺点:
优点:
- 无须为表示中元素之间的逻辑关系而增加额外的存储空间。
- 可以快速的存取表中任一位置的元素。
缺点:
- 插入和删除操作需要后移大量数据元素。
- 当线性表长度未知时,难以确定存储空间的容量。
- 若存储空间开的大,会造成大量的空闲空间。
简单实现顺序表: https://blog.csdn.net/lesileqin/article/details/88078923
本博客内容借鉴于:
①《数据结构》 作者:严蔚敏
②《大话数据结构》 作者:程杰