线性表的顺序存储结构——顺序表

什么是线性表?
线性表简称表,是n(n>=0)个具有相同类型的数据元素的有限序列,线性表中数据元素的个数称为线性表的长度,长度为0的表称为空表。

什么是顺序表?
线性表的顺序存储结构称为顺序表
顺序表是用一段地址连续的存储单元依次存储线性表的数据元素,因为线性表中每个元素的类型相同,通常用一维数组来实现线性表,也就是把线性表中相邻的元素存在数组中相邻的位置(即用物理位置来表现元素间的关系)。

顺序表的必要属性:
1.存储空间的起始位置 。顺序表是连续存储,只要确定了存储顺序表的起始地址,就可以计算任何一个元素的存储地址。并且,计算任何一个元素的存储地址的时间是相等的(单个元素所占的空间*该元素的序号+起始位置),具有这一特点的存储结构也称为随机存取(时间性能O(1) )结构。
2.顺序表的容量(最大长度MaxSize)。用数组存储顺序表,就意味着要分配固定长度的数组空间,因此必须确定数组的长度,即存放线性表的数组空间的长度。
3.顺序表的当前长度(length)。因为在线性表中可以进行插入操作,则数组的长度就要大于当前线性表的长度。即需要知道顺序表的当前长度(length),以及最大长度(MaxSize)。

顺序表的存储要点:
1.分配一段地址连续的存储空间
2.依次存储线性表中的数据元素
3.表示逻辑关系不分配存储空间(最本质)(元素之间的位置关系即表示其逻辑关系)

顺序表的实现:

由于线性表的数据元素类型不确定,所有采用C++的模板机制。
对C++模板机制不太了解的可以看看我之前的-----》C++模板的概念 定义和使用

Seqlist.h:(顺序表类的声明)

const int MaxSize=100;  //100只是示例性的数据,可以根据实际问题具体定义
template <class T>      //定义模板类SeqList
class SeqList
{
public:
   SeqList( );       //无参构造函数
   SeqList(T a[], int n);       //有参构造函数
   ~SeqList();             //析构函数为空
   int 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();       //遍历线性表,按序号依次输出各元素
private:
   T data[MaxSize];      //存放数据元素的数组
   int length;            //线性表的长度
};

基本操作的算法:

1.构造函数
(1) 无参构造函数 SeqList( ):
创建一个空的顺序表,只需简单的将顺序表的长度length初始化为0。

template <class T>
SeqLsit<T>::SeqList()
{
	length=0;
}

(2) 有参构造函数 SeqList(T a[], int n) :
创建一个长度为n的顺序表,需要将给定的数组元素作为线性表的数据元素传入顺序表中,并将传入的元素个数作为顺序表的长度。

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;
}

2.求线性表的长度
int Length() 只需返回成员变量length的值

template <class T>
int SeqList<T>::Length()
{
	 return length;
}

3.查找操作:
(1) 按位查找
T Get(int i)取线性表的第i个元素:
顺序表中第i个元素存储在数组中下标为i-1的位置,所以,容易实现按位查找。该按位查找算法的时间复杂度为O(1)。

template <class T>
T SeqList<T>::Get(int i)
{
	if(i<1 && i>length) 
		throw"查找位置超出边界";
	else 
		return data[i-1];
}

(2) 按值查找
int Locate(T x) 求线性表中值为x的元素序号:
在顺序表中实现按值查找操作,需要对顺序表中的元素依次进行比较。如果查找成功,返回元素的序号(注意不是下标);如果查找不成功,返回查找失败的标准‘0’。

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;  //退出循环,说明查找失败
}

按值查找算法的问题规模是表长n,最好的情况是比较一次就行了,最坏情况是比较n次,假设数据是等概率分布,则平均比较表长的一半。所以,按值查找算法的平均时间性能是O(n)。

4.插入操作
void Insert(int i, T x) 在线性表中第i个位置插入值为x的元素:
其伪代码如下(注意需要考虑的情况):

伪代码:
1.如果表满了,则抛出上溢异常;
2.如果元素的插入位置不合理,则抛出位置异常;
3.将最后一个元素直至第i个元素分别向后移动一个位置;
4.将元素x填入位置i处;
5.表长加1;

C++描述如下:

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];   //注意第j个元素存在数组下标为j-1处
	data[i-1]=x;
	length++;
}

在第i(1<= i <= i+1)个位置上插入一个元素后移语句的执行次数为n-i+1,假设在表中任何位置上插入元素的机会是均等的,则平均后移语句的执行次数为n/2,算法的时间复杂度为O(n)。

5.顺序表删除算法
T Delete(int i) 删除线性表的第i个元素:
删除操作是将表的第i个元素删除,使长度为n的线性表变成长度为n-1的线性表,取出被删除元素后,必须从第i+1(下标为i)个元素开始移动,直至将最后一个元素前移为止。

伪代码:
1.如果表空,则抛出空表警告;
2.如果删除位置不合理,则抛出删除位置异常;
3.取出被删除元素;
4.将下标为i,i+1,...,n-1处的元素分别移到下标i-1,i,...,n-2处;
5.表长减1,返回被删元素值;

C++描述如下:

template<class T>
T SeqList<T>::Delete(int i)
{
	if(length==0)
		throw"表为空!";
	if(i<1||i>length)
		throw"位置异常";
	x=data[i-1];     //取出位置i的元素
	for(j=i;j<length;j++)
		data[j-1]=data[j];     //j是元素所在的数组下标
	length--;
	return x;
}

在顺序表上实现删除操作,等概率情况下,平均要移动表中一半的元素,算法的平均时间复杂度为O(n)。

6.遍历操作:
void PrintList() 按下标依次输出各元素:

template<class T>
void SeqList<T>::PrintList()
{
	for(int i=0;i<length;i++)
		cout<<data[i]<<endl;   //依次输出线性表的元素值
}

最后:
顺序表的优点:
1.无需为表示表中的元素之间的逻辑关系而增加额外的存储空间。
2.随机存取:可以快速的存取表中任一位置的元素。

顺序表的缺点:
1.插入和删除操作需要移动大量元素。
2.表的容量难以确定,表的容量难以扩充。
3.造成存储空间的碎片

参考至-----《数据结构(C++版)(第二版)》/王红梅,胡明,王涛编著.

猜你喜欢

转载自blog.csdn.net/qq_28840013/article/details/84980591