顺序表是线性表基于数组的存储表示。
1、顺序表定义:
把线性表中的所有表项按照其逻辑顺序依次存储到从计算机存储中指定存储位置开始的一块连续的存储空间中。线性表中第一个表项的存储位置就是被指定的存储位置,第i个表项(2 <= i <= n)的存储位置紧接在第i-1个表项的位置的后面。假设顺序表中每个表项的数据类型为T,则每个表项所占用存储空间的大小(即字节数)大小相同,均为sizeof(T),整个顺序表所占用存储空间的大小为n×sizeof(T),其中n表示线性表的长度。
2、顺序表的特点:
- 在顺序表中,各个表项的逻辑顺序与其物理顺序一致,即第i个表项存储于第i个物理位置(1 <= i <= n)。
- 对顺序表中所有表项,既可以进行顺序访问,也可以进行随机访问。也就是说,既可以从表的第一个表项开始逐个访问,也可以按照表项的序号(下标)直接访问。
3、顺序表的优缺点 :
优点:
- 无需为表示结点间的逻辑关系而增加额外的外储空间,存储利用率高。
- 可以方便地随机存取表中的任一结点,存取速度快。
缺点:
- 在表中插入新元素或删除无用元素时,为了保持其他元素的相对次序不变,平均需要移动一半元素,运行效率很低。
- 由于顺序表要求占用连续的空间,如果预先进行存储分配(静态分配),则当表长度变化较大时,难以确定合适的存储空间大小,若按可能达到的最大长度预先分配表的空间,则容易造成一部分空间长期闲置而得不到充分利用。若事先对表长估计不足,则插入操作可能使表长超过预先分配的空间而造成溢出。如果采用指针方式定义数组,在程序运行时动态分配存储空间,一旦需要,可以用另一个新的更大的数组代替原来的数组,这样虽然能够扩充数组空间,但是时间开销比较大。
4、顺序表的静态存储表示:
#define maxSize 100
typedef int T;
typedef struct
{
T data[maxSize];
int n;
}SeqList;
5、顺序表的动态存储表示:
typedef int T;
typedef struct
{
T *data;
int maxSize, n;
}SeqList
6、顺序表的类声明:
const int defaultSize = 100;
template<class T>
class SeqList
{
protected:
T *data; //存放数组
int maxSize; //最大可容纳表项的项数
int last; //当前已存表项的最后位置(从0开始)
void reSize(int newSize); //改变data数组空间大小
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; //搜索x在表中位置,函数返回表项序号
int Locate(int i)const; //定位第i个表项,函数返回表项序号
bool getData(int i, T& x)const //取第i个表项的值
{
if(i > 0 && i <= last+1)
{
x = data[i-1];
return true;
}
else
return false;
}
bool Insert(int i, T& x); //插入x在第i个表项之后
bool Remove(int i, T& x); //删除第i个表项,通过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);
};
构造函数的实现:通过指定参数sz定义数组的长度。
template<class T>
SeqList<T>::SeqList(int sz) //构造函数,通过指定参数sz定义数组的长度
{
if(sz > 0)
{
maxSize = sz;
last = -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)
{
cout << "存储分配失败" << endl;
exit(1);
}
for(int i = 1; i <= last+1; ++i)
{
L.getData(i, value);
data[i-1] = value;
}
}
reSize函数:扩充顺序表的存储数组空间大小,新数组的元素个数为newSize。
template<class T>
void SeqList<T>::reSize(int newSize)
{
if(newSize <= 0)
{
cout << "无效的数组大小" << endl;
}
if(newSize != maxSize) //修改大小
{
T* new_arr = new T[newSize]; //建立新数组
if(new_arr == NULL)
{
cout << "存储分配错误" << endl;
exit(1);
}
int n = last+1;
T *srcptr = data; //源数组首地址
T *desptr = new_arr; //目的数组首地址
while(n--) //把旧数组数据复制到新数组里
*desptr++ = *srcptr++;
delete[] data; //释放旧数组分配的空间
data = new_arr;
maxSize = newSize;
}
}
搜索函数:在表中顺序搜索与给定值x匹配的表项,找到则函数返回该表项是第几个元素,否则返回0,表示搜索失败。
template<class T>
int SeqList<T>::search(T& x)const
{
for(int i = 0; i <= last;++i)
{
if(data[i] == x)
return i+1;
}
return 0;
}
定位函数:函数返回第i个表项的位置,否则函数返回0,表示定位失败。
template<class T>
int SeqList<T>::Locate(int i)const
{
if(i >= 1 && i <= last+1)
return i;
else
return 0;
}
顺序表中表项的序号从1开始,第一个表项存放于data[0],第二个表项存放于data[1]......第n个表项存放于data[n-1]。由此可知,表项序号与它在数组中的实际存放位置差1。第i个表项存放于数组第i-1号位置。
插入函数:将新元素x插入到表中第i个表项之后。函数返回插入成功的信息,若插入成功,则返回true;否则返回false。i = 0是虚拟的,实际上是插入到第1个元素位置。
template<class T>
bool SeqList<T>::Insert(int i, T& x)
{
if(last == maxSize-1) //表满,不能插入元素
return false;
if(i < 0 || i > last+1)
return false; //参数i不合理
for(int j = last; j >= i; j--) //依次后移,空出第i号位置
{
data[j+1] = data[j];
}
data[i] = x; //插入
last++; //最后位置加1
return true;
}
删除函数:从表中删除第i个表项,通过引用x返回删除的元素值。函数返回删除成功的信息,若删除成功则返回true,否则返回false。
template<class T>
bool SeqList<T>::Remove(int i, T& x)
{
if(last == -1)
return false;
if(i < 1 || i > last+1)
return false;
x = data[i-1];
for(int j = i; j <= last; ++j)
data[j-1] = data[j]; //依次前移,填补
last--; //最后位置减1
return true;
}
输入函数:从标准输入(键盘)逐个输入数据,建立顺序表。
template<class T>
void SeqList<T>::input()
{
cout << "开始建立顺序表,请输入表中元素个数";
while(1)
{
cin >> last;
if(last <= maxSize-1)
break;
cout << "表元素个数输入有误,范围不能超过" << maxSize-1 <<":";
}
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;
}
}