介于作者水平的问题,文中可能会有这样或者那样的错误或者漏洞,欢迎指正
提示:本文基于上一篇静态顺序表所写,目的也是作为对比使用
文章目录
1.1静态顺序表(可点击跳转)
1.2动态顺序表
动态顺序表:为什么叫做动态顺序表,顾名思义,就是其中的空间是动态的 ,并不像静态的一样在定义结构体的时候就将链表的最大空间确定了下来,而是当size将要达到动态顺序表的最大容器的时候,就会选择扩容这里我选择双倍扩容
既然是作为对比同样的我们实现的功能也和上文一样,只需要略作修改便可,主要修改的部分体现在
1、(动态)定义结构体
(若是至于参数什么时候&L(需要对L中元素进行修改的时候),什么时候L(查看时候))
typedef struct {
ElemType *data=NULL;
//与静态相比这里使用的是指针,不用数组
int length;//表的实际长度
int capacity; //但是同样的这里需要多定义容量(可变化),用来判断是否需要扩容
} SqList;
下图为静态中结构体
2、(动态)与最大值判断,
若是大于最最大空间并不是返回错误 而是对空间进行扩容,扩容的方式有两种 一种直接原始数组后面若是有足够大的空间,直接在后面加即可,若是不够,则重新开辟一块足够大的区域 然后再进行数据拷贝
,
这里要特别注意realloc函数的使用
其中两个参数,一个原地址,一个size量 返回值同样是一个void *型指针 需要强制转化一下
if(L->capacity==L->length){//若是插入之后达到最大容量就扩容
L->data=(ElemType *)realloc(L->data,L->capacity<<1);
L->capacity*=2;
}
当然你也可以不使用这个realloc函数,重新使用malloc函数申请一片空间,然后将原来的值赋值给新申请的空间,在将这个新申请的空间赋值给L->data,并修改容量便可,但是这种因为要全部赋值,所以较耗时,
下图为静态中需要容量判断,超过MAX返回RERROR
3、(动态)初始化,
需要注意一点的就是需要进行判断是否申请成功 还有就是注意mallo函数的使用,本来他的返回值是void * 所以前面需要强制类型转化一下,并且强制转化为ElemType*类型是因为访问其中数据元素的时候,是根据这个转化的类型来对顺序表进行操作的,
status InitList(SqList* L) { //相当于是给上面的结构体中各个变量赋一个初值
int size;
cout<<"你现在需要多大的容积(不知道就随便填一个)"<<endl;
cin>>size;
L->data=(ElemType*) malloc(size*sizeof(ElemType));
if(NULL==L->data){
cout<<"申请空间失败!"<<endl;
exit(1);
}
else cout<<"空间申请成功";
L->length=0;
L->capacity=size;
return OK;
}
下图为静态中的初始化
4、(动态)因为是空间动态申请的所以需要释放,
(题外话,使用free之后指针指向还是不变的,所以别忘了置为NULL)
status DestoryList(SqList *L) {
printf("释放之前的指针位置是%p\n",L->data);
free(L->data);
printf("释放之后的指针位置是%p\n",L->data);
L->data=NULL;
printf("加NULL后的指针位置是%p\n",L->data);
L->length=0;
L->capacity=0;
PrintList(*L);
}
下图是静态中的删除
可执行代码(只是对上一篇静态数组稍作修改)
//InitList(&L):初始化一个空的线性表
//Length(L):求表长,返回线性表L的长度,即即L中数据元素的个数
//LocateElem(L,e):按值查找操作,即获取表L中具有给定关键字值的元素
//GetElem(L,i):按位查找操作,获取L中第i个位置上的元素的值
//ListInsert(&L,i,e):插入操作,在表L中第i个位置插入指定元素
//PrintList(L):输出操作,按照前后 顺序输出线性表L的所有元素的值
//Empty(L):判空操作:若是L为空表,返回true,否则返回false
//DestoryList(&l):销毁操作,销毁线性表,并释放线性表L占用的存储空间
//考试的时候最好也是使用这些名称
#include<bits/stdc++.h>
#define ElemType int
#define status int
#define OK 1
#define ERROR 0
#define F(i,m,n) for(int i=m;i<n;i++)
using namespace std;
/********************功能函数*************************/
typedef struct {
ElemType *data=NULL;
//与静态相比这里使用的是指针,不用数组
int length;//表的实际长度
int capacity; //但是同样的这里需要多定义容量(可变化),用来判断是否需要扩容
} SqList;
status PrintList(SqList L) {
cout<<"数组L此时的内容是"<<endl;
for(int i=0; i<L.length; i++)
cout<<L.data[i]<<" ";
cout<<endl;
return OK;
}
status InitList(SqList* L) { //相当于是给上面的结构体中各个变量赋一个初值
int size;
cout<<"你现在需要多大的容积(不知道就随便填一个)"<<endl;
cin>>size;
L->data=(ElemType*) malloc(size*sizeof(ElemType));
if(NULL==L->data){
cout<<"申请空间失败!"<<endl;
exit(1);
}
else cout<<"空间申请成功";
L->length=0;
L->capacity=size;
return OK;
}
status Length(SqList L) {
return L.length;
}
int LocateElem(SqList L,ElemType e) {
F(i,0,L.length) {
if(e==L.data[i])
return ++i;
}
printf("未找到这个值");
return 0;
}
ElemType GetElem(SqList L,int i) { //因为是获取第i个位置上,所以不用取等号
if(L.length<i||i<0) {
printf("你所输入的位置信息不对");
return 0;
}
else return L.data[i-1];
}
status ListInsert(SqList *L,int i,ElemType e) {
/*要想实现修改顺序表,就需要移动其中的数据*/
if(i<1||i>L->length+1) {
printf("你的输入有问题");
return ERROR;
}
/*因为顺序表的最大容积是确定的,所以需要加一个是否已经满的判断*/
else {
if((L->length+1)==i) { //插入最后一个元素就不需要移动
L->data[i-1]=e;
}
else { //否则就需要移动
for(int j=L->length-1; j>=i-1; j--) {
/*第一只能从尾部向前来移动 否则就会发生数据 覆盖,
我们要插入i位置就需要数组的i-1空出来,所以i-1也要移动*/
L->data[j+1]=L->data[j];
}
L->data[i-1]=e;
}
L->length++;
}
if(L->capacity==L->length){//若是插入之后达到最大容量就扩容
L->data=(ElemType *)realloc(L->data,L->capacity<<1);
L->capacity*=2;
}
return OK;
}
status ListDelete(SqList *L,int i){//删除顺序表中指定位置的值
if(i<1||i>L->length){
cout<<"此时的i的值是"<<i;
cout<<"你输入的区间不正确"<<endl;
return ERROR;
}
else{//区间正确,直接时候后面一个元素覆盖前一个元素即可
for(int j=i;j<L->length;j++){//要考虑边界值,这里边界值没有问题
L->data[j-1]=L->data[j];
}
L->length--;
cout<<"成功删除!"<<endl;
PrintList(*L);
return OK;
}
}
status Empty(SqList L) {
if(0==L.length) return OK;
else return ERROR;
}
status DestoryList(SqList *L) {
printf("释放之前的指针位置是%p\n",L->data);
free(L->data);
printf("释放之后的指针位置是%p\n",L->data);
L->data=NULL;
printf("加NULL后的指针位置是%p\n",L->data);
L->length=0;
L->capacity=0;
PrintList(*L);
}
int Capacity(SqList L){
return L.capacity;
}
/**************************操作函数*****************************/
/*写操作函数的时候就尽量避免使用内部*/
void Add(SqList *L){
cout<<"1、你是要增加一系列数,2、还是在某一个位置增加一个数"<<endl;
int choice;
cin>>choice;int i=1;int size;ElemType val;
switch(choice){
case 1:{
cout<<"请输入你要添加多少个元素 添加的值是多少"<<endl;
scanf("%d%d",&size,&val);
while(size--){
ListInsert(L,i++,val);
}
PrintList(*L);
break;
}
case 2:{
cout<<"请输入某一个位置,以及某一个值"<<endl;
cin>>size>>val;
ListInsert(L,size,val);
PrintList(*L);
break;
}
default:{
break;
}
}
}
void Delete(SqList* L){
int flag;int size;
cout<<"1、删除某个位置,2、销毁向量"<<endl;
cin>>flag;
if(1==flag){
cout<<"请输入你要删除的位置"<<endl;
cin>>size;
ListDelete(L,size);
}
else if(2==flag){
DestoryList(L);
}
else{
cout<<"你的输入不正确"<<endl;
}
}
void Modify(SqList*L){//修改某个值为某 只修改第一个
ElemType val1,val2;
cout<<"请输入你想修改的值"<<endl;
cout<<"请输入你现在想填入的值"<<endl;
scanf("%d%d",&val1,&val2);
int i=LocateElem(*L,val1);
ListDelete(L,i);
ListInsert(L,i,val2);
PrintList(*L);
}
void Seek(SqList L){
int choice; int val;
cout<<"1、查找某一个位置的值"<<endl;
cout<<"2、查找某一个值第一次出现的位置"<<endl;
cout<<"3、查看是否是空值"<<endl;
cout<<"4、查看列表的长度"<<endl;
cout<<"5、查看此时的容积"<<endl;
cin>>choice;
switch(choice){
case 1:{
cout<<"请输入你要查找的位置"<<endl;
cin>>val;
cout<<"你要查找的位置上的值是"<<GetElem(L,val)<<endl;
break;
}
case 2:{
cout<<"请输入你要查找的值"<<endl;
cin>>val;
cout<<"你要查找的值所在的位置是"<<LocateElem(L,val)<<endl;
break;
}
case 3:{
if(1==Empty(L)) cout<<"是一个空表"<<endl;
else cout<<"不是一个空表"<<endl;
break;
}
case 4:{
cout<<"此时的列表长度是"<<Length(L)<<endl;
break;
}
case 5:{
cout<<"此时的容量是"<<Capacity(L)<<endl;
break;
}
default: break;
}
}
void menu() {
cout<<"使用上述函数实现增删改查"<<endl;
cout<<"1、增 2、删除 3、修改 4、查 5、退出"<<endl;
}
status main() {
SqList L;int choice;
InitList(&L);
while(1){
menu();cin>>choice;
if(5==choice) break;
switch(choice){
case 1:{
Add(&L);
break;
}
case 2:{
Delete(&L);
break;
}
case 3:{
Modify(&L);
break;
}
case 4:{
Seek(L);
break;
}
default:break;
}
}
}