--------顺序表的定义
线性表的顺序存储又称为顺序表。它是用一组地址连续的存储单元,依次存储线性表中的数据元素,
从而使得逻辑上相邻的两个元素在物理位置上也相邻。第 1 个元素存储在线性表的起始位置,第 i 个元素
元素的存储位置后面紧接着存储的是第 i + 1 个元素。因此,顺序表的特点是表中元素的逻辑顺序与其物理
顺序相同。
假设线性表 L 存储的起始位置为 LOC(A) ,sizeof(ElemType) 是每个数据元素所占用存储空间的大小,
则表 L 所对应的顺序存储如下图:
注意:线性表中的位序是从 1 开始的,而数组中元素的下标是从 0 开始的。
-----------------------------------------------------------------------------------------------------
假定线性表的元素类型为 ElemType ,线性表的顺序存储类型描述为:
# 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[InitSize] ;
注意:动态分配并不是链式存储,同样还是属于顺序存储结构,其物理结构没有变化,依然是
随机存取方式, 只是分配的空间大小可以在运行时决定。
顺序表最主要的特点是:随机访问,即通过首地址和元素序号可以再O(1) 时间内找到指定的元素。
顺序表的存储密度高,每个结点只存储数据元素。
顺序表逻辑上相邻的元素物理上也相邻,所以插入和删除操作需要移动大量元素。
-------------顺序表上基本操作的实现
这里仅给出顺序表的插入操作、删除操作和按值查找的算法。
(1)、插入操作
在顺序表 L 的第 i (1 <= i <= L.length+1) 个位置插入新元素 e 。如果 i 的输入不合法,则返回
false ,表示插入失败;否则,将顺序表的第 i 个元素以及其后的所有元素右移一个位置,腾出一个空位置
插入新元素 e ,顺序表长度增加 1 ,插入成功,返回 true 。
----------------------------------------------------------------------------------------------------------------------------------------
bool ListInsert( SqList &L , int i , ElemType e){
// 本算法实现将元素 e 插入到顺序表 L 中第 i 个位置
if ( i < 1 || i > L.length +1 ){ // 判断 i 的范围是否有效
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; // 在位置 i 处放入 e
L.length++; // 线性表的长度 加 1
return true;
}
----------------------------------------------------------------------------------------------------------------------------------------
注意:区别顺序表的位序和数组下标。理解为什么判断插入位置是否合法时 if 语句中用 length +1 ,
而移动元素的 for 语句只用 length ?
《
最好情况:在表尾插入(即 i = n + 1 ),元素后移动语句将不执行,时间复杂度为 O(1) 。
最坏情况:在表头插入(即 i = 1 ),元素后移动语句将执行 n 次,时间复杂度为 O( n ) 。
平均情况:假设 P(i)(P(i) = 1 / (n +1)) 是在第 i 个位置上插入一个结点的概率,则在长度为
n 的线性表中插入一个结点时所需移动结点的平均次数为:
因此,线性表插入算法的平均时间复杂度为 O( n )
》
(2)、删除操作
删除顺序表 L 中第 i (1 <= i <= L.length)个为位置的元素,成功则返回 true ,并将被删除的元素用引
用变量 e 返回,否则返回 false 。
----------------------------------------------------------------------------------------------------------------------------------------------
bool ListDelete( SqList &L , int i , int &e ) {
// 本算法实现删除顺序表 L 中第 i 个位置的元素
if( i < 1 || i > L.length ){ // 判断 i 的范围是否有效
return false ;
}
e = L.data[ i -1 ] ; // 将被删除的元素赋值给 e
for( int j = i ; j < L.length ; j++ ){ // 将第 i 个位置之后的元素前移
L.data[ j -1 ] = L.data[ j ]
}
L.length--; // 线性表的长度减 1
return true;
}
-----------------------------------------------------------------------------------------------------------------------------------------------
《
最好情况:删除表尾元素(即 i = n),无须移动元素,时间复杂度为 O(1)。
最坏情况:删除表头元素(即 i = 1),需要移动一个元素外的所有元素,时间复杂度为 O(n) 。
平均情况:假设 P(i) (P(i) = 1 / n) 是删除第 i 个位置上结点的概率,则在长度为 n 的线性表中
删除一个结点所需移动结点的平均次数为:
因此,线性表删除算法的平均时间复杂度为 O( n ) 。
》
(3)、按值查找(顺序查找)
在顺序表 L 中查找第一个元素值等于 e 的元素,并返回其位序。
----------------------------------------------------------------------------------------------------------------------------
int LocateElem( SqList L , ElemType e){
// 本算法实现查找顺序表中值为 e 的元素,如果查找成功,返回元素位序,否则返回 0
int i ;
for( i = 0 ; i < L.length ; i++){
if( L.data[ i ] == e){
return i +1 ; // 下标为 i 的元素值等于 e ,返回其位序 i + 1
}
return 0; //退出循环,说明查找失败
}
}
-----------------------------------------------------------------------------------------------------------------------------------
《
最好情况:查找的元素就在表头,仅需比较一次,时间复杂度为 O(1) 。
最坏情况:查找的元素在表尾(或不存在)时,需要比较 n 次,时间复杂度为 O(n)。
平均情况:假设 P(i) (P(i) = 1 / n )是查找的元素在第 i (1 <= i <= L.length)额个位置上的
概率,则在长度为 n 的线性表中查找值为 e 的元素所需比较的平均次数为:
因此,线性表按值查找算法的平均时间复杂度为 O(n) 。
》