目录
前言
这篇文章讲的是线性表的动态分配存储表示。
1.顺序表的动态分配存储表示
在上一篇博客中,我们介绍了线性表的静态分配存储结构。使用静态分配的时候,有个缺点就是数组的长度是固定的,顺序表中数据元素达到上上限之后,我们就无法继续操作了。
C++中我们除了使用静态数组之外,还可以动态的给数据元素分配存储空间,这样的话线性表的长度就可变了,我们就可以更加灵活的操作表了。
2.顺序表的静态存储表示
在C++中顺序表的动态分配存储结构定义如下:
//----- 线性表的动态分配顺序存储结构 - - - - -
#define LIST_INIT_SIZE 10 // 线性表存储空间的初始分配量
#define LISTINCREMENT 10 // 线性表存储空间的分配增量
typedef int ElementType;
typedef int Status;
typedef struct {
ElementType * element; // 存储空间基址
int length; // 当前长度
int lisezsize; // 当前分配的存储容量(以sizeof(ElementType)为单位)
}SeqList;
其中,数组指针elem表示线性表的基地址,length表示线性表的当前长度,listsize指示顺序表当前分配的存储空间大小,一旦因为插入元素而空间不足的时候,可进行再分配,即为顺序表增加一个大小存储为LISTINCREMENT个数据元素的空间。
1.初始化
顺序表的时候分配初始内存空间
// 初始化顺序表
Status initSeqList(SqList *sqList){
sqList->element = new ElementType[LIST_INIT_SIZE];//分配内存
if (!sqList->element) {
return 0; // 内存分配失败
}
sqList->length = 0; // 初始长度为0
sqList->listsize = LIST_INIT_SIZE; // 初始存储容量为初始分配量
return 1; // 初始化成功
}
2.销毁
删除动态分配的存储空间,置空指针和容量大小
// 销毁
void destroySqList(SqList *sqList){
delete [] sqList->element;
sqList->element = nullptr;//讲指针置空
sqList->length = 0;
sqList->listsize = 0;
}
3.清空
长度置为0
// 清空
void clearSqList(SqList *sqList){
sqList->length = 0;// 长度置为0.但存储空间不变
}
4.判空
// 判空
Status emptySqList(SqList *sqList){
return sqList->length == 0;
}
5.表长
返回顺序表的长度
// 长度
int staticSqListLength(StaticSqList *sqList){
return sqList->length;
}
6.数据元素
遍历数组根据下标获取数据元素
// 获取元素
Status getElemForSqList(SqList *sqList,int location,ElementType * element){
if (location > sqList->length - 1 || location < 0) {
return 0;
}
*element = sqList->element[location];
return 1;
}
7.获取下标
// 获取元素下标
Status locationElemForSqList(SqList *sqList,ElementType element,int *location){
for (int i = 0; i < sqList->length; i++) {
if (sqList->element[i] == element) {
* location = i;
return 1;
}
}
return 0;
}
8.前驱节点
// 前驱节点
Status priorElemForSqList(SqList *sqList,ElementType currentElement,ElementType * priorElement){
for (int i = 0; i < sqList->length; i++) {
if (sqList->element[i] == currentElement) {
if (i >= 1) {
* priorElement = sqList->element[i-1];
return 1;
}
}
}
return 0;
}
9.后继节点
// 后继节点
Status nextElemForSqList(SqList *sqList,ElementType currentElement,ElementType * nextElement){
for (int i = 0; i < sqList->length; i++) {
if (sqList->element[i] == currentElement) {
if (i < sqList->length - 1) {
* nextElement = sqList->element[i+1];
return 1;
}
}
}
return 0;
}
10.插入
当我们使用动态分配存储表示顺序表的时候,如果在插入元素时发现顺序表的存储空间已满,我们需要动态地扩展存储空间,以容纳更多的元素。这就涉及到重新分配内存,并将原有数据复制到新的存储空间中,然后再进行元素插入操作。这样可以确保在插入元素时不会受到存储空间的限制。
// 插入
Status insertSqList(SqList *sqList, int pos, ElementType element) {
if (pos < 0 || pos > sqList->length + 1) {
return 0;
}
// 检查存储空间是否足够,不足则扩展存储空间
if (sqList->length >= sqList->listsize) {
ElementType *newElement = new ElementType[sqList->listsize + LISTINCREMENT]; // 新的存储空间
if (!newElement) {
return 0; // 内存分配失败
}
// 将原有数据复制到新的存储空间中
for (int i = 0; i < sqList->length; ++i) {
newElement[i] = sqList->element[i];
}
// 释放原有存储空间
delete[] sqList->element;
// 更新指针指向新的存储空间
sqList->element = newElement;
// 更新存储容量
sqList->listsize += LISTINCREMENT;
}
// 插入位置之后的元素后移
for (int i = sqList->length; i > pos - 1; i--) {
sqList->element[i] = sqList->element[i - 1];
}
// 插入新元素
sqList->element[pos - 1] = element;
// 更新顺序表的长度
sqList->length++;
return 1; // 插入成功
}
11.删除
// 删除
Status deleteSqList(SqList *sqList, int i, ElementType *element) {
if (i < 1 || i > sqList->length || sqList->length == 0) {
return 0;
}
*element = sqList->element[i - 1];
for (int j = i; j < sqList->length; j++) { // 删除位置之后的元素前移
sqList->element[j - 1] = sqList->element[j];
}
sqList->length--;
return 1;
}
12.遍历
// 遍历
void traverseSqList(SqList *sqList){
for (int i = 0; i<sqList->length; i++) {
cout<<sqList->element[i]<<"\t";
}
cout<<endl;
}
13.测试代码
void testSeqList(void){
SqList sqList;
cout<<"顺序表初始化......"<<endl;
if (initSeqList(&sqList)) {
cout<<"顺序表初始化成功"<<endl;
}
cout<<"顺序表判空和长度计算......"<<endl;
if (emptySqList(&sqList)) {
cout<<"顺序表为空,长度为"<<SqListLength(&sqList)<<endl;
}
cout<<"顺序表插入测试......"<<endl;
for (int i = 1; i <=11 ; i++) {
if (insertSqList(&sqList, sqList.length + 1, i)) {
cout<<"数据元素"<<i<<"插入成功"<<endl;
}else{
cout<<"数据元素"<<i<<"插入失败"<<endl;
}
}
cout<<"插入之后的静态顺序表"<<endl;
traverseSqList(&sqList);
cout<<"顺序表删除测试......"<<endl;
ElementType element;
if (deleteSqList(&sqList, 10, &element)){
cout<<"数据元素"<<element<<"删除成功"<<endl;
}
cout<<"删除之后的静态顺序表"<<endl;
traverseSqList(&sqList);
//后继节点测试
ElementType nextElement;
if (nextElemForSqList(&sqList, 8, &nextElement)) {
cout<<"数据元素8"<<"后继节点为:"<<nextElement<<endl;
}else{
cout<<"后继节点不存在"<<endl;
}
//前驱节点测试
ElementType priorElement;
if (priorElemForSqList(&sqList, 8, &priorElement)) {
cout<<"数据元素8"<<"前驱节点为:"<<priorElement<<endl;
}else{
cout<<"前驱节点不存在"<<endl;
}
cout<<"顺序表数据元素下标测试......"<<endl;
for (int i = -1; i <= 12; i++) {
int location;
if (locationElemForSqList(&sqList, i, &location)) {
cout<<"数据元素"<<i<<"下标为:"<<location<<endl;
}else{
cout<<"数据元素不存在"<<endl;
}
}
destroySqList(&sqList);
cout<<"顺序表销毁"<<endl;
}