2.3.3笔记-不带头结点的单链表

来源:互联网 发布:java底层框架源码 编辑:程序博客网 时间:2024/04/30 15:56
       单链表有两种形式:带头结点的单链表和不带头结点的单链表。带头结点的单链表的表示已经在 

2.3笔记-线性表的链式表示和实现中做了解释。现在再在这次笔记里对不带头结点的单链表做个解释。不带头结点的单链表L是把头结点去掉,然后关于单链表L的基本操作跟带头结点的单链表的基本操作稍有不同,特别的是在ListInsert函数和ListDelete函数中都加入了对第一个结点的判断,因为在插入和删除中第一个结点和其他结点时操作不同,要改变链表头指针的值。而带头结点的单链表无论插入和删除第几个元素,其操作都是统一的。那么不设头结点的单链表有什么用呢?据高一凡的《数据结构算法分析》说是在第七章会有应用。

不带头结点的单链表的源代码

#include<stdio.h>#include<malloc.h>#include<math.h>#include<stdlib.h>#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0typedef int ElemType;typedef int Status;//该链表为不带头结点的单链表struct LNode{//线性表的单链表结构ElemType data;LNode *next;};typedef LNode *LinkList;void InitList(LinkList &L){//操作结果:构造一个空的线性表L=NULL;//指针为空,此处只设一个空的头指针,如果是带头结点的单链表还要创建一个头结点}Status ListInsert(LinkList &L,int i,ElemType e){//在不设头结点的单链线性表L中第i个位置之前插入元素eint j=1;//计数器初值为1LinkList s,p=L;//p指向第一结点if(i<1) return ERROR;s=(LinkList)malloc(sizeof(LNode));s->data=e;//给s的data域赋值eif(i==1)//插在表头{s->next=L;//新结点指向原第一结点,成为新的第一结点L=s;//L指向新结点}else{while(p&&j<i-1){j++;//计数器+1p=p->next;//p指向下个结点}if(!p||j>i-1)return ERROR;s->next=p->next;//新结点指向元第i个结点p->next=s;//原第i-1个结点指向新结点}return OK;//插入成功}void print(ElemType e){printf("%d ",e);}void ListTraverse(LinkList L,void (*visit)(ElemType )){//初始条件:线性表L已存在。操作结果:依次对L的每个数据元素调用函数visit()LinkList p=L->next;while(p)//p所指结点存在{visit(p->data);//对p所指结点调用函数visit()p=p->next;//p指向下一个结点}printf("\n");}Status ListEmpty(LinkList L){//初始条件:线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSEif(L)return FALSE;elsereturn TRUE;}int ListLength(LinkList L){//初始条件:线性表L已存在。操作结果;返回L中数据元素的个数LinkList p;int i=0;//计数器初值为0p=L;//p指向第1个结点while(p){//未到表尾i++;//计数器+1p=p->next;//p指向下个结点}return i;}void DestroyList(LinkList &L){//初始条件:线性表L已存在。操作结果:销毁线性表LLinkList q;while(L){//L指向的结点(非空)q=L->next;//q指向现在线性表的首元结点free(L);//释放现在线性表的头结点L=q;//L指向现头结点}}void ClearList(LinkList L){//初始条件:线性表L已存在。操作结果:将L重置为空表(只留下头指针和头结点)//线性表L的结构;  L+头结点+头结点指向的单链表LinkList p=L->next;//p指向第1个结点L->next=NULL;//将头结点指针域为空,断开头结点和头结点指向的单链表DestroyList(p);//销毁p所指的单链表}int LocateElem(LinkList L,ElemType e, Status(* compare)(ElemType,ElemType)){//初始条件:线性表L已存在,compare()是数据元素判定函数(满足为1,否则为0)//操作结果:返回L中第1个与e满足关系compare()的数据元素的位序//若这样的数据元素不存在,则返回值为0int i=0;LinkList p=L;//p指向第1个结点while(p)//未到表尾 { i++; if(compare(p->data,e))//找到这样的数据元素 return i; p=p->next;//p指向下一个结点 }return 0;//满足关系的数据元素不存在}Status equal(ElemType c1,ElemType c2){//判断是否相等的函数if(c1==c2)return TRUE;elsereturn FALSE;}Status GetElem(LinkList L,int i,ElemType &e){//算法2.8//L为不设头结点的单链表的头指针。当第i个元素存在时,其值赋给e并返回ok,否则返回ERRORint j=1;//计数器初值为1LinkList p=L;//p指向第1个结点if(i<1) return ERROR;while(p&&j<i) {   j++;   p=p->next;//p指向下一个结点}    if(j==i&&p)//存在第i个元素{e=p->data;//取第i个元素的值赋给ereturn OK;}return ERROR;//不存在第i个元素,失败返回ERROR}Status PriorElem(LinkList L,ElemType cur_e,ElemType &pre_e){//初始条件:线性表L已存在//操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,返回ok,否则操作失败,pre_ew无定义,返回ERRORLinkList q,p=L;//p指向第1个结点while(p->next){//p所指结点有后继q=p->next;if(q->data==cur_e)//p的后继为cur_e{pre_e=p->data;//将p所指元素的值赋给pre_ereturn OK;//}p=q; //p的后继不为cur_e,p向后移}return ERROR;}Status NextElem(LinkList L,ElemType cur_e,ElemType &next_e){  //初始条件:线性表L已存在 //操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e 返回它的后继,返回OKLinkList p=L;//p指向第一个结点while(p->next) //p所指结点有后继 { if(p->data==cur_e)//p所指结点的值为cur_e   {   next_e=p->next->data;               return OK;    } p=p->next;//p指向下个结点  } return ERROR;}Status ListDelete(LinkList L,int i,ElemType &e){//算法2.10 不改变L//在不设头结点的单链线性表L中,删除第i个元素,并由e返回其值  int j=1;//计数器初值为1  LinkList q,p=L;//p指向第一个结点  if(!L)//表L空  return ERROR;//删除失败  else if(i==1)//删除第一个结点  {  L=p->next;//L由第二个结点开始  e=p->data;//将待删结点的值赋给e  free(p);//删除并释放第一个结点  }else{  while(p->next && j<i-1){//寻找第i个结点,并令p指向其前驱     j++; p=p->next;//p指向下一个结点  }  if(!p->next || j>i-1)//删除位置不合理  return ERROR;  q=p->next;  p->next=q->next;//待删除结点的前驱指向待删结点的后继  e=q->data;//将待删结点的值赋给e  free(q);//释放待删结点  }  return OK;//删除成功  }void main(){LinkList L;//首先定义指针LElemType e,e0;Status i;int j,k;InitList(L);//初始化线性表for(j=1;j<=5;j++)i=ListInsert(L,1,j);//从L的表头插入jprintf("在L的表头依次插入1~5后,L=");ListTraverse(L,print);//依次对元素调用print(),输出元素的值i=ListEmpty(L);//检测表L是否为空printf("L是否为空?i=%d(1:是 0:否),表L的长度=%d\n",i,ListLength(L));ClearList(L);//清空表Lprintf("清空L后,L=");ListTraverse(L,print);i=ListEmpty(L);//检测表L是否为空printf("L是否为空?i=%d(1:是 0:否),表L的长度=%d\n",i,ListLength(L));    for(j=1;j<=10;j++)ListInsert(L,j,j);//在L的表尾插入jprintf("在L的表尾依次插入1~10后,L= ");ListTraverse(L,print);//依次输出表L中的元素for(j=0;j<=1;j++)k=LocateElem(L,j,equal);//查找表L中与j相等的元素,并将其在链表中的排序赋给k    if(k) //k不为0,表明有符合条件的元素   printf("第%d个元素的值为%d\n",k,j);    for(j=1;j<=2;j++)//测试头2个数据{GetElem(L,j,e0);//把表L中的第j个数据赋给e0i=PriorElem(L,e0,e);//把表L中的第j个数据赋给e0if(i==ERROR)printf("元素%d无前驱\n",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无后继\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)//表中不存在第j个数据  printf("删除第%d个元素失败(不存在此元素)。",j);  else //表中存在第j个数据,删除成功,其值赋给e  printf("删除第%d个元素成功,其值为%d\n",j,e);}printf("依次输出L的元素:");ListTraverse(L,print);//依次输出表L中的元素DestroyList(L);//销毁表Lprintf("销毁L后,L=%u\n",L);}
运行结果:

0 0