线性表的顺序存储又称顺序表。它是用一组连续的存储单元依次存储线性表中的数据元素,从而使得在逻辑上相邻的两个元素在物理位置上也相邻。
顺序表的最主要特点是随机访问,即通过首地址和元素序号可在时间O(1)内找到指定的元素。
顺序表的存储密度高,每个节点只存储数据元素。
顺序表逻辑上相邻的元素物理上也相邻,所以插入和删除需要移动大量元素。
顺序表类
顺序表类私有成员有3个,分别是要开辟的动态数组,用指针data来表示;数组的长度,用length来记录;数组的最大长度,用Maxsize来表示。
顺序表类的成员函数包括有参和无参的构造函数,打印顺序表的函数,向表中某个位置插入某个元素的函数,删除表中某个位置元素的函数,求顺序表长度的函数,判空函数,按照位序进行查找的函数,按照值进行查找的函数,对顺序表进行析构的函数,对顺序表扩容的函数。
class seqlist
{
public:
seqlist();//无参构造函数,初始化一个空表
seqlist(datatype[], int);//以一个数组对顺序表进行初始化
void printlist();//打印顺序表(遍历)
void insertlist(int,datatype);//向表中插入元素
void deletelist(int);//删除表中某个元素
int empty();//判空操作
int Length();//求顺序表的长度
datatype get(int);//按位查找
int locate(datatype);//按值查找
~seqlist();//析构顺序表
void resize(int);//增加数组长度
private:
datatype* data;//要开辟的动态数组
int length;//顺序表的长度
int Maxsize;//顺序表的最大长度
};
无参构造函数
假设数组的最大长度为10,在堆区创建大小为10的连续空间。由于无参构造函数创建的是空表,所以初始化长度为0.
//建立空表
template <typename datatype>
seqlist<datatype>::seqlist()
{
Maxsize = 10;
data = new datatype[Maxsize];
length = 0;
}
有参构造函数
用一个数组对顺序表进行初始化。如果数组的长度大于顺序表的长度,超出了顺序表的范围,不能被初始化,提示后返回;否则将数组中每个元素依次复制到顺序表中,并记录顺序表的长度。
//以一个数组对顺序表进行初始化
template <typename datatype>
seqlist<datatype>::seqlist(datatype a[], int n)
{
Maxsize = 10;
data = new datatype[Maxsize];
length = 0;
if (n > Maxsize)
{
cout << "元素过多,无法初始化顺序表" << endl;
return;
}
else
{
for (int i = 0; i < n; i++)
{
data[i] = a[i];
}
length = n;
}
}
打印顺序表函数
实质上是对顺序表的遍历操作,打印出顺序表中的每一个元素。
//打印顺序表
template <typename datatype>
void seqlist<datatype>::printlist()
{
for (int i = 0; i < length; i++)
{
cout << *(data + i) << " ";
}
cout << endl;
}
析构顺序表函数
当指向顺序表的指针不为空时,释放掉在堆区开辟的这块连续的内存空间。
//析构顺序表
template <typename datatype>
seqlist<datatype>::~seqlist()
{
if(data!=NULL)
delete[] this->data;
}
向表中插入元素的函数
如果插入的位置在位序为1的元素前或者在位序为length+2的位置时(不能隔着一个或多个空位进行插入),则返回插入位置错误。如果顺序表的长度已经大于其最大长度时,那么返回顺序表已满,无法继续插入。上述这两种情况如果都没有发生,则可以正常插入,从最后一个元素开始,依次向后移动一个元素,直至找到pos位置(但在插入的时候,要放在pos-1的位置上,因为数组下标是从0开始的),随后让顺序表的长度加1.
//向表中插入元素
template <typename datatype>
void seqlist<datatype>::insertlist(int pos,datatype element)
{
if (pos<1 || pos>length + 1)
{
cout << "插入错误" << endl;
return;
}
if (length == Maxsize)
{
cout << "顺序表已满,无法继续插入" << endl;
return;
}
for (int i = length; i >= pos; i--)
{
data[i] = data[i - 1];
}
data[pos-1] = element;
length++;
}
判空函数
如果顺序表的长度为0,则返回0.
//判空操作
template<typename datatype>
int seqlist<datatype>::empty()
{
if (length == 0) return 0;
}
求顺序表长度的函数
返回顺序表的长度。
//求顺序表的长度
template <typename datatype>
int seqlist<datatype>::Length()
{
return this->length;
}
删除表中某个元素的函数
如果线性表的长度为0,不能再删了,返回;如果删除的位置不是表中的元素,返回删除位置错误。上述这两种情况均未发生,则可以正常删除,从pos位置开始(因为要删的元素位序是pos,但在顺序表中存储的位置是pos-1,所以从pos位置实际上就是从要删元素的下一个元素开始),一直到表的最后一个元素,依次向前挪动一个位置,并且把要删除的数提前存起来,并将顺序表长度减1.
//删除表中某个元素
template <typename datatype>
void seqlist<datatype>::deletelist(int pos)
{
if (length == 0)
{
cout << "所有元素已经被删完,不能再删" << endl;
return;
}
if (pos < 1 || pos>length)
{
cout << "要删除的元素位置不正确" << endl;
return;
}
datatype tmp = data[pos-1];
for (int i = pos; i < length; i++)
{
data[i-1] = data[i];
}
length--;
}
按位序查找的函数
传入要找的元素的位序pos,返回在数组中对应相应的元素(pos-1)
//按位序查找
template <typename datatype>
datatype seqlist<datatype>::get(int pos)
{
if (pos<1 || pos>length) return -1;
else return data[pos - 1];
}
按值查找的函数
在顺序表中查找相应值的元素,返回元素的位序(如果在for循环中找到了,返回i+1,是其位序),如果没找到,返回0。
//按值查找
template <typename datatype>
int seqlist<datatype>::locate(datatype d)
{
for (int i = 0; i < length; i++)
{
if (data[i] == d) return i + 1;
}
return 0;
}
增加数组长度的函数(动态扩容)
先将原来数组的指针用一个变量p存储,根据传入的参数,将该指针指向一块新的内存空间((length+len)这么长的空间),将原数组p中的元素依次复制到新的data数组中,并将数组的最大长度更新,并且释放掉原来的堆区空间。
//增加数组长度
template <typename datatype>
void seqlist<datatype>::resize(int len)
{
datatype* p = data;
data = new datatype[length+len];
for (int i = 0; i < length; i++)
{
data[i] = p[i];
}
Maxsize = length + len;
delete []p;
}