线性表的顺序表示和实现
线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素,以第一个单元的存储地址作为数据元素的存储位置(教材P21)。
线性表中的顺序表,是表中相邻的元素a
i
和a
i+1
赋以相邻的存储位置LOC(
a
i
)和
LOC(
a
i+1
)。以元素在计算机内“物理位置相邻”来表示线性表中的数据元素之间的逻辑关系(教材P22)。
下面的程序主要是用来实现教材P19中关于线性表的12种基本操作的实现,这些基本操作包括了教材第二章中的算法2.3~2.6。
程序介绍:程序的所有逻辑都写在了一个程序main2-1.cpp中,代码可能比较多,但是合到一块方便代码的查看,如果分开可能移到自己的集成开发环境会出问题,总之把所有的逻辑都放到了一块。程序的第一部分是引入一些库以及对结构体的声明,第二部分是线性表的12种基本操作的实现,第三部分是main函数来分别调用线性表的12种基本操作。
main2-1.cpp的源代码
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<math.h>
#define ok 1
#define error 0
typedef int ElemType;//定义ElemType为整型
typedef int status;
#define list_init_size 10//线性表存储空间的初始分配量
#define list_increment 2//线性表存储空间的分配增量
struct SqList{//线性表的顺序存储结构
ElemType * elem;//存储空间基址
int length;//当前长度
int listsize;//当前分配的总容量(以sizeof(ElemType)为单位)
};
typedef int status;
//顺序存储的线性表的基本操作12个,包括教材上的算法2.3~2.6
void InitList(SqList &L)
{
//操作结果:构造一个空的顺序线性表l
L.elem=(ElemType *)malloc(list_init_size*sizeof(ElemType));
if(!L.elem)//存储分配失败
exit(OVERFLOW);
L.length=0;//空表长度为0
L.listsize=list_init_size;//初始存储容量
}
status listinsert(SqList &L,int i,ElemType e){
//初始条件:顺序线性表l已存在,1≤i≤listlength(l)+1
//操作结果:在l中第i个位置之前插入新的数据元素e,l的长度加1
ElemType *newbase,*q,*p;
if(i<1||i>L.length+1)
return error;
if(L.length==L.listsize)//当前存储空间已满,增加分配,修改
{
newbase=(ElemType *)realloc(L.elem,(L.listsize+list_increment)*sizeof(ElemType));
if(!newbase)//存储分配失败
exit(OVERFLOW);
L.elem=newbase;//新基址赋给L.elem
L.listsize+=list_increment;//增加存储容量
}
q=L.elem+i-1;//q为插入位置
for(p=L.elem+L.length-1;p>=q;--p)//插入位置之后的元素后移(由表尾元素开始移)
*(p+1)=*p;
*q=e;//插入e
++L.length;//表长增1
return ok;
}
void listtraverse(SqList &L,void(*visit)(ElemType&)){
//初始条件:顺序线性表l已存在
//操作结果:依次对l的每个数据元素调用函数visit() visit()的形参加'&',表明可通过visit()改变元素的值
ElemType *p=L.elem;//p指向第一个元素
int i;
for(i=1;i<=L.length;i++)//从表l的第一个元素到最后1个元素
visit(*p++);//对每个数据元素调用visit()
printf("\n");
}
status listempty(SqList L){
//初始条件:顺序线性表l已存在
//操作结果:若l为空表,则返回true,否则返回false
if(L.length==0)
return true;
else
return false;
}
void clearlist(SqList &L){
//初始条件:顺序线性表l已存在。操作结果:将l重置为空表
L.length=0;
}
status getelem(SqList L,int i,ElemType &e){
//初始条件:顺序线性表l已存在,1≤i≤listlength(l)
//操作结果:用e返回l中第i个数据元素的值
if(i<1||i>L.length)//i不在表l的范围之内
return error;
ElemType *p;
p=L.elem+i-1;
e=*p;//将表l的第i个元素的值赋给e
return ok;
}
int locateelem(SqList L,ElemType e,status (*compare)(ElemType,ElemType)){
//初始条件:顺序线性表l已存在,compare()是数据元素判定函数(满足为1,否则为0)
//操作结果:返回l中第1个与e满足关系compare()的数据元素的位序,若这样的数据元素不存在,则返回值为0
int i=1;//i的初值为第1个元素的位序
ElemType *p=L.elem;//p的初值为第一个元素的存储位置
while(i<=L.length && !(compare(*p++,e)))//i未超出表的范围且未找到满足关系的数据元素
++i;//继续向后找
if(i<=L.length)//找到满足关系的数据元素
return i;//返回其位序
else
return 0;
}
status priorelem(SqList L,ElemType cur_e,ElemType &pre_e){
//初始条件:顺序线性表l已存在
//操作结果:若cur_e是l的数据元素,且不是第一个,则用pre_e返回它的前驱;否则操作失败,pre_e无定义
int i=2;//从第2个元素开始
ElemType *p=L.elem+1;//p指向第2个元素
while(i<=L.length&&*p!=cur_e)//i未超出表的范围且未找到值为cur_e的元素
{
p++;//p指向下一个元素
i++;//计数加1
}
if(i>L.length)//到表结束处还未找到值为cur_e的元素
return error;//操作失败
else
{
pre_e=*--p;//p指向前一个元素(cur_e的前驱),将所指元素的值赋给pre_e
return ok;//操作成功
}
}
int listlength(SqList L){
//初始条件:顺序线性表l已存在
//操作结果:返回l中数据元素的个数
return L.length;
}
int nextelem(SqList L,ElemType cur_e,ElemType &next_e){
//初始条件:顺序线性表l已存在
//操作结果:若cur_e是l的数据元素,且不是最后一个,则用next_e返回它的后继,否则操作失败,next_e无定义
int i=1;//从第1个元素开始
ElemType *p=L.elem;//p指向第1个元素
while(i<L.length&&*p!=cur_e){//i未到表尾且未找到值为cur_e的元素
i++;
p++;
}
if(i==L.length)
return error;//到表尾的前一个元素还未找到值为cur_e的元素
else
{
next_e= * ++p;//p指向下一个元素(cur_e的后继),将所指元素的值赋给next_e
return ok;//操作成功
}
}
status listdelete(SqList L,int i,ElemType &e){
//初始条件:顺序线性表l已存在,1≤i≤listlength(l)
//操作结果:删除l的第i个数据元素,并用e返回其值,l的长度减1
ElemType *p,*q;
if(i<1||i>L.length)
return error;
p=L.elem+i-1;//被删除元素的位置
e=*p;//被删除元素的值赋给e
q=L.elem+L.length-1;//q为表尾元素的位置
for(++p;p<=q;++p)//被删除元素之后的元素左移(由被删除元素的后继元素开始移)
*(p-1)=*p;
L.length--;//表长减1
return ok;
}
void destroylist(SqList &L){
//初始条件:顺序线性表l已存在
//操作结果:销毁顺序线性表l
free(L.elem);//释放L.elem所指的存储空间
L.elem=NULL;//L.elem不再指向任何存储单元
L.length=0;
L.listsize=0;
}
/**
*线性表的顺序表示和实现
*/
status equal(ElemType c1,ElemType c2){
//判断是否相等的函数
if(c1==c2)
return true;
else
return false;
}
status sq(ElemType c1,ElemType c2){
//数据元素判定函数(平方关系,locateelem()调用的函数)
if(c1==c2*c2)
return true;
else
return false;
}
void dbl(ElemType &c){
//listtraverse()调用的另一个函数(元素值加倍)
c*=2;
}
void print1(ElemType &c){
//以十进制整型的格式输出元素的值(设c为 引用类型)
//此处的引用只是为了满足listtraverse函数复用的需要,而对于listtraverse函数的第二个参数中真正用到&的是dbl()函数
printf("%d ",c);
}
void main(){
SqList L;
ElemType e,e0;
status i;
int j,k;
InitList(L);//初始化线性表
printf("初始化L后,L.length=%d,L.listsize=%d,L.elem=%u\n",L.length,L.listsize,L.elem);
for(j=1;j<=5;j++)
i=listinsert(L,1,j);//在L的表头插入j
printf("在L的表头依次插入1~5后,*L.elem=");
for(j=1;j<=5;j++)
printf("%d ",*(L.elem+j-1));//依次输出表L中的元素
printf("\n调用listtraverse()函数,依次输出表L中的元素:");
listtraverse(L,print1);//依次对表L中的元素调用print1()函数(输出元素的值)
i=listempty(L);//检测表L是否为空
printf("L.length=%d(改变),L.listsize=%d(不变)",L.length,L.listsize);
printf("L.elem=%d(不变),L是否空?i=%d(1:是 0:否)",L.elem,i);
clearlist(L);//清空表l
i=listempty(L);//再次检测表l是否为空
printf("清空L后,L.length=%d,L.listsize=%d",L.length,L.listsize);
printf("L.elem=%d,l是否空?i=%d(1:是 0:否)",L.elem,i);
for(j=1;j<=10;j++)
listinsert(L,j,j);//在l的表尾插入j
printf("在l的表尾依次插入1~10后,l=");
listtraverse(L,print1);//依次输出表l中的元素
printf("L.length=%d,L.listsize=%d,L.elem=%u\n",L.length,L.listsize,L.elem);
listinsert(L,1,0);//在l的表头插入0,增加存储空间
printf("在l的表头插入0后,L.length=%d(改变),L.listsize==%d(改变),L.elem=%u(有可能改变)\n",L.length,L.listsize,L.elem);
getelem(L,5,e);//将元素表第5个元素的值赋给e
printf("第5个元素的值为%d\n",e);
for(j=10;j<=11;j++)
{
k=locateelem(L,j,equal);
if(k)//k不为0,表明有符合条件的元素
printf("第%d个元素的值为%d ",k,j);
else
printf(" 没有值为%d的元素\n",j);
}
for(j=3;j<=4;j++)//测试2个数据
{
k=locateelem(L,j,sq);//查找表l中与j的平方相等的元素,并将其位序赋给k
if(k)//k不为0,表明有符合条件的元素
printf("第%d个元素的值为%d的平方 ",k,j);
else
printf("没有值为%d的平方元素\n",j);
}
for(j=1;j<=2;j++)//测试头2个数据
{
getelem(L,j,e0);//将表l的第j个元素的值赋给e0
i=priorelem(L,e0,e);//求e0的前驱,如成功,将值赋给e
if(i==error)//操作失败
printf("元素%d无前驱 ",e0);
else
printf(" 元素%d的前驱为%d\n" ,e0,e);
}
for(j=listlength(L)-1;j<=listlength(L);j++)//测试最后2个数据
{
getelem(L,j,e0);//将表l中第j个元素的值赋给e0
i=nextelem(L,e0,e);//求e0的后继,如成功,将值赋给e
if(i==error)//操作失败
printf("元素%d无后继 ",e0);
else
printf("元素%d的后继为%d ",e0,e);
}
printf("\n");
k=listlength(L);//k为表长
for(j=k+1;j>=k;j--)
{
i=listdelete(L,j,e);//删除第j个数据
if(i==error)//表中不存在第j个数据
printf("删除第%d个元素失败 ",j);
else
printf("删除第%d个元素成功,其值为%d ",j,e);
}
listtraverse(L,dbl);//依次对元素调用dbl(),元素值乘以2
printf("l的元素值加倍后,l=");
listtraverse(L,print1);//依次输出表l中的元素
destroylist(L);//销毁表L
printf("销毁l后,L.length=%d,L.listsize=%d,L.elem=%u\n",L.length,L.listsize,L.elem);
}
输出结果
最后把关于线性表的12种基本操作的实现单独贴出来:
//顺序存储的线性表的基本操作12个,包括教材上的算法2.3~2.6
void InitList(SqList &L)
{
//操作结果:构造一个空的顺序线性表l
L.elem=(ElemType *)malloc(list_init_size*sizeof(ElemType));
if(!L.elem)//存储分配失败
exit(OVERFLOW);
L.length=0;//空表长度为0
L.listsize=list_init_size;//初始存储容量
}
status listinsert(SqList &L,int i,ElemType e){
//初始条件:顺序线性表l已存在,1≤i≤listlength(l)+1
//操作结果:在l中第i个位置之前插入新的数据元素e,l的长度加1
ElemType *newbase,*q,*p;
if(i<1||i>L.length+1)
return error;
if(L.length==L.listsize)//当前存储空间已满,增加分配,修改
{
newbase=(ElemType *)realloc(L.elem,(L.listsize+list_increment)*sizeof(ElemType));
if(!newbase)//存储分配失败
exit(OVERFLOW);
L.elem=newbase;//新基址赋给L.elem
L.listsize+=list_increment;//增加存储容量
}
q=L.elem+i-1;//q为插入位置
for(p=L.elem+L.length-1;p>=q;--p)//插入位置之后的元素后移(由表尾元素开始移)
*(p+1)=*p;
*q=e;//插入e
++L.length;//表长增1
return ok;
}
void listtraverse(SqList &L,void(*visit)(ElemType&)){
//初始条件:顺序线性表l已存在
//操作结果:依次对l的每个数据元素调用函数visit() visit()的形参加'&',表明可通过visit()改变元素的值
ElemType *p=L.elem;//p指向第一个元素
int i;
for(i=1;i<=L.length;i++)//从表l的第一个元素到最后1个元素
visit(*p++);//对每个数据元素调用visit()
printf("\n");
}
status listempty(SqList L){
//初始条件:顺序线性表l已存在
//操作结果:若l为空表,则返回true,否则返回false
if(L.length==0)
return true;
else
return false;
}
void clearlist(SqList &L){
//初始条件:顺序线性表l已存在。操作结果:将l重置为空表
L.length=0;
}
status getelem(SqList L,int i,ElemType &e){
//初始条件:顺序线性表l已存在,1≤i≤listlength(l)
//操作结果:用e返回l中第i个数据元素的值
if(i<1||i>L.length)//i不在表l的范围之内
return error;
ElemType *p;
p=L.elem+i-1;
e=*p;//将表l的第i个元素的值赋给e
return ok;
}
int locateelem(SqList L,ElemType e,status (*compare)(ElemType,ElemType)){
//初始条件:顺序线性表l已存在,compare()是数据元素判定函数(满足为1,否则为0)
//操作结果:返回l中第1个与e满足关系compare()的数据元素的位序,若这样的数据元素不存在,则返回值为0
int i=1;//i的初值为第1个元素的位序
ElemType *p=L.elem;//p的初值为第一个元素的存储位置
while(i<=L.length && !(compare(*p++,e)))//i未超出表的范围且未找到满足关系的数据元素
++i;//继续向后找
if(i<=L.length)//找到满足关系的数据元素
return i;//返回其位序
else
return 0;
}
status priorelem(SqList L,ElemType cur_e,ElemType &pre_e){
//初始条件:顺序线性表l已存在
//操作结果:若cur_e是l的数据元素,且不是第一个,则用pre_e返回它的前驱;否则操作失败,pre_e无定义
int i=2;//从第2个元素开始
ElemType *p=L.elem+1;//p指向第2个元素
while(i<=L.length&&*p!=cur_e)//i未超出表的范围且未找到值为cur_e的元素
{
p++;//p指向下一个元素
i++;//计数加1
}
if(i>L.length)//到表结束处还未找到值为cur_e的元素
return error;//操作失败
else
{
pre_e=*--p;//p指向前一个元素(cur_e的前驱),将所指元素的值赋给pre_e
return ok;//操作成功
}
}
int listlength(SqList L){
//初始条件:顺序线性表l已存在
//操作结果:返回l中数据元素的个数
return L.length;
}
int nextelem(SqList L,ElemType cur_e,ElemType &next_e){
//初始条件:顺序线性表l已存在
//操作结果:若cur_e是l的数据元素,且不是最后一个,则用next_e返回它的后继,否则操作失败,next_e无定义
int i=1;//从第1个元素开始
ElemType *p=L.elem;//p指向第1个元素
while(i<L.length&&*p!=cur_e){//i未到表尾且未找到值为cur_e的元素
i++;
p++;
}
if(i==L.length)
return error;//到表尾的前一个元素还未找到值为cur_e的元素
else
{
next_e= * ++p;//p指向下一个元素(cur_e的后继),将所指元素的值赋给next_e
return ok;//操作成功
}
}
status listdelete(SqList L,int i,ElemType &e){
//初始条件:顺序线性表l已存在,1≤i≤listlength(l)
//操作结果:删除l的第i个数据元素,并用e返回其值,l的长度减1
ElemType *p,*q;
if(i<1||i>L.length)
return error;
p=L.elem+i-1;//被删除元素的位置
e=*p;//被删除元素的值赋给e
q=L.elem+L.length-1;//q为表尾元素的位置
for(++p;p<=q;++p)//被删除元素之后的元素左移(由被删除元素的后继元素开始移)
*(p-1)=*p;
L.length--;//表长减1
return ok;
}
void destroylist(SqList &L){
//初始条件:顺序线性表l已存在
//操作结果:销毁顺序线性表l
free(L.elem);//释放L.elem所指的存储空间
L.elem=NULL;//L.elem不再指向任何存储单元
L.length=0;
L.listsize=0;
}