目录
一 、线性表定义
二、线性表的顺序表示简介
三、开发环境 Dev-c++
四、常用操作的实现
1.初始化线性表 2.销毁线性表 3.清空线性表 4.判断是否为空表 5.线性表元素个数 6.取相应位置上元素
7.匹配元素 8.返回前驱元素 9.返回后继元素 10.插入元素 11.删除元素 12.输出元素 13.主函数
五、总结
六、后记
线性表是最常用且最简单的一种数据结构,是一个n个数据元素的有限序列。
(1)存在唯一的一个被称作“第一个”的数据元素
(2)存在唯一的一个被称作“最后一个”的数据元素
(3)除第一个之外,集合中的每个元素均只有一个直接前驱
(4)除最后一个之外,集合中的每个元素均只有一个直接后继
线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素
这里也就是说逻辑上相邻的两个元素在物理存储上也是相邻的。
如图所示,只要我们确定了线性表的首地址,那么我们就可以随机存取表中任一数据元素 ,对于int数据类型来说,是以4个字节存储的,线性表中的元素下表每增一,存储地址就加4,如此想要访问第三个元素的存储位置,则计算公式为 &a[2]=&a[0]+2*4
所以线性表的顺序存储结构是一种随机存取的存储结构
由于高级程序设计语言中的数组类型也有随机存取的特性,因此,通常都用数组来描述数据结构中的顺序存取结构
#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配增量
#define LISTTNCREMENT 10 //分配增量。空间不足时,增加存储10个元素的空间
typedef struct {
Element * elem; //存储空间基址
int length; //当前长度
int listsize; //当前分配的存储容量,以sizeof(Element) 为单位
}SqList; //这个结构体的别名就是SqList
Dev-C++ 下载链接
提取码:3f00
结构体、头文件以及相关的宏定义
#include
#include
#include
#include
//函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1 //不可行,不能操作
#define OVERFLOW -2 //溢出
#define EMPTY -3 //表为空
#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配增量
#define LISTTNCREMENT 10 //分配增量。空间不足时,增加存储10个元素的空间
typedef int Status; //int 的别名,其值是函数结果状态代码
typedef struct {
int * elem; //存储空间基址
int length; //当前长度
int listsize; //当前分配的存储容量,以sizeof(int) 为单位
}SqList; //这个结构体的别名就是SqList
InitList (& L) //操作结果:构造一个空的线性表 L
Status InitList (SqList & L)//引用类型,关于引用可以看我博客中的简单介绍
{
L.elem=(int *)malloc(LIST_INIT_SIZE*sizeof(int));//elem指向这个新开辟的空间,可以看成数组名
if(! L.elem) return ERROR;//分配失败退出
L.length=0; //空表长度为0
L.listsize=LIST_INIT_SIZE;//初始存储容量
return OK;
}
DestroyList(& L) //初始条件:线性表L已存在 操作结果:销毁线性表L。
Status DestroyList(SqList & L)//初始条件:线性表L已存在 操作结果:销毁线性表L。
{
free(L.elem);//释放空间
L.elem = NULL;
L.length=0;
L.listsize = 0;
return OK;
}
ClearList( &L ) //初始条件:线性表L已存在。操作结果:将L重置为空表。
Status ClearList( SqList & L )//初始条件:线性表L已存在。操作结果:将L重置为空表。
{
if(1){//不管是否为空都清空
L.length=0;
return OK;
}
}
ListEmpty( L ) //初始条件:线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE
Status ListEmpty(SqList L ) //初始条件:线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE
{
if(L.length == 0){
return TRUE;
}
return FALSE;
}
ListLength( L ) //初始条件:线性表L已存在。操作结果:返回L中数据元素个数。
Status ListLength( SqList L )//初始条件:线性表L已存在。操作结果:返回L中数据元素个数。
{
return L.length;
}
GetElem( L, i, &e ) //初始条件:线性表L已存在,1≤i≤ListLength(L)。操作结果:用e返回L中第i个数据元素的值。
Status GetElem( SqList L, int i, int &e )//初始条件:线性表L已存在,1≤i≤ListLength(L)。操作结果:用e返回L中第i个数据元素的值。
{
if( L.elem == NULL)//线性表还未初始化
return OVERFLOW;
if(L.length==0)//线性表为空
return EMPTY;
if(i<1 || i>L.length){//位置不合法
return ERROR;
}
e = L.elem[i-1];
return OK;
}
LocateElem( L, e, compare() )
/* 初始条件:线性表L已存在,compare()是数据元素判定函数。
操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。若这样的数据元素不存在,则返回值为0。
*/
Status LocateElem( SqList L, int e) //返回第一个大于 e元素的位置
/*初始条件:线性表L已存在,compare()是数据元素判定函数。
操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。
若这样的数据元素不存在,则返回值为0。*/
{
for(int i=0;i e)
return i+1;
}
return ERROR;
}
PriorElem( L, cur_e, &pre_e )
/* 初始条件:线性表L已存在。
操作结果:若cur.e是L的数据元素,且不是第一个,则用pre. e返回它的前驱,否则操作 失败,pre_e无定义。 */
Status PriorElem( SqList L, int cur_e,int &pre_e ) /* 初始条件:线性表L已存在。
操作结果:若cur.e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,否则操作失败,pre_e无定义。 */
{
if( L.elem == NULL)//线性表还未初始化
return OVERFLOW;
if(L.length==0)//线性表为空
return EMPTY;
for(int i=1;i
NextElem( L, cur_e, &next_e )
/* 初始条件:线性表L已存在。
操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继,否则操作失败,next. e无定义。
*/
Status NextElem( SqList L , int cur_e,int &next_e )/*初始条件:线性表L已存在。
操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继,否则操作失败,next. e无定义。
*/
{
if( L.elem == NULL)//线性表还未初始化
return OVERFLOW;
if(L.length==0)//线性表为空
return EMPTY;
for(int i=0;i
ListInsert( &L, i, e ) /* 初始条件:线性表L已存在,1≤i≤ListLength(L) + 1.
操作结果:在L中第i个位置之前插人新的数据元素e,L的长度加1。*/
Status ListInsert( SqList &L, int i,int e ) /*初始条件:线性表L已存在,1≤i≤ListLength(L) + 1.
操作结果:在L中第i个位置之前插人新的数据元素e,L的长度加1。*/
{
if(i <1 || i>L.length+1) return ERROR;
if(L.length >=L.listsize){//存储空间已满
int *newbase=(int *)realloc(L.elem,(L.listsize+LISTTNCREMENT)*sizeof(int)); //重新分配空间
if(! newbase) return ERROR;//存储分配失败
L.elem=newbase;
L.listsize += LISTTNCREMENT;//增加存储容量
}
int *q=&(L.elem[i-1]); //q为插入位置
for(int *p= &(L.elem[L.length-1]);p>=q;--p ) *(p+1)=*p;
//插入位置及之后的元素后移
*q=e;//插入e
++L.length; //表长加一
return OK;
}
ListDelete(&L,i, &e) /* 初始条件:线性表L已存在且非空,1≤i≤listLength(L)。
操作结果:删除L的第i个数据元素,并用e返回其值,工的长度减1。*/
Status ListDelete(SqList & L,int i, int &e) //初始条件:线性表L已存在且非空,1≤i≤listLength(L)
//操作结果:删除L的第i个数据元素,并用e返回其值,表的长度减1
{
if(i <1 || i>L.length)
return ERROR;
int* p=&(L.elem[i-1]);
e=*p; //被删除的元素值赋给e
int* q=L.elem+L.length-1;//表尾元素的位置
for(++p;p<=q;++p) *(p-1)=*p;//被删除元素之后的元素前移
--L.length; //表长减一
return OK;
}
ListTraverse(L) /* 初始条件:线性表L已存在。
操作结果:输出线性表的每个元素*/
void ListTraverse(SqList L )
{
for(int i=0;i
int main(){
int num=0;//菜单选项
int i=0,e=0,k=-10;//函数的参数
SqList L;
L.elem=NULL;//线性表开始为空,需要初始化
while(true)
{
printf("\t*************************************\n");
printf("\t*****\t1.初始化线性表\t\t*****\n");
printf("\t*****\t2.销毁线性表\t\t*****\n");
printf("\t*****\t3.清空线性表\t\t*****\n");
printf("\t*****\t4.判断线性表是否为空\t*****\n");
printf("\t*****\t5.线性表元素个数\t*****\n");
printf("\t*****\t6.取相应位置上元素\t*****\n");
printf("\t*****\t7.匹配元素\t\t*****\n");
printf("\t*****\t8.返回前驱元素\t\t*****\n");
printf("\t*****\t9.返回后继元素\t\t*****\n");
printf("\t*****\t10.插入元素\t\t*****\n");
printf("\t*****\t11.删除元素\t\t*****\n");
printf("\t*****\t12.输出线性表\t\t*****\n");
printf("\t*****\t13.退出系统\t\t*****\n");
printf("\t*************************************\n");
printf("请选择一个操作:");
scanf("%d",&num);
switch(num){
case 1:
if(InitList(L)) printf("初始化成功 ! \n");
break;
case 2:
if(DestroyList(L)) printf("销毁成功 ! \n");
break;
case 3:
if(ClearList( L )) printf("清空成功 ! \n");
break;
case 4:
if(ListEmpty( L )) printf("表为空 ! \n");
else printf("表不为空 ! \n");
break;
case 5:
printf("元素个数为:%d\n",ListLength( L ));
break;
case 6:
printf("请输入要查找元素的位置:");
scanf("%d",&i);
if(GetElem( L, i, e )==1) printf("第%d个元素为:%d\n",i,e);
else if (GetElem( L, i, e )==-3) printf("表为空,请先添加元素!\n ");
else if (GetElem( L, i, e )==0) printf("位置不正确!\n ");
else printf("线性表还未初始化,请初始化!\n ");
break;
case 7 :
printf("请输入要匹配的元素(返回第一个大于您输入的元素位置):");
scanf("%d",&e);
if(LocateElem( L, e)) printf("第一个大于%d的是第%d个元素\n",e,LocateElem( L, e));
else printf("这样的元素不存在!\n ");
break;
case 8:
printf("请输入要查找前驱的元素:");
scanf("%d",&e);
PriorElem( L,e,k);
if(PriorElem( L,e,k)==-2)printf("线性表还未初始化,请初始化!\n ");
else if(PriorElem( L,e,k)==-3)printf("表为空,请先添加元素!\n ");
else if(k!=-10) printf("元素%d的前驱元素是%d\n",e,L.elem[k]);
else printf("操作失败\n"); k=-10;
break;
case 9:
printf("请输入要查找后继的元素:");
scanf("%d",&e);
NextElem( L , e,k);
if( NextElem( L , e,k) ==-2)printf("线性表还未初始化,请初始化!\n ");
else if(NextElem( L , e,k)==-3)printf("表为空,请先添加元素!\n ");
else if(k!=-10) printf("元素%d的后继元素是%d\n",e,L.elem[k]);
else printf("操作失败\n"); k=-10;
break;
case 10:
printf("请输入插入元素的位置:");
scanf("%d",&i);
printf("请输入插入元素的值:");
scanf("%d",&e);
if(ListInsert( L, i, e )) printf("成功插入一个元素!\n");
else printf("请重新选择插入位置!\n");
break;
case 11:
printf("请输入删除元素的位置:");
scanf("%d",&i);
if(ListDelete( L, i, e )) printf("删除元素%d成功!\n",e);
else printf("请重新选择删除元素的位置!\n");
break;
case 12:
ListTraverse( L );
break;
case 13:
exit(0);
break;
default:
if(InitList(L)) printf("初始化成功 ! \n");
break;
}
printf("Press Enter to continue..."); getch();system("cls");
}
return 0;
}
1.线性表的功能看似很多,其实只要耐下心来好好分析,即可写出。需要提前复习结构体、指针、引用相关知识。
2.存储空间不够时要进行申请空间,用完后要进行释放。常用函数 malloc 、 realloc 、 free
3.插入和删除元素要记得判断位置是否合法,特别是插入还要考虑存储空间的大小,以及相关的实现步骤。
这里的顺序表示是用数组来实现的,上述代码是一个完整体,全部复制到C++源文件中即可运行。其中用到了指针类型和引用类型,对于二者不太清晰的同学可以看我的另一篇博客,或者自己看相关资料,关于上述主函数中的菜单栏,请大家按照先初始化再进行相关操作的顺序,不然可能会有一些问题,因为我没有严格来考虑各种情况的发生,比如没初始化就进行插入,匹配等等情况,但是正常操作不会影响。如果带来不便,还望谅解,另外有什么问题可以留言,我会第一时间来进行有关问题的说明。