2.1顺序表
顺序表的定义和特点
线性表的存储方式有多种,有基于数组的存储表示、基于链表的存储表示、散列的存储表示,其中顺序表是线性表基于数组的存储表示。
其用一段地址连续的存储单元,依次存储线性表中的数据元素。
其特点有
- 各个表项的逻辑顺序与物理顺序一致。
- 对顺序表中的所有表项,可以顺序访问,也可以随机访问。
顺序表的类定义
顺序表可以用C++的一维数组来实现,C++的一维数组是可以静态分配,也可以动态分配的。在传统的C语言中可用静态、动态方式描述顺序表的存储。
为保证程序的灵活性,本例采用动态方式定义顺序表。用C++的描述顺序表的类声明及部分操作如下。在该定义中,利用了数组作为顺序表的存储结构,被封装在类的私有域中。
#include<iostream.h>
#include<stdlib.h>
#include "linerList.h" //将上节定义的顺序表模板类作为基类并加入头文件
const int defaultsize=100;
template <class T>
class SeqList:public LinearList<T>
{
protected:
T *data; //**顺序表存储数组**,“T”类型,根据对象数据类型而变化以实现多态
int MaxSize; //最大允许长度
int last; //当前最后元素下标
void reSize(int newSize);
public:
SeqList ( int sz= defaultSize );//构造函数
SeqList(SeqList<T>& L);//构造函数,复制线性表
~SeqList ( )
{
delete [ ] data;
}
int Size()const
{
return maxSize;
}
int Length ( ) const
{
return last+1;
}
int Search ( T& x ) const; //查找
int Locate ( int i ) const; //定位
bool getData(int i,T& x)const
{
if(i>0&&i<=last+1)
{
x=data[i-1];
return true;
}
else
return false;
}
void setData (int i, T& x)
{
if(i>0 && i<=last+1)
{
data[i-1]=x;
}
}
int Insert (int i, T & x); //插入
int Remove (int i, T & x ); //删除
bool IsEmpty ( )
{
return (last ==-1)?true:false;
}
bool IsFull ( )
{
return (last == MaxSize-1)?true:false;
}
void input();
void output();
SeqList<T> operator=(SeqList<T>& L);
};
const成员函数的意义
注意在搜索和定位函数中const起保护作用,表示该成员函数不能改变对象的数据的值。且const成员函数不能调用非const成员函数。
顺序表的主要操作实现
SeqList
构造函数
template <class T>
SeqList<T> :: SeqList ( int sz ) { //传递的参数为表的长度
if ( sz > 0 ) {
MaxSize = sz; last = -1;
data = new T [MaxSize]; //用new创建动态数组
if ( data == NULL ) {
cerr<<"存储分配失败!"<<endl;exit(1);
}
}
}
复制构造函数
template <class T>
SeqList<T> :: SeqList(SeqList<T>& L)//传递参数为要复制的表
{
maxSize=L.Size();
last=L.Length()-1;
T value;
data=new T[maxSize];
if ( data == NULL )
{
cerr<<"存储分配失败!"<<endl;
exit(1);
}
for(int i=1; i<=last+1; i++)
{
L.getData(i,value);
data[i-1]=value;
}
}
当程序调用具有SeqList类型返回值的函数时都要使用复制构造函数,用以复制和返回运算结果。如没有定义构造函数,系统会自动建立一个复制构造函数来完成以上工作。
reSize(int newSize)
重定义数组大小
template <class T> //重定义大小
void SeqList<T> :: reSize(int newSize)
{
if(newSize<=0)
{
cerr<<"无效的数组大小"<<endl;
return;
}
if(newSize!=maxSize)
{
T *newarray=new T[newSize]; //建立新数组
if ( newarray == NULL )
{
cerr<<"存储分配失败!"<<endl;
exit(1);
}
int n=last+1; //要复制的表项个数
T *srcptr=data; //获得原数组首地址
T *destptr=newarray;//目的数组首地址
while(n- -)//循环次数需要复制的表项个数
*destptr++=*srcptr++;//把原数组内的表项一一复制进入新数组中
delete []data//删除老数组空间
data=newarray;//把data指针指向新数组
maxSize=newSize;//更新长度
}
}
search ( T & x ) const
template <class T>
int SeqList<T> :: search ( T & x ) const
{
//搜索函数:在顺序表中从头查找结点值等于
//给定值x的结点所在位置,如果没找到返回0
for(int i = 0; i <= last ; i++)
if (data[i]==x)
return i+1 ;
return 0;
}
Insert(int i, T& x)
算法描述:
- 如果表满了,则抛出上溢异常;
- 如果元素的插入位置不合理,则抛出位置异常;
- 将最后一个元素至第i个元素分别向后移动一个位置;
- 将元素x填入位置i处;
- 表长加1;
template <class T>
bool SeqList<T> :: Insert (T& x, int i )//插入的数据,插入的位置
{
if (last+1 >= MaxSize|| (i < 1 || i > last + 2) )
return false;
for (int j = last+1; j >= i; j--)
data[j] = data[j-1];
data[i-1] = x;
last++;
}
删除、输入输出操作
template <class T>
bool SeqList<T> :: Remove ( int i, T& x )
{
//在表中删除已有元素 x
if(last==-1 ||i<1 || i>last+1)
return false;
x=data[i-1];
for ( int j = i; j <= last; j++ )
data[j-1] = data[j];
last- - ;
return true; //成功删除
}
template <class T>
void SeqList<T> ::input()
{
cout<<"请输入元素个数";
while(1)
{
cin>>last;
if(last<=maxSize-1)
break;
cout<<"个数输入有误";
}
for(int i=0; i<=last; i++)
{
cin>>data[i];
cout<<i+1<<endl;
}
}
template <class T>
void SeqList<T> ::output()
{
cout<<"当前元素最后位置为"<<last<<endl;
for(int i=0; i<=last; i++)
{
cout<<"#"<<i+1<<":"<<data[i]<<endl;
}
}
顺序表的应用
集合的并交运算
并运算
void Union ( SeqList<int> & A, SeqList<int> & B)
{
int n = A.Length ( ), x;
int m = B.Length ( );
for ( int i = 1; i < =m; i++ )
{
B.getData(i,x); //在B中取一元素
int k = A.Search (x); //在A中搜索它
if ( k == 0 ) //若未找到插入它,将其插入A中
{
A.Insert (n, x);
n++;
}
}
}
交运算
void Intersection ( SeqList<int> & A,
SeqList<int> & B )
{
int n = A.Length ( );
int m = B.Length ( );
int i = 1, x;
while ( i < =n )
{
A.get Data(i, x); //在A中取一元素
int k = B.search (x); //在B中搜索它
if ( k == 0 )
{
A.Remove (i,x);
n- - ;
}
//未找到在A中删除它
else
i++;
}
}
顺序表的优缺点
顺序表的优点:
- 无需为表示表中元素之间的逻辑关系而增加额外的存储空间;
- 随机存取:可以快速地存取表中任一位置的元素。
顺序表的缺点: - 插入和删除操作需要移动大量元素;
- 表的容量难以确定,表的容量难以扩充;
- 造成存储空间的碎片。