2.4线性表的顺序表示和实现
前面的内容都是铺垫,到2.4是应用。前面就简单提一下。
数据结构中线性结构是1对1的,比较简单。咱们柿子先挑着软的捏。
线性结构的定义:
例如:
特点(其实就是把定义又强调了一遍)
废话少说,上代码!
#include <iostream>
using namespace std;
//定义存储表示
typedef int ElemType; //定义int的别名ElemType
typedef int Status;
# define MAXSIZE 100 // 初始化长度
# define OK 1
//定义一个SqList结构体
typedef struct
{
ElemType *elem; //定义一个指针表示存储空间基址
int length; //当前表长(特指元素个数)
} SqList;
//初始化
Status InitList_Sq(SqList &L)
{
//构造一个空的顺序表L。
L.elem = new ElemType[MAXSIZE];//开辟一个存放整型数字,大小为100的数组空间,并返回首元素的地址
if ( ! L.elem )
cout<<"内存空间分配失败"<<endl;
L.length = 0; // 空表长度为0
return OK;
}
//销毁顺序表
void DestroyList(SqList &L)
{
if (L.elem)
delete[ ] L.elem; //释放存储空间
L.length=0;
L.elem = NULL;
}
//求顺序表的长度
int GetLength(SqList L)
{
return L.length;
}
//判断顺序表是否为空
bool IsEmpty(SqList L)
{
if (L.length==0)
return true;
else
return false;
}
//给顺序表赋值
void fuzhi(SqList &L)
{
int n,m;
cout<<"请输入赋值的数据元素个数"<<endl;
cin>>n;
for(int i=0; i<n; i++)
{
cout<<"请输入第"<<i+1<<"的数据元素的值"<<endl;
cin>>m;
L.elem[i]=m;
L.length++;
}
cout<<"赋值成功"<<endl;
}
//清空顺序表
void ClearList(SqList &L)
{
L.length=0;
cout<<"顺序表清空成功"<<endl;
}
//获取顺序表指定位置元素
void Getelem(SqList L,int i)
{
ElemType e;
if(i<1||i>L.length)
{
cout<<"输入的查找参数错误"<<endl;
}
else
{
e=L.elem[i-1];
cout<<"查找成功"<<endl;
cout<<"顺序表中第"<<i<<"个数据元素是"<<e<<endl;
}
}
//获取顺序表指定位置元素的后继
Status Next_elem(SqList L,int i)
{
ElemType e;
if(i<1||i>L.length)
{
cout<<"输入的查找参数错误"<<endl;
return -1;
}
if (i==L.length)
{
cout<<"最后一个元素没有后继"<<endl;
return -1;
}
e=L.elem[i];
cout<<"查找成功"<<endl;
cout<<"顺序表中第"<<i<<"个数据元素的后继是"<<e<<endl;
return OK;
}
//获取顺序表指定位置元素的前驱
Status pre_elem(SqList L,int i)
{
ElemType e;
if(i<1||i>L.length)
{
cout<<"输入的查找参数错误"<<endl;
return -1;
}
if (i==1)
{
cout<<"第一个元素没有前驱"<<endl;
return -1;
}
e=L.elem[i-2];
cout<<"查找成功"<<endl;
cout<<"顺序表中第"<<i<<"个数据元素的前驱是"<<e<<endl;
return OK;
}
//显示顺序表
void display(SqList L)
{
for(int i=0; i<L.length; i++)
{
cout<<"第"<<i+1<<"的数据元素的值:";
cout<<L.elem[i]<<endl;
}
cout<<"顺序表输出完成"<<endl;
}
//在顺序表指定位置插入元素
Status ListInsert(SqList &L,int i,ElemType e)
{
int j=0;
if(i<1||i>L.length)
{
cout<<"输入的查找参数错误"<<endl;
return -1;
}
if(L.length==MAXSIZE)
{
cout<<"当前储存空间已满,无法插入"<<endl;
return -1;
}
for(j=L.length-1; j>=i-1; j--)
{
L.elem[j+1]=L.elem[j];
}
L.elem[i-1]=e;
++L.length;
cout<<"插入顺序表中第"<<i<<"个数据元素成功"<<endl;
return OK;
}
//删除顺序表指定位置元素
void ListDelete(SqList &L,int i)
{
int j=0;
if(i<1||i>L.length)
{
cout<<"输入的查找参数错误"<<endl;
}
else
{
for(j=i; j<=L.length-1; j++)
{
L.elem[j-1]=L.elem[j];
}
--L.length;
cout<<"删除顺序表中第"<<i<<"个数据元素成功"<<endl;
}
}
//根据顺序表中的值,查找其位置
void Locateelem(SqList L,ElemType e)
{
int i=0;
int flag=0;
for(i=0; i<L.length; i++)
{
if(L.elem[i]==e)
{
cout<<"查找成功"<<endl;
cout<<e<<"位于顺序表中第"<<i+1<<"个数据元素"<<endl;
flag=1;
}
}
if(flag==0)
cout<<"查找失败"<<endl;
}
void show_help()
{
cout<<"******* Data Structure ******"<<endl;
cout<<"1----清空顺序表"<<endl;
cout<<"2----判断顺序表是否为空"<<endl;
cout<<"3----求顺序表长度"<<endl;
cout<<"4----获取顺序表指定位置元素"<<endl;
cout<<"5----求前驱"<<endl;
cout<<"6----求后继"<<endl;
cout<<"7----在顺序表指定位置插入元素"<<endl;
cout<<"8----删除顺序表指定位置元素"<<endl;
cout<<"9----显示顺序表"<<endl;
cout<<"10----给顺序表赋值"<<endl;
cout<<"11----根据数据元素查询在顺序表中位置"<<endl;
cout<<" 退出,输入0"<<endl;
}
int main()
{
int operate_code;
show_help();
//定义顺序表变量,如SqList L;
SqList L;
//调用初始化顺序表函数,如Init_List(L);
InitList_Sq(L);
while(1)
{
cout<<"";
cin>>operate_code;
if(operate_code==1)
{
ClearList(L);
}
else if (operate_code==2)
{
if(IsEmpty(L))
cout<<"顺序表为空表"<<endl;
else
cout<<"顺序表非空表"<<endl;
}
else if (operate_code==3)
{
cout<< "顺序表的长度是:"<< GetLength(L)<<endl;
}
else if (operate_code==4)
{
int c;
cout<< "请输入你要查找的数据元素的位置"<<endl;
cin>>c;
Getelem(L,c);
}
else if (operate_code==5)
{
int c;
cout<< "请输入你要查找的数据元素的位置"<<endl;
cin>>c;
pre_elem(L,c);
}
else if (operate_code==6)
{
int c;
cout<< "请输入你要查找的数据元素的位置"<<endl;
cin>>c;
Next_elem(L,c);
}
else if (operate_code==7)
{
int a;
ElemType e;
cout<<"请输入你要插入的数据元素位置"<<endl;
cin>>a;
cout<<"请输入你要插入的数据元素"<<endl;
cin>>e;
ListInsert(L,a,e);
}
else if (operate_code==8)
{
int b;
cout<<"请输入你要删除的数据元素位置"<<endl;
cin>>b;
ListDelete(L,b);
}
else if (operate_code==9)
{
display(L);
}
else if (operate_code==10)
{
fuzhi(L);
}
else if (operate_code==11)
{
ElemType f;
cout<<"请输入你要查找的数据元素"<<endl;
cin>>f;
Locateelem(L,f);
}
else if (operate_code==0)
{
break;
}
else
{
cout<<"\n操作码错误!!!"<<endl;
show_help();
}
}
//调用销毁顺序表函数,如Destroy_List(L);
DestroyList(L);
return 0;
}
剖析:
<1>
typedef int ElemType; //定义int的别名ElemType
typedef int Status;
- 这个是用来定义int的别名Elemtype和Status。人们喜欢这样做是因为使程序更容易明白,因为用int的时候不知道他是干嘛的
<2>
typedef struct
{
ElemType *elem; //定义一个指针表示存储空间基址
int length; //当前表长(特指元素个数)
} SqList;
- 定义一个叫做SqList的结构体。
- 通过定义顺序表存储空间基址和其长度来把顺序表确定下来。
<3>
//初始化
Status InitList_Sq(SqList &L)
{
//构造一个空的顺序表L。
L.elem = new ElemType[MAXSIZE];//开辟一个存放整型数字,大小为100的数组空间,并返回首元素的地址
if ( ! L.elem )
cout<<"内存空间分配失败"<<endl;
L.length = 0; // 空表长度为0
return OK;
}
- Status其实就是int。所以这个函数的类型是int型。
- 因为初始化要对顺序表进行改变,所以这里用引用(&L)
- 之前定义的是*elem这个指针,现在我们要往里面传地址。而new ElemType[MAXSIZE]的作用就是:开辟一个存放整型数字,大小为100的数组空间,并返回首元素的地址
- 之后让顺序表长度为0,完成初始化。
<4>
//销毁顺序表
void DestroyList(SqList &L)
{
if (L.elem)
delete[ ] L.elem; //释放存储空间
L.length=0;
L.elem = NULL;
}
- 最开始初始化,最后结束要销毁顺序表。使用new [ ]申请的内存释放时要用delete [ ]才行。
- 长度变0,数据清空。欧了。
<5>
//求顺序表的长度
int GetLength(SqList L)
{
return L.length;
}
- 用int类型函数直接return 长度即可。
- 这里因为不需要对顺序表进行修改所以直接传入L即可,不用引用。
<6>
bool IsEmpty(SqList L)
{
if (L.length==0)
return true;
else
return false;
}
- 因为return值是true or false ,所以函数类型为bool型。
<7>
//给顺序表赋值
void fuzhi(SqList &L)
{
int n,m;
cout<<"请输入赋值的数据元素个数"<<endl;
cin>>n;
for(int i=0; i<n; i++)
{
cout<<"请输入第"<<i+1<<"的数据元素的值"<<endl;
cin>>m;
L.elem[i]=m;
L.length++;
}
cout<<"赋值成功"<<endl;
}
- 修改顺序表用引用,位置从0开始赋值。
<8>
//清空顺序表
void ClearList(SqList &L)
{
L.length=0;
cout<<"顺序表清空成功"<<endl;
}
- 直接让长度为0即可,不用像销毁那样用delete [ ].
<9>
//获取顺序表指定位置元素
void Getelem(SqList L,int i)
{
ElemType e;
if(i<1||i>L.length)
{
cout<<"输入的查找参数错误"<<endl;
}
else
{
e=L.elem[i-1];
cout<<"查找成功"<<endl;
cout<<"顺序表中第"<<i<<"个数据元素是"<<e<<endl;
}
}
- 要先判断要查询的位置是不是在顺序表里面
- 因为存储是从0这个位置开始的,所以要返回第 i − 1 i - 1 i−1个的值
<10>
//获取顺序表指定位置元素的后继
Status Next_elem(SqList L,int i)
{
ElemType e;
if(i<1||i>L.length)
{
cout<<"输入的查找参数错误"<<endl;
return -1;
}
if (i==L.length)
{
cout<<"最后一个元素没有后继"<<endl;
return -1;
}
e=L.elem[i];
cout<<"查找成功"<<endl;
cout<<"顺序表中第"<<i<<"个数据元素的后继是"<<e<<endl;
return OK;
}
//获取顺序表指定位置元素的前驱
Status pre_elem(SqList L,int i)
{
ElemType e;
if(i<1||i>L.length)
{
cout<<"输入的查找参数错误"<<endl;
return -1;
}
if (i==1)
{
cout<<"第一个元素没有前驱"<<endl;
return -1;
}
e=L.elem[i-2];
cout<<"查找成功"<<endl;
cout<<"顺序表中第"<<i<<"个数据元素的前驱是"<<e<<endl;
return OK;
}
- 求前驱后继挺像的,搞清楚位置就可了。
- if语句中记得写return -1.要不后面的语句还是会执行的。
- 因为有返回值所以函数类型不可为void。用int型即Status
<11>
//显示顺序表
void display(SqList L)
{
for(int i=0; i<L.length; i++)
{
cout<<"第"<<i+1<<"的数据元素的值:";
cout<<L.elem[i]<<endl;
}
cout<<"顺序表输出完成"<<endl;
}
- 用个for循环去输出即可。
<12>
//在顺序表指定位置插入元素
Status ListInsert(SqList &L,int i,ElemType e)
{
int j=0;
if(i<1||i>L.length)
{
cout<<"输入的查找参数错误"<<endl;
return -1;
}
if(L.length==MAXSIZE)
{
cout<<"当前储存空间已满,无法插入"<<endl;
return -1;
}
for(j=L.length-1; j>=i-1; j--)
{
L.elem[j+1]=L.elem[j];
}
L.elem[i-1]=e;
++L.length;
cout<<"插入顺序表中第"<<i<<"个数据元素成功"<<endl;
return OK;
}
- 插在表外面不可,插都满了再查不可。
- 如果直接从前面插队还得定义一个Temp来防止覆盖。干脆用个for循环让所有元素先往后移动一个。L.length-1是最后一个元素的地址,变成L.length,以此类推。
- 插入后别忘了让顺序表的长度加1。
<13>
//删除顺序表指定位置元素
void ListDelete(SqList &L,int i)
{
int j=0;
if(i<1||i>L.length)
{
cout<<"输入的查找参数错误"<<endl;
}
else
{
for(j=i; j<=L.length-1; j++)
{
L.elem[j-1]=L.elem[j];
}
--L.length;
cout<<"删除顺序表中第"<<i<<"个数据元素成功"<<endl;
}
}
- 这里只有查询位置不在顺序表这一个可能错误。所有用if……else就可以应付过来。不用return -1来中途结束这个函数了。
- 删除的话直接让要删的那个位置后面的元素覆盖掉他就ok了。
<14>
void Locateelem(SqList L,ElemType e)
{
int i=0;
int flag=0;
for(i=0; i<L.length; i++)
{
if(L.elem[i]==e)
{
cout<<"查找成功"<<endl;
cout<<e<<"位于顺序表中第"<<i+1<<"个数据元素"<<endl;
flag=1;
}
}
if(flag==0)
cout<<"查找失败"<<endl;
}
- 用for循环内置if判断就ok了。
- flag是用来标志是否查到的小旗子。
<15>
//定义顺序表变量,如SqList L;
SqList L;
- 主函数就比较常规了,就这个说下。之前我们定义了一个结构体的蓝图,现在L是那个结构体的实例。
性能分析:
同样,查找也是平均下来要过
n
2
\frac{n}{2}
2n 个元素。
so ~