2.1线性表的逻辑结构
- 线性表的定义:
是零个或多个具有相同类型的数据元素的有限序列。
数据元素的个数定义为线性表的长度。
长度等于零时称为空表,一个非空表通常记为
L = ( a 1 , a 2 ,……, a n )
其中, a i ( 1 ≤ i ≤ n )称为数据元素,
下标 i 表示该元素在线性表中的位置或序号, 称元素 a i 位于表的第 i 个位置,或称 a i 是表中的第 i 个元素。
2.2线性表的顺序存储结构及其实现
- 2.2.1 线性表的顺序存储结构——顺序表
特点:线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素,
作用:线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系。
顺序存储的实现:一维数组存储顺序表中的数据
顺序表支持数据元素的随机访问
顺序表的实现:
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;}
有参构造函数:
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;
}
插入操作:
线性表的插入运算是指在表的第i (1≤i≤n+1)个位置,插入一个新元素e,使长度为n的线性表 (e1,…,ei-1,ei,…,en) 变成长度为n+1的线性表(e1,…, ei-1,e,ei,…,en)。
- 插入算法:
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++;
}
插入算法复杂:
问题规模:n
最好情况:在最后插入,不需要移动元素,时间复杂性为O(1);
最坏情况:在开头插入,需要移动n个数据,O(n)
平均时间复杂度:
元素总个数为n,各个位置插入的概率相等为p=1/(n+1 )
平均移动元素次数为
时间复杂性为O(n)
删除操作:
线性表的删除运算是指将表的第i(1≤i≤n)个元素删去,使长度为n的线性表(e1,…, ei-1,ei,ei+1,…,en)变成长度为n-1的线性表(e1,…, ei-1, ei+1,…,en)。
- 删除算法;
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;
}
删除算法的复杂性分析
问题规模:n
最好情况:在最后删除,不需要移动元素,时间复杂性为O(1);
最坏情况:在开头删除,需要移动n-1个数据,O(n)
平均复杂性:
元素总个数为n,各个位置删除的概率为p=1/n
平均移动元素次数为
时间复杂性为O(n)
查找操作:
两种查找方法
按位置查找,即查找指定位置上的元素
按值查找,即查找指定的值在顺序表中的位置
按位查找:
template <class T>
T SeqList<T>::Get(int i)
{
if (i<1 && i>length) throw "查找位置非法";
else return data[i-1];
}
按位查找算法的时间复杂度为 O ( 1 ) 。
按值查找:
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; //退出循环,说明查找失败
}
如果顺序表的第一个元素恰好就是 x ,算法只要比较一次就行了,这是最好情况;
如果顺序表的最后一个元素是 x ,算法就要比较 n 个元素,这是最坏情况;
平均情况下,假设数据是等概率分布,则平均要比较 n /2 个元素。所以,按值查找算法的平均时间性能是 O ( n ) 。
顺序表特点:
- 优点:
(1) 无需为表示结点间的逻辑关系而增加额外的存储空间(因为逻辑上相邻的元素其存储的物理位置也是相邻的);
(2) 可方便地随机存取表中的任一元素。 - 缺点:
(1)插入或删除运算不方便,
除表尾的位置外,在表的其它位置上进行插入或删除操作都必须移动大量的结点,其效率较低;
(2) 由于顺序表要求占用连续的存储空间,存储分配只能预先进行静态分配,因此当表长变化较大时,难以确定合适的存储规模。