不带头结点的单链表
单链表也可以不设头结点,如图212 所示。显 然,基于这种结构的基本操作和带有头结点的线性链 表基本操作是不同的。bo2-8.cpp 是不带头结点的线 性链表的基本操作。
// bo2-8.cpp 不带头结点的单链表(存储结构由c2-2.h定义)的部分基本操作(9个) #define DestroyList ClearList // DestroyList()和ClearList()的操作是一样的 void InitList(LinkList &L) { // 操作结果:构造一个空的线性表L(见图2.13) L=NULL; // 指针为空 } void ClearList(LinkList &L) { // 初始条件:线性表L已存在。操作结果:将L重置为空表(见图2.13) LinkList p; while(L) // L不空 { p=L; // p指向首元结点 L=L->next; // L指向第2个结点(新首元结点) free(p); // 释放首元结点 } } Status ListEmpty(LinkList L) { // 初始条件:线性表L已存在。操作结果:若L为空表,则返回TRUE;否则返回FALSE if(L) return FALSE; else return TRUE; } int ListLength(LinkList L) { // 初始条件:线性表L已存在。操作结果:返回L中数据元素的个数 int i=0; LinkList p=L; while(p) // p指向结点(没到表尾) { p=p->next; // p指向下一个结点 i++; } return i; } Status GetElem(LinkList L,int i,ElemType &e) { // L为不带头结点的单链表的头指针。当第i个元素存在时,其值赋给e并返回OK;否则返回ERROR int j=1; LinkList p=L; if(i<1) // i值不合法 return ERROR; while(j<i&&p) // 没到第i个元素,也没到表尾 { j++; p=p->next; } if(j==i) // 存在第i个元素 { e=p->data; return OK; } else return ERROR; } int LocateElem(LinkList L,ElemType e,Status(*compare)(ElemType,ElemType)) { // 初始条件:线性表L已存在,compare()是数据元素判定函数(满足为1;否则为0) // 操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。 // 若这样的数据元素不存在,则返回值为0 int i=0; LinkList p=L; while(p) { i++; if(compare(p->data,e)) // 找到这样的数据元素 return i; p=p->next; } return 0; } Status ListInsert(LinkList &L,int i,ElemType e) { // 在不带头结点的单链线性表L中第i个位置之前插入元素e int j=1; LinkList p=L,s; if(i<1) // i值不合法 return ERROR; s=(LinkList)malloc(sizeof(LNode)); // 生成新结点 s->data=e; // 给s的data域赋值 if(i==1) // 插在表头(见图2.14) { s->next=L; L=s; // 改变L } else { // 插在表的其余处(见图2.15) while(p&&j<i-1) // 寻找第i-1个结点 { p=p->next; j++; } if(!p) // i大于表长+1 return ERROR; s->next=p->next; p->next=s; } return OK; } Status ListDelete(LinkList &L,int i,ElemType &e) { // 在不带头结点的单链线性表L中,删除第i个元素,并由e返回其值 int j=1; LinkList p=L,q; if(i==1) // 删除第1个结点(见图2.16) { L=p->next; // L由第2个结点开始 e=p->data; free(p); // 删除并释放第1个结点 } else { while(p->next&&j<i-1) // 寻找第i个结点,并令p指向其前驱 { p=p->next; j++; } if(!p->next||j>i-1) // 删除位置不合理 return ERROR; q=p->next; // 删除并释放结点 p->next=q->next; e=q->data; free(q); } return OK; } void ListTraverse(LinkList L,void(*vi) (ElemType)) { // 初始条件:线性表L已存在 // 操作结果:依次对L的每个数据元素调用 // 函数vi() LinkList p=L; while(p) { vi(p->data); p=p->next; } printf("\n"); }
// bo2-9.cpp 不带头结点的单链表(存储结构由c2-2.h定义)的部分基本操作(2个) Status PriorElem(LinkList L,ElemType cur_e,ElemType &pre_e) { // 初始条件:线性表L已存在 // 操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱, // 返回OK;否则操作失败,pre_e无定义,返回INFEASIBLE LinkList q,p=L; // p指向第一个结点 while(p->next) // p所指结点有后继 { q=p->next; // q为p的后继 if(q->data==cur_e) { pre_e=p->data; return OK; } p=q; // p向后移 } return INFEASIBLE; } Status NextElem(LinkList L,ElemType cur_e,ElemType &next_e) { // 初始条件:线性表L已存在 // 操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继, // 返回OK;否则操作失败,next_e无定义,返回INFEASIBLE LinkList p=L; // p指向第一个结点 while(p->next) // p所指结点有后继 { if(p->data==cur_e) { next_e=p->next->data; return OK; } p=p->next; } return INFEASIBLE; }
// main2-8.cpp 检验bo2-8.cpp和bo2-9.cpp的主程序 #include"c1.h" typedef int ElemType; #include"c2-2.h" #include"bo2-8.cpp" #include"bo2-9.cpp" #include"func2-3.cpp" // 包括equal()、comp()、print()、print2()和print1()函数 void main() { LinkList L; ElemType e,e0; Status i; int j,k; InitList(L); for(j=1;j<=5;j++) { i=ListInsert(L,1,j); if(!i) // 插入失败 exit(ERROR); } printf("在L的表头依次插入1~5后:L="); ListTraverse(L,print); // 依次对元素调用print(),输出元素的值 i=ListEmpty(L); printf("L是否空:i=%d(1:是0:否)\n",i); ClearList(L); printf("清空L后:L="); ListTraverse(L,print); i=ListEmpty(L); printf("L是否空:i=%d(1:是0:否)\n",i); for(j=1;j<=10;j++) ListInsert(L,j,j); printf("在L的表尾依次插入1~10后:L="); ListTraverse(L,print); i=GetElem(L,5,e); if(i==OK) printf("第5个元素的值为%d\n",e); for(j=0;j<=1;j++) { k=LocateElem(L,j,equal); if(k) printf("第%d个元素的值为%d\n",k,j); else printf("没有值为%d的元素\n",j); } for(j=1;j<=2;j++) // 测试头两个数据 { GetElem(L,j,e0); // 把第j个数据赋给e0 i=PriorElem(L,e0,e); // 求e0的前驱 if(i==INFEASIBLE) printf("元素%d无前驱\n",e0); else printf("元素%d的前驱为%d\n",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无后继\n",e0); else printf("元素%d的后继为%d\n",e0,e); } k=ListLength(L); // k为表长 for(j=k+1;j>=k;j--) { i=ListDelete(L,j,e); // 删除第j个数据 if(i==ERROR) printf("删除第%d个元素失败\n",j); else printf("删除第%d个元素成功,其值为%d\n",j,e); } printf("依次输出L的元素:"); ListTraverse(L,print); DestroyList(L); printf("销毁L后:L=%u\n",L); }
运行结果如下:
/* 在L的表头依次插入1~5后:L=5 4 3 2 1 L是否空:i=0(1:是0:否) 清空L后:L= L是否空:i=1(1:是0:否) 在L的表尾依次插入1~10后:L=1 2 3 4 5 6 7 8 9 10 第5个元素的值为5 没有值为0的元素 第1个元素的值为1 元素1无前驱 元素2的前驱为1 元素9的后继为10 元素10无后继 删除第11个元素失败 删除第10个元素成功,其值为10 依次输出L的元素:1 2 3 4 5 6 7 8 9 销毁L后:L=0 Press any key to continue */
每当夜深人静的时候,想想今天发生了什么,失去了什么,得到了什么,做了什么,没做什么,该做什么,不该做什么,明天要做什么!