线性表的类型定义
线性表(linear_list)是最常用且最简单的一种数据结构。简言之,一个线性表是n个数据元素的有限序列。至于每个数据元素的具体含义,在不同的情况下各不相同,它可以是一个数或一个符号,也可以是一页书,甚至其他更复杂的信息。在稍复杂的线性表中,一个数据元素可以由若干个数据项(item)组成。在这种情况下,常把数据元素称为记录(record),含有大量记录的线性表又称文件(file)。
线性表是一个相当灵活的数据结构,它的长度可根据需要增长或缩短,即对线性表的数据元素不仅可以进行访问,还可进行插入和删除等。
抽象数据类型线性表的定义如下:
ADT List {
数据对象:D={ ai|ai∈ElemSet,i=1,2,…,n, n≥0}
数据关系:R1={<ai-1,ai>|ai-1,ai∈D,i=2,…,n}
基本操作:
InitList( &L )
操作结果:构造一个空的线性表L。
DestroyList( &L )
初始条件:线性表L已存在。
操作结果:销毁线性表L。
ClearList( &L )
初始条件:线性表L已存在。
操作结果:将L重置为空表。
ListEmpty( L )
初始条件:线性表L已存在。
操作结果:若L为空表,则返回TRUE,否则返回FALSE。
ListLength( L )
初始条件:线性表L已存在。
操作结果:返回L中数据元素个数。
GetElem( L, i, &e )
初始条件:线性表L已存在,1≤i≤ListLength(L)。
操作结果:用e返回L中第i个数据元素的值。
LocateElem( L, e, compare() )
初始条件:线性表L已存在,compare()是数据元素判定函数。
操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。若这样的数据元素不存在,则返回0。
PriorElem( L, cur_e, &pre_e )
初始条件:线性表L已存在。
操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,否则操作失败,pre_e无定义。
NextElem( L, cur_e, &next_e)
初始条件:线性表L已存在。
操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继,否则操作失败,next_e无定义。
ListInsert( &L, i, e)
初始条件:线性表已存在,1≤i≤ListLength(L)+1。
操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1。
ListDelete( &L, i, &e)
初始条件:线性表L已存在且非空,1≤i≤ListLength(L)+1。
操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1。
ListTraverse( L, visit() )
初始条件:线性表L已存在。
操作结果:依次对L的每个数据元素调用函数visit()。一旦visit()失败,则操作失败。
} ADT List
顺序线性表的表示和实现
线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素。线性表第一个数据元素ai通常称做线性表的起始位置或基地址。
只要确定了存储线性表的起始位置,线性表中任一数据元素都可随机存取,所以线性表的顺序存储结构是一种随机存储的存储结构。
// - - - - - 线性表的动态分配顺序存储结构 - - - - -
#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量
#define LISTINCREMENT 10 //线性表存储空间的分配增量
typedef struct{
ElemType *elem; //存储空间基址
int length; //当前长度
int listsize; //当前分配的存储容量(以sizeof(ElemType)为单位)
} SqList;
接口代码实现:
// &为引用参数,并非c语言语法,应用时把.c后缀改为.cpp即可,也可自行改为指针*。
Status InitList_Sq(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; //初始存储容量
return OK;
}
Status ListInsert_Sq(SqList &L, int i, ElemType e){
//顺序线性表L中第i个位置之前插入新的元素e,
//i的合法值为1≤i≤ListLength_Sq(L)+1
ElemType*newbase;
ElemType*q,*p;
if(i<1||i>L.length+1) return ERROR; //i值不合法
if(L.length>=L.listsize){ //当前存储空间已满,增加分配
newbase=(ElemType*)realloc(L.elem, (L.listsize+LISTINCREMENT)*sizeof(ElemType));
if(!newbase) exit(OVERFLOW);//存储空间分配失败
L.elem=newbase; //新基址
L.listsize+=LISTINCREMENT;//增加存储容量
}
q=&(L.elem[i-1]);
for(p=&(L.elem[L.length-1]);p>=q;--p)
*(p+1)=*p; //插入位置及之后的元素右移
*q=e; //插入e
++L.length; //表长增1
return OK;
}
Status ListDelete_Sq(SqList &L, int i, ElemType &e){
//在顺序线性表L中删除第i个元素,并用e返回其值
//i的合法值为1≤i≤ListLength_Sq(L)
ElemType*q,*p;
if((i<1)||(i>L.length)) return ERROR; //i值不合法
p=&(L.elem[i-1]); //p为被删除元素的位置
e=*p; //被删除元素的值赋给e
q=L.elem+L.length-1;//表尾元素的位置
for(++p; p<=q; ++p)
*(p-1)=*p; //被删除元素之后的元素左移
--L.length; //表长减1
return OK;
}
Status Append_Sq(SqList &L, ElemType e) { // 在顺序表L表尾添加元素e
ElemType*newbase;
if(L.length>=L.listsize){
newbase=(ElemType*)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType));
if(NULL==newbase)return OVERFLOW;
L.elem=newbase;
L.listsize+=LISTINCREMENT;
}
L.elem[L.length++]=e;
return OK;
}
Status DeleteLast_Sq(SqList &L, ElemType &e) {
// 删除顺序表L的表尾元素,并用参数e返回其值
if(0==L.length)return ERROR;
e=L.elem[L.length-1];
--L.length;
return OK;
}
int LocateElem_Sq(SqList L, ElemType e, Status(*compare)(ElemType, ElemType)){
//在顺序线性表L中查找第1个值与e满足compare()的元素的位序
//若找到,则返回其在L中的位序,否则返回0
int i=1; //i的初值为第1个元素的位序
ElemType*p=L.elem; //p的初值为第1个元素的存储位置
while(i<=L.length&&!(*compare)(*p++,e)) ++i;
if(i<=L.length) return i;
else return 0;
}
Status NextElem_Sq(SqList L, ElemType cur_e, ElemType &next_e){
ElemType*p=L.elem;
int i=1;
while(i<=L.length&&*p++!=cur_e) ++i;
if(i>=L.length)
return ERROR;
else{
next_e=*p;
return TRUE;
}
}
Status PriorElem_Sq(SqList L, ElemType cur_e, ElemType &pre_e){
ElemType*p=L.elem;
int i=2;
if(*p==cur_e)
return ERROR;
else{
while(i<=L.length&&*++p!=cur_e) ++i;
if(i<=L.length)
pre_e=*--p;
else
return ERROR;
}
return TRUE;
}
void MergeList_Sq(SqList La, SqList Lb, SqList &Lc){
//已知顺序线性表La和Lb的元素按值非递减排列
//归并La和Lb得到新的顺序线性表Lc,Lc的元素也按值非递减排列
ElemType *pa,*pb,*pc;
ElemType *pa_last,*pb_last;
pa=La.elem; pb=Lb.elem;
Lc.listsize=Lc.length=La.length+Lb.length;
pc=Lc.elem=(ElemType*)malloc(Lc.listsize*sizeof(ElemType));
if(!Lc.elem) exit(OVERFLOW); //存储分配失败
pa_last=La.elem+La.length-1;
pb_last=Lb.elem+Lb.length-1;
while(pa<=pa_last&&pb<=pb_last){//归并
if(*pa<=*pb) *pc++=*pa++;
else *pc++=*pb++;
}
while(pa<=pa_last) *pc++=*pa++; //插入La的剩余元素
while(pb<=pb_last) *pc++=*pb++; //插入Lb的剩余元素
}
Status DestroyList_Sq(SqList &L){ // 销毁顺序表L
if(L.elem!=NULL)
free(L.elem);
L.elem=NULL;
return TRUE;
}
Status ListTraverse_Sq(SqList L, Status(*visit)(ElemType e)){
int i=0;
while(i<L.length)
{
(*visit)(L.elem[i]);
i++;
}
return OK;
}
Status GetElem_Sq(SqList L, int i, ElemType &e){
// 用e返回顺序表L中第 i个元素的值1≤i≤L.length
if(i<=L.length&&i>=1){
e=L.elem[i-1];
return TRUE;
}else{
return FALSE;
}
}
int ListLength_Sq(SqList L){
return L.length;
}
Status ClearList_Sq(SqList &L){ // 将顺序表L清空
L.length=0;
return OK;
}
Status ListEmpty_Sq(SqList L){
if(L.length==0)
return TRUE;
else
return FALSE;
}
main文件(测试接口)
#include"SqList.h"
Status printElement(ElemType e);
Status equalPrior(ElemType x, ElemType y);
char get_choice(void);
int get_ElemType(void);
char get_first(void);
int main(void){
SqList L;
ElemType e,x;
InitList_Sq(L);
int i;
char choice;
Status (* visit)(ElemType e);
printf("\n初始化顺序表L,插入数据A,B,C,D,E,F,如下:\n");
Append_Sq(L,1);
Append_Sq(L,3);
Append_Sq(L,5);
Append_Sq(L,7);
Append_Sq(L,9);
Append_Sq(L,11);
visit=printElement; //取函数地址
ListTraverse_Sq(L,visit);
while((choice=get_choice())!='q')
{
switch(choice)
{
case 'a':DestroyList_Sq(L);
printf("成功销毁表。\n");
system("pause");
exit(0);
case 'b':if(ListEmpty_Sq(L)==OK)
printf("线性表为空.\n");
else
printf("线性表不为空.\n");
break;
case 'c':printf("请输入你要查找的位置:");
i = get_ElemType();
if(GetElem_Sq(L, i, e)==OK)
printf("第%d个位置的数据为 %d.\n",i,e);
else
printf("不存在该位置元素.\n");
break;
case 'd':ClearList_Sq(L);
printf("成功清空表!\n");
break;
case 'e':printf("请输入你要查找的元素:");
x = get_ElemType();
if(PriorElem_Sq(L,x,e)==OK)
printf("元素%d的前一个数据为 %d.\n",x,e);
else
printf("元素不存在.\n");
break;
case 'f':printf("请输入你要查找的元素:");
x = get_ElemType();
if(NextElem_Sq(L,x,e)==OK)
printf("元素%d的后一个数据为 %d.\n",x,e);
else
printf("元素不存在.\n");
break;
case 'g':
printf("线性表的长度为 %d.\n",ListLength_Sq(L));
break;
case 'h':printf("请输入你要插入的位置:");
i = get_ElemType();
printf("请输入你要插入的元素:");
e = get_ElemType();
if(ListInsert_Sq(L,i,e)){
printf("插入成功!\n");
printf("此时表内数据为:\n");
ListTraverse_Sq(L, visit);
}else
printf("插入失败.\n");
break;
case 'i':printf("请输入你要删除元素的位置:");
i = get_ElemType();
if(ListDelete_Sq(L,i,e)){
printf("删除元素 %d 成功!\n",e);
printf("此时表内数据为:\n");
ListTraverse_Sq(L, visit);
}else
printf("删除失败.\n");
break;
case 'j': printf("此时表内数据为:\n");
ListTraverse_Sq(L, visit);
}
}
printf("Bye.\n");
getchar();
getchar();
return 0;
}
char get_choice(void)
{
char ch;
printf("\n");
for(int i=0;i<60;i++)
printf("=");
printf("\n");
printf("Enter the operation of your choice:\n");
printf("%-36s%s\n","a.销毁线性表","b.表的判空");
printf("%-36s%s\n","c.查找对应位置元素","d.清空线性表");
printf("%-36s%s\n","e.查找前一个元素","f.查找后一个元素");
printf("%-36s%s\n","g.输出表的长度","h.插入元素");
printf("%-36s%s\n","i.删除元素","j.遍历线性表");
printf("q.quit\n");
printf("\n");
for(int k=0;k<60;k++)
printf("=");
printf("\n");
ch=get_first();
while(ch!='a'&&ch!='b'&&ch!='c'&&ch!='d'
&&ch!='e'&&ch!='f'&&ch!='g'&&ch!='h'
&&ch!='i'&&ch!='j'&&ch!='q')
{
printf("Please enter a ~ j or q.\n");
ch=get_first();
}
return ch;
}
int get_ElemType(void)
{
ElemType input;
char ch;
while(scanf("%d",&input)!=1)
{
while((ch=getchar())!='\n')
putchar(ch);
printf(" is not a ElemType.\n");
printf("Please enter a ElemType,such as 1 , 2 or 3: ");
}
while(getchar()!='\n')
continue;
return input;
}
char get_first(void)
{
char ch;
ch=getchar();
while(getchar()!='\n')
continue;
return ch;
}
Status printElement(ElemType e){
printf("%d ",e);
return OK;
}
Status equalPrior(ElemType x, ElemType y) { // compare函数
return x==y;
}