一、线性表的逻辑结构
1.定义
是零个或多个具有相同类型的数据元素的有限序列。
数据元素的个数定义为线性表的 长度 ,长度等于零时称为空表
一个非空表通常记为 L = ( a 1 , a 2 ,……, a n ) 其中, a i ( 1 ≤ i ≤ n )称为数据元素
下标 i 表示该元素在线性表中的位置或序号, 称元素 a i 位于表的第 i 个位置,或称 a i 是表中的第 i 个元素。
2.线性表的抽象数据类型定义
ADT List
Data
线性表中的数据元素具有相同类型,相邻元素具有前驱和后继关系
Operation
InitList
前置条件:线性表不存在
输入:无
功能:线性表的初始化
输出: 无
后置条件:一个空的线性表
DestroyList
前置条件:线性表已存在
输入:无
功能:销毁线性表
输出:无
后置条件:释放线性表所占用的存储空间
Length
前置条件:线性表已存在
输入:无
功能:求线性表的长度
输出: 线性表中数据元素的个数
后置条件:线性表不变
Get
前置条件:线性表已存在
输入:元素的序号 i
功能:在线性表中取序号为 i 的数据元素
输出:如果序号合法,返回序号为 i 的元素值,否则抛出异常
后置条件:线性表不变
Locate
前置条件:线性表已存在
输入:数据元素 x
功能:在线性表中查找值等于 x 的元素
输出:如果查找成功,返回元素 x 在表中的序号,否则返回 0
后置条件:线性表不变
Insert
前置条件:线性表已存在
输入:插入位置 i ;待插元素 x
功能:在线性表的第 i 个位置处插入一个新元素 x
输出:若插入不成功,抛出异常
后置条件:若插入成功,表中增加了一个新元素
Delete
前置条件:线性表已存在
输入:删除位置 i
功能:删除线性表中的第 i 个元素
输出:若删除成功,返回被删元素,否则抛出异常
后置条件:若删除成功,表中减少了一个元素
Empty
前置条件:线性表已存在
输入:无
功能:判断线性表是否为空表
输出:若是空表,返回 1 ,否则返回 0
后置条件:线性表不变
PrintList
前置条件:线性表已存在
输入:无
功能:按位置的先后次序依次输出线性表中的元素
输出:线性表的各个数据元素
后置条件:线性表不变
说明:
⑴ 对于不同的应用,线性表的基本操作是不同的。并非任何时候都需要以上操作,有些问题只需要一部分上述操作;
⑵ 上述操作是最基本的,对于实际问题中涉及的关于表的更复杂的操作,可以用这些基本操作的组合来实现;
⑶ 对于不同的应用,上述操作的接口可能不同,例如删除操作,若要求删除表中值为 x 的元素,则 Delete 操作的输入参数就不能是位置而应该是元素值。*
二、线性表的顺序存储结构及其实现
顺序表
(1)特点:线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素
(2)作用:线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系。
(3)顺序存储的实现:一维数组存储顺序表中的数据
const int Maxsize=100;
template <class T>
class SeqList{
private:
T data[MaxSize]; // 存放数据元素的数组
int length; // 线性表的长度
public:
SeqList ( ) ;// 无参构造函数
SeqList ( T a[ ], int n ) ; // 有参构造函数
~SeqList( ) { } // 析构函数为空
int Length ( ) {return length;} // 求线性表的长度
T Get ( int i ); // 按位查找,取线性表的第 i 个元素
int Locate ( T x ) ; // 按值查找,求线性表中值为 x 的元素序号
void Insert ( int i, T x ) ; // 在线性表中第 i 个位置插入值为 x 的元素
T Delete ( int i ) ; // 删除线性表的第 i 个元素
void PrintList ( ) ; // 遍历线性表,按序号依次输出各元素
};
定义了两个构造函数:
无参构造函数(构造一个空的顺序表)
SeqList ( ) {length=0;}
构造一个非空的顺序表
SeqList ( T a[ ], int n ) ; // 有参构造函数
有参构造函数的实现:
将长度为n的一维数组中的元素依次传入到data中。
template <class T>
SeqList<T>:: SeqList(T a[], int n)
{
if (n>MaxSize) throw "参数非法";
for (int i=0; i<n; i++)
data[i]=a[i];
length=n;
}
插入:(时间复杂度 O(n) )
1 如果顺序表已满,抛出上溢异常
2 如果元素插入位置不存在,抛出位置异常
3 将最后一个元素至第i个元素(i为插入位置)向后移动一个位置
4 将元素插入到i位置
5 将顺序表的长度增1
template <class T>
void SeqList<T>::Insert(int i, T x){
int j;
if (length>=MaxSize) throw "上溢";
if (i<1 || i>length+1) throw "位置";
for (j=length; j>=i; j--)
data[j]=data[j-1];
data[i-1]=x;
length++;
}
删除:
1 如果顺序表已空,抛出下溢异常
2 如果元素删除位置不存在,抛出位置异常
3 取出被删除的元素
4 将下标为i,i+1…n-1的元素一次移到i-1,i,…n-2的位置
5 将顺序表的长度减1,返回被删除的元素
template <class T>
T SeqList<T>::Delete(int i){
int j;
T x;
if (length==0) throw "下溢";
if (i<1 || i>length) throw "位置";
x=data[i-1];
for (j=i; j<length; j++)
data[j-1]=data[j];
length--;
return x;
}
查找:
1.按位置查找(时间复杂度 O(1) )
template <class T>
T SeqList<T>::Get(int i)
{
if (i<1 && i>length) throw "查找位置非法";
else return data[i-1];
}
2.按值查找(时间复杂度 O(n))
template <class T>
int SeqList<T>::Locate(T x){
for (int i=0; i<length; i++)
if (data[i]==x)
return i+1 ; //下标为i的元素等于x,返回其序号i+1
return 0; //退出循环,说明查找失败
}
顺序表的特点
优点:
(1) 无需为表示结点间的逻辑关系而增加额外的存储空间(因为逻辑上相邻的元素其存储的物理位置也是相邻的)
(2) 可方便地随机存取表中的任一元素。
缺点:
(1)插入或删除运算不方便,除表尾的位置外,在表的其它位置上进行插入或删除操作都必须移动大量的结点,其效率较低
(2)由于顺序表要求占用连续的存储空间,存储分配只能预先进行静态分配,因此当表长变化较大时,难以确定合适的存储规模