/* 顺序表存储结构容易实现随机存取线性表的第i 个数据元素的操作,但在实现插入、 删除的操作时要移动大量数据元素,所以,它适用于数据相对稳定的线性表,如职工工资 表、学生学籍表等。 c2-1.h 是动态分配的顺序表存储结构,bo2-1.cpp 是基于顺序表的基本操作。由于 C++函数可重载,故去掉bo2-1.cpp 中算法2.3 等函数名中表示存储类型的后缀_Sq。 c2-1.h 不采用固定数组作为线性表的存储结构,而采用动态分配的存储结构,这样可以合 理地利用空间,使长表占用的存储空间多, 短表占用的存储空间少。这些可通过 bo2-1.cpp 中基本操作函数ListInsert()和图24 清楚看出。 */
// c2-1.h 线性表的动态分配顺序存储结构(见图2.1) #define LIST_INIT_SIZE 10 // 线性表存储空间的初始分配量 #define LIST_INCREMENT 2 // 线性表存储空间的分配增量 struct SqList { ElemType *elem; // 存储空间基址 int length; // 当前长度 int listsize; // 当前分配的存储容量(以sizeof(ElemType)为单位) };
// bo2-1.cpp 顺序表示的线性表(存储结构由c2-1.h定义)的基本操作(12个),包括算法2.3,2.4,2.5,2.6 void InitList(SqList &L) // 算法2.3 { // 操作结果:构造一个空的顺序线性表L(见图2.2) L.elem=(ElemType*)malloc(LIST_INIT_SIZE*sizeof(ElemType)); if(!L.elem) exit(OVERFLOW); // 存储分配失败 L.length=0; // 空表长度为0 L.listsize=LIST_INIT_SIZE; // 初始存储容量 } void DestroyList(SqList &L) { // 初始条件:顺序线性表L已存在。操作结果:销毁顺序线性表L(见图2.3) free(L.elem); L.elem=NULL; L.length=0; L.listsize=0; } void ClearList(SqList &L) { // 初始条件:顺序线性表L已存在。操作结果:将L重置为空表 L.length=0; } Status ListEmpty(SqList L) { // 初始条件:顺序线性表L已存在。操作结果:若L为空表,则返回TRUE;否则返回FALSE if(L.length==0) return TRUE; else return FALSE; } int ListLength(SqList L) { // 初始条件:顺序线性表L已存在。操作结果:返回L中数据元素的个数 return L.length; } Status GetElem(SqList L,int i,ElemType &e) { // 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)。操作结果:用e返回L中第i个数据元素的值 if(i<1||i>L.length) return ERROR; e=*(L.elem+i-1); return OK; } int LocateElem(SqList L,ElemType e,Status(*compare)(ElemType,ElemType)) { // 初始条件:顺序线性表L已存在,compare()是数据元素判定函数(满足为1,否则为0) // 操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。 // 若这样的数据元素不存在,则返回值为0。算法2.6 ElemType *p; int i=1; // i的初值为第1个元素的位序 p=L.elem; // p的初值为第1个元素的存储位置 while(i<=L.length&&!compare(*p++,e)) ++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; ElemType *p=L.elem+1; while(i<=L.length&&*p!=cur_e) { p++; i++; } if(i>L.length) return INFEASIBLE; // 操作失败 else { pre_e=*--p; return OK; } } Status NextElem(SqList L,ElemType cur_e,ElemType &next_e) { // 初始条件:顺序线性表L已存在 // 操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继; // 否则操作失败,next_e无定义 int i=1; ElemType *p=L.elem; while(i<L.length&&*p!=cur_e) { i++; p++; } if(i==L.length) return INFEASIBLE; // 操作失败 else { next_e=*++p; return OK; } } Status ListInsert(SqList &L,int i,ElemType e) // 算法2.4 { // 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)+1 // 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1(见图2.4) ElemType *newbase,*q,*p; if(i<1||i>L.length+1) // i值不合法 return ERROR; if(L.length>=L.listsize) // 当前存储空间已满,增加分配 { if(!(newbase=(ElemType *)realloc(L.elem,(L.listsize+LIST_INCREMENT)*sizeof(ElemType)))) exit(OVERFLOW); // 存储分配失败 L.elem=newbase; // 新基址 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; } Status ListDelete(SqList &L,int i,ElemType &e) // 算法2.5 { // 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) // 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1(见图2.5) ElemType *p,*q; if(i<1||i>L.length) // i值不合法 return ERROR; 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; } void ListTraverse(SqList L,void(*vi)(ElemType&)) { // 初始条件:顺序线性表L已存在 // 操作结果:依次对L的每个数据元素调用函数vi() // vi()的形参加′&′,表明可通过调用vi()改变元素的值 ElemType *p; int i; p=L.elem; for(i=1;i<=L.length;i++) vi(*p++); printf(" "); }
// func2-3.cpp 几个常用的函数 Status equal(ElemType c1,ElemType c2) { // 判断是否相等的函数 if(c1==c2) return TRUE; else return FALSE; } int comp(ElemType a,ElemType b) { // 根据a<、=或>b,分别返回-1、0或1 if(a==b) return 0; else return (a-b)/abs(a-b); } void print(ElemType c) { printf("%d ",c); } void print2(ElemType c) { printf("%c ",c); } void print1(ElemType &c) { printf("%d ",c); }
// main2-1.cpp 检验bo2-1.cpp的主程序 #include"c1.h" typedef int ElemType; #include"c2-1.h" #include"bo2-1.cpp" #include"func2-3.cpp" // 包括equal()、comp()、print()、print2()和print1()函数 Status sq(ElemType c1,ElemType c2) { // 数据元素判定函数(平方关系),LocateElem()调用的函数 if(c1==c2*c2) return TRUE; else return FALSE; } void dbl(ElemType &c) { // ListTraverse()调用的另一函数(元素值加倍) c*=2; } void main() { SqList L; ElemType e,e0; Status i; int j,k; InitList(L); printf("初始化L后:L.elem=%u L.length=%d L.listsize=%d ",L.elem,L.length,L.listsize); for(j=1;j<=5;j++) i=ListInsert(L,1,j); printf("在L的表头依次插入1~5后:*L.elem="); for(j=1;j<=5;j++) cout<<*(L.elem+j-1)<<""; cout<<endl; printf("L.elem=%u L.length=%d L.listsize=%d ",L.elem,L.length,L.listsize); i=ListEmpty(L); printf("L是否空:i=%d(1:是0:否) ",i); ClearList(L); printf("清空L后:L.elem=%u L.length=%d L.listsize=%d ",L.elem,L.length,L.listsize); i=ListEmpty(L); printf("L是否空:i=%d(1:是0:否) ",i); for(j=1;j<=10;j++) ListInsert(L,j,j); printf("在L的表尾依次插入1~10后:*L.elem="); for(j=1;j<=10;j++) cout<<*(L.elem+j-1)<<""; cout<<endl; printf("L.elem=%u L.length=%d L.listsize=%d ",L.elem,L.length,L.listsize); ListInsert(L,1,0); printf("在L的表头插入0后:*L.elem="); for(j=1;j<=ListLength(L);j++) // ListLength(L)为元素个数 cout<<*(L.elem+j-1)<<""; cout<<endl; printf("L.elem=%u(有可能改变) L.length=%d(改变) L.listsize=%d(改变) ",L.elem,L.length, L.listsize); GetElem(L,5,e); printf("第5个元素的值为%d ",e); for(j=10;j<=11;j++) { k=LocateElem(L,j,equal); if(k) // k不为0,表明有符合条件的元素,且其位序为k printf("第%d个元素的值为%d ",k,j); else printf("没有值为%d的元素 ",j); } for(j=3;j<=4;j++) { k=LocateElem(L,j,sq); if(k) // k不为0,表明有符合条件的元素,且其位序为k printf("第%d个元素的值为%d的平方 ",k,j); else printf("没有值为%d的平方的元素 ",j); } for(j=1;j<=2;j++) // 测试头两个数据 { GetElem(L,j,e0); // 把第j个数据赋给e0 i=PriorElem(L,e0,e); // 求e0的前驱 if(i==INFEASIBLE) printf("元素%d无前驱 ",e0); else printf("元素%d的前驱为%d ",e0,e); } for(j=ListLength(L)-1;j<=ListLength(L);j++) // 最后两个数据 { GetElem(L,j,e0); // 把第j个数据赋给e0 i=NextElem(L,e0,e); // 求e0的后继 if(i==INFEASIBLE) printf("元素%d无后继 ",e0); else printf("元素%d的后继为%d ",e0,e); } k=ListLength(L); // k为表长 for(j=k+1;j>=k;j--) { i=ListDelete(L,j,e); // 删除第j个数据 if(i==ERROR) printf("删除第%d个元素失败 ",j); else printf("删除第%d个元素成功,其值为%d ",j,e); } printf("依次输出L的元素:"); ListTraverse(L,print1); // 依次对元素调用print1(),输出元素的值 printf("L的元素值加倍后:"); ListTraverse(L,dbl); // 依次对元素调用dbl(),元素值乘2 ListTraverse(L,print1); DestroyList(L); printf("销毁L后:L.elem=%u L.length=%d L.listsize=%d ",L.elem,L.length,L.listsize); }
以下是运行的结果代码:
/* 初始化L后:L.elem=3615192 L.length=0 L.listsize=10 在L的表头依次插入1~5后:*L.elem=54321 L.elem=3615192 L.length=5 L.listsize=10 L是否空:i=0(1:是0:否) 清空L后:L.elem=3615192 L.length=0 L.listsize=10 L是否空:i=1(1:是0:否) 在L的表尾依次插入1~10后:*L.elem=12345678910 L.elem=3615192 L.length=10 L.listsize=10 在L的表头插入0后:*L.elem=012345678910 L.elem=3606792(有可能改变) L.length=11(改变) L.listsize=12(改变) 第5个元素的值为4 第11个元素的值为10 没有值为11的元素 第10个元素的值为3的平方 没有值为4的平方的元素 元素0无前驱 元素1的前驱为0 元素9的后继为10 元素10无后继 删除第12个元素失败 删除第11个元素成功,其值为10 依次输出L的元素:0 1 2 3 4 5 6 7 8 9 L的元素值加倍后: 0 2 4 6 8 10 12 14 16 18 销毁L后:L.elem=0 L.length=0 L.listsize=0 */
/* 顺序表存储结构容易实现随机存取线性表的第i 个数据元素的操作,但在实现插入、 删除的操作时要移动大量数据元素,所以,它适用于数据相对稳定的线性表,如职工工资 表、学生学籍表等。 c2-1.h 是动态分配的顺序表存储结构,bo2-1.cpp 是基于顺序表的基本操作。由于 C++函数可重载,故去掉bo2-1.cpp 中算法2.3 等函数名中表示存储类型的后缀_Sq。 c2-1.h 不采用固定数组作为线性表的存储结构,而采用动态分配的存储结构,这样可以合 理地利用空间,使长表占用的存储空间多, 短表占用的存储空间少。这些可通过 bo2-1.cpp 中基本操作函数ListInsert()和图24 清楚看出。 */
// c2-1.h 线性表的动态分配顺序存储结构(见图2.1) #define LIST_INIT_SIZE 10 // 线性表存储空间的初始分配量 #define LIST_INCREMENT 2 // 线性表存储空间的分配增量 struct SqList { ElemType *elem; // 存储空间基址 int length; // 当前长度 int listsize; // 当前分配的存储容量(以sizeof(ElemType)为单位) };
// bo2-1.cpp 顺序表示的线性表(存储结构由c2-1.h定义)的基本操作(12个),包括算法2.3,2.4,2.5,2.6 void InitList(SqList &L) // 算法2.3 { // 操作结果:构造一个空的顺序线性表L(见图2.2) L.elem=(ElemType*)malloc(LIST_INIT_SIZE*sizeof(ElemType)); if(!L.elem) exit(OVERFLOW); // 存储分配失败 L.length=0; // 空表长度为0 L.listsize=LIST_INIT_SIZE; // 初始存储容量 } void DestroyList(SqList &L) { // 初始条件:顺序线性表L已存在。操作结果:销毁顺序线性表L(见图2.3) free(L.elem); L.elem=NULL; L.length=0; L.listsize=0; } void ClearList(SqList &L) { // 初始条件:顺序线性表L已存在。操作结果:将L重置为空表 L.length=0; } Status ListEmpty(SqList L) { // 初始条件:顺序线性表L已存在。操作结果:若L为空表,则返回TRUE;否则返回FALSE if(L.length==0) return TRUE; else return FALSE; } int ListLength(SqList L) { // 初始条件:顺序线性表L已存在。操作结果:返回L中数据元素的个数 return L.length; } Status GetElem(SqList L,int i,ElemType &e) { // 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)。操作结果:用e返回L中第i个数据元素的值 if(i<1||i>L.length) return ERROR; e=*(L.elem+i-1); return OK; } int LocateElem(SqList L,ElemType e,Status(*compare)(ElemType,ElemType)) { // 初始条件:顺序线性表L已存在,compare()是数据元素判定函数(满足为1,否则为0) // 操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。 // 若这样的数据元素不存在,则返回值为0。算法2.6 ElemType *p; int i=1; // i的初值为第1个元素的位序 p=L.elem; // p的初值为第1个元素的存储位置 while(i<=L.length&&!compare(*p++,e)) ++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; ElemType *p=L.elem+1; while(i<=L.length&&*p!=cur_e) { p++; i++; } if(i>L.length) return INFEASIBLE; // 操作失败 else { pre_e=*--p; return OK; } } Status NextElem(SqList L,ElemType cur_e,ElemType &next_e) { // 初始条件:顺序线性表L已存在 // 操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继; // 否则操作失败,next_e无定义 int i=1; ElemType *p=L.elem; while(i<L.length&&*p!=cur_e) { i++; p++; } if(i==L.length) return INFEASIBLE; // 操作失败 else { next_e=*++p; return OK; } } Status ListInsert(SqList &L,int i,ElemType e) // 算法2.4 { // 初始条件:顺序线性表L已存在,1≤i≤ListLength(L)+1 // 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1(见图2.4) ElemType *newbase,*q,*p; if(i<1||i>L.length+1) // i值不合法 return ERROR; if(L.length>=L.listsize) // 当前存储空间已满,增加分配 { if(!(newbase=(ElemType *)realloc(L.elem,(L.listsize+LIST_INCREMENT)*sizeof(ElemType)))) exit(OVERFLOW); // 存储分配失败 L.elem=newbase; // 新基址 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; } Status ListDelete(SqList &L,int i,ElemType &e) // 算法2.5 { // 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) // 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1(见图2.5) ElemType *p,*q; if(i<1||i>L.length) // i值不合法 return ERROR; 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; } void ListTraverse(SqList L,void(*vi)(ElemType&)) { // 初始条件:顺序线性表L已存在 // 操作结果:依次对L的每个数据元素调用函数vi() // vi()的形参加′&′,表明可通过调用vi()改变元素的值 ElemType *p; int i; p=L.elem; for(i=1;i<=L.length;i++) vi(*p++); printf(" "); }
// func2-3.cpp 几个常用的函数 Status equal(ElemType c1,ElemType c2) { // 判断是否相等的函数 if(c1==c2) return TRUE; else return FALSE; } int comp(ElemType a,ElemType b) { // 根据a<、=或>b,分别返回-1、0或1 if(a==b) return 0; else return (a-b)/abs(a-b); } void print(ElemType c) { printf("%d ",c); } void print2(ElemType c) { printf("%c ",c); } void print1(ElemType &c) { printf("%d ",c); }
// main2-1.cpp 检验bo2-1.cpp的主程序 #include"c1.h" typedef int ElemType; #include"c2-1.h" #include"bo2-1.cpp" #include"func2-3.cpp" // 包括equal()、comp()、print()、print2()和print1()函数 Status sq(ElemType c1,ElemType c2) { // 数据元素判定函数(平方关系),LocateElem()调用的函数 if(c1==c2*c2) return TRUE; else return FALSE; } void dbl(ElemType &c) { // ListTraverse()调用的另一函数(元素值加倍) c*=2; } void main() { SqList L; ElemType e,e0; Status i; int j,k; InitList(L); printf("初始化L后:L.elem=%u L.length=%d L.listsize=%d ",L.elem,L.length,L.listsize); for(j=1;j<=5;j++) i=ListInsert(L,1,j); printf("在L的表头依次插入1~5后:*L.elem="); for(j=1;j<=5;j++) cout<<*(L.elem+j-1)<<""; cout<<endl; printf("L.elem=%u L.length=%d L.listsize=%d ",L.elem,L.length,L.listsize); i=ListEmpty(L); printf("L是否空:i=%d(1:是0:否) ",i); ClearList(L); printf("清空L后:L.elem=%u L.length=%d L.listsize=%d ",L.elem,L.length,L.listsize); i=ListEmpty(L); printf("L是否空:i=%d(1:是0:否) ",i); for(j=1;j<=10;j++) ListInsert(L,j,j); printf("在L的表尾依次插入1~10后:*L.elem="); for(j=1;j<=10;j++) cout<<*(L.elem+j-1)<<""; cout<<endl; printf("L.elem=%u L.length=%d L.listsize=%d ",L.elem,L.length,L.listsize); ListInsert(L,1,0); printf("在L的表头插入0后:*L.elem="); for(j=1;j<=ListLength(L);j++) // ListLength(L)为元素个数 cout<<*(L.elem+j-1)<<""; cout<<endl; printf("L.elem=%u(有可能改变) L.length=%d(改变) L.listsize=%d(改变) ",L.elem,L.length, L.listsize); GetElem(L,5,e); printf("第5个元素的值为%d ",e); for(j=10;j<=11;j++) { k=LocateElem(L,j,equal); if(k) // k不为0,表明有符合条件的元素,且其位序为k printf("第%d个元素的值为%d ",k,j); else printf("没有值为%d的元素 ",j); } for(j=3;j<=4;j++) { k=LocateElem(L,j,sq); if(k) // k不为0,表明有符合条件的元素,且其位序为k printf("第%d个元素的值为%d的平方 ",k,j); else printf("没有值为%d的平方的元素 ",j); } for(j=1;j<=2;j++) // 测试头两个数据 { GetElem(L,j,e0); // 把第j个数据赋给e0 i=PriorElem(L,e0,e); // 求e0的前驱 if(i==INFEASIBLE) printf("元素%d无前驱 ",e0); else printf("元素%d的前驱为%d ",e0,e); } for(j=ListLength(L)-1;j<=ListLength(L);j++) // 最后两个数据 { GetElem(L,j,e0); // 把第j个数据赋给e0 i=NextElem(L,e0,e); // 求e0的后继 if(i==INFEASIBLE) printf("元素%d无后继 ",e0); else printf("元素%d的后继为%d ",e0,e); } k=ListLength(L); // k为表长 for(j=k+1;j>=k;j--) { i=ListDelete(L,j,e); // 删除第j个数据 if(i==ERROR) printf("删除第%d个元素失败 ",j); else printf("删除第%d个元素成功,其值为%d ",j,e); } printf("依次输出L的元素:"); ListTraverse(L,print1); // 依次对元素调用print1(),输出元素的值 printf("L的元素值加倍后:"); ListTraverse(L,dbl); // 依次对元素调用dbl(),元素值乘2 ListTraverse(L,print1); DestroyList(L); printf("销毁L后:L.elem=%u L.length=%d L.listsize=%d ",L.elem,L.length,L.listsize); }
以下是运行的结果代码:
/* 初始化L后:L.elem=3615192 L.length=0 L.listsize=10 在L的表头依次插入1~5后:*L.elem=54321 L.elem=3615192 L.length=5 L.listsize=10 L是否空:i=0(1:是0:否) 清空L后:L.elem=3615192 L.length=0 L.listsize=10 L是否空:i=1(1:是0:否) 在L的表尾依次插入1~10后:*L.elem=12345678910 L.elem=3615192 L.length=10 L.listsize=10 在L的表头插入0后:*L.elem=012345678910 L.elem=3606792(有可能改变) L.length=11(改变) L.listsize=12(改变) 第5个元素的值为4 第11个元素的值为10 没有值为11的元素 第10个元素的值为3的平方 没有值为4的平方的元素 元素0无前驱 元素1的前驱为0 元素9的后继为10 元素10无后继 删除第12个元素失败 删除第11个元素成功,其值为10 依次输出L的元素:0 1 2 3 4 5 6 7 8 9 L的元素值加倍后: 0 2 4 6 8 10 12 14 16 18 销毁L后:L.elem=0 L.length=0 L.listsize=0 */