1.概述:
对于一个循环链表来说,其首节点和末节点被连接在一起。这种方式在单向和双向链表中皆可实现。要转换一个循环链表,可以选择开始于任意一个节点然后沿着列表的任一方向直到返回开始的节点。再来看另一种方法,循环链表可以被视为“无头无尾”。这种列表很利于节约数据存储缓存, 假定你在一个列表中有一个对象并且希望所有其他对象迭代在一个非特殊的排列下。
指向整个列表的指针可以被称作访问指针。
用单向链表构建的循环链表
循环链表中第一个节点之前就是最后一个节点,反之亦然。循环链表的无边界使得在这样的链表上设计算法会比普通链表更加容易。对于新加入的节点应该是在第一个节点之前还是最后一个节点之后可以根据实际要求灵活处理,区别不大(详见下面实例代码)。当然,如果只会在最后插入数据(或者只会在之前),处理也是很容易的。
另外有一种模拟的循环链表,就是在访问到最后一个节点之后的时候,手工的跳转到第一个节点。访问到第一个节点之前的时候也一样。这样也可以实现循环链表的功能,在直接用循环链表比较麻烦或者可能会出现问题的时候可以用。
2.程序实现:
/* c2-2.h 线性表的单链表存储结构 */ struct LNode { ElemType data; struct LNode *next; }; typedef struct LNode *LinkList; /* 另一种定义LinkList的方法 */
/* bo2-4.c 设立尾指针的单循环链表(存储结构由c2-2.h定义)的12个基本操作 */ Status InitList_CL(LinkList *L) { /* 操作结果:构造一个空的线性表L */ *L=(LinkList)malloc(sizeof(struct LNode)); /* 产生头结点,并使L指向此头结点 */ if(!*L) /* 存储分配失败 */ exit(OVERFLOW); (*L)->next=*L; /* 指针域指向头结点 */ return OK; } Status DestroyList_CL(LinkList *L) { /* 操作结果:销毁线性表L */ LinkList q,p=(*L)->next; /* p指向头结点 */ while(p!=*L) /* 没到表尾 */ { q=p->next; free(p); p=q; } free(*L); *L=NULL; return OK; } Status ClearList_CL(LinkList *L) /* 改变L */ { /* 初始条件:线性表L已存在。操作结果:将L重置为空表 */ LinkList p,q; *L=(*L)->next; /* L指向头结点 */ p=(*L)->next; /* p指向第一个结点 */ while(p!=*L) /* 没到表尾 */ { q=p->next; free(p); p=q; } (*L)->next=*L; /* 头结点指针域指向自身 */ return OK; } Status ListEmpty_CL(LinkList L) { /* 初始条件:线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */ if(L->next==L) /* 空 */ return TRUE; else return FALSE; } int ListLength_CL(LinkList L) { /* 初始条件:L已存在。操作结果:返回L中数据元素个数 */ int i=0; LinkList p=L->next; /* p指向头结点 */ while(p!=L) /* 没到表尾 */ { i++; p=p->next; } return i; } Status GetElem_CL(LinkList L,int i,ElemType *e) { /* 当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR */ int j=1; /* 初始化,j为计数器 */ LinkList p=L->next->next; /* p指向第一个结点 */ if(i<=0||i>ListLength_CL(L)) /* 第i个元素不存在 */ return ERROR; while(j<i) { /* 顺指针向后查找,直到p指向第i个元素 */ p=p->next; j++; } *e=p->data; /* 取第i个元素 */ return OK; } int LocateElem_CL(LinkList L,ElemType e,Status(*compare)(ElemType,ElemType)) { /* 初始条件:线性表L已存在,compare()是数据元素判定函数 */ /* 操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。 */ /* 若这样的数据元素不存在,则返回值为0 */ int i=0; LinkList p=L->next->next; /* p指向第一个结点 */ while(p!=L->next) { i++; if(compare(p->data,e)) /* 满足关系 */ return i; p=p->next; } return 0; } Status PriorElem_CL(LinkList L,ElemType cur_e,ElemType *pre_e) { /* 初始条件:线性表L已存在 */ /* 操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱, */ /* 否则操作失败,pre_e无定义 */ LinkList q,p=L->next->next; /* p指向第一个结点 */ q=p->next; while(q!=L->next) /* p没到表尾 */ { if(q->data==cur_e) { *pre_e=p->data; return TRUE; } p=q; q=q->next; } return FALSE; } Status NextElem_CL(LinkList L,ElemType cur_e,ElemType *next_e) { /* 初始条件:线性表L已存在 */ /* 操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继, */ /* 否则操作失败,next_e无定义 */ LinkList p=L->next->next; /* p指向第一个结点 */ while(p!=L) /* p没到表尾 */ { if(p->data==cur_e) { *next_e=p->next->data; return TRUE; } p=p->next; } return FALSE; } Status ListInsert_CL(LinkList *L,int i,ElemType e) /* 改变L */ { /* 在L的第i个位置之前插入元素e */ LinkList p=(*L)->next,s; /* p指向头结点 */ int j=0; if(i<=0||i>ListLength_CL(*L)+1) /* 无法在第i个元素之前插入 */ return ERROR; while(j<i-1) /* 寻找第i-1个结点 */ { p=p->next; j++; } s=(LinkList)malloc(sizeof(struct LNode)); /* 生成新结点 */ s->data=e; /* 插入L中 */ s->next=p->next; p->next=s; if(p==*L) /* 改变尾结点 */ *L=s; return OK; } Status ListDelete_CL(LinkList *L,int i,ElemType *e) /* 改变L */ { /* 删除L的第i个元素,并由e返回其值 */ LinkList p=(*L)->next,q; /* p指向头结点 */ int j=0; if(i<=0||i>ListLength_CL(*L)) /* 第i个元素不存在 */ return ERROR; while(j<i-1) /* 寻找第i-1个结点 */ { p=p->next; j++; } q=p->next; /* q指向待删除结点 */ p->next=q->next; *e=q->data; if(*L==q) /* 删除的是表尾元素 */ *L=p; free(q); /* 释放待删除结点 */ return OK; } Status ListTraverse_CL(LinkList L,void(*vi)(ElemType)) { /* 初始条件:L已存在。操作结果:依次对L的每个数据元素调用函数vi()。一旦vi()失败,则操作失败 */ LinkList p=L->next->next; while(p!=L->next) { vi(p->data); p=p->next; } printf("\n"); return OK; }
/* main2-4.c 单循环链表,检验bo2-4.c的主程序 */ #include"c1.h" typedef int ElemType; #include"c2-2.h" #include"bo2-4.c" Status compare(ElemType c1,ElemType c2) { if(c1==c2) return TRUE; else return FALSE; } void visit(ElemType c) { printf("%d ",c); } void main() { LinkList L; ElemType e; int j; Status i; i=InitList_CL(&L); /* 初始化单循环链表L */ printf("初始化单循环链表L i=%d (1:初始化成功)\n",i); i=ListEmpty_CL(L); printf("L是否空 i=%d(1:空 0:否)\n",i); ListInsert_CL(&L,1,3); /* 在L中依次插入3,5 */ ListInsert_CL(&L,2,5); i=GetElem_CL(L,1,&e); j=ListLength_CL(L); printf("L中数据元素个数=%d,第1个元素的值为%d。\n",j,e); printf("L中的数据元素依次为:"); ListTraverse_CL(L,visit); PriorElem_CL(L,5,&e); /* 求元素5的前驱 */ printf("5前面的元素的值为%d。\n",e); NextElem_CL(L,3,&e); /* 求元素3的后继 */ printf("3后面的元素的值为%d。\n",e); printf("L是否空 %d(1:空 0:否)\n",ListEmpty_CL(L)); j=LocateElem_CL(L,5,compare); if(j) printf("L的第%d个元素为5。\n",j); else printf("不存在值为5的元素\n"); i=ListDelete_CL(&L,2,&e); printf("删除L的第2个元素:\n"); if(i) { printf("删除的元素值为%d,现在L中的数据元素依次为:",e); ListTraverse_CL(L,visit); } else printf("删除不成功!\n"); printf("清空L:%d(1: 成功)\n",ClearList_CL(&L)); printf("清空L后,L是否空:%d(1:空 0:否)\n",ListEmpty_CL(L)); printf("销毁L:%d(1: 成功)\n",DestroyList_CL(&L)); }
本文向大家介绍C语言单向链表的表示与实现实例详解,包括了C语言单向链表的表示与实现实例详解的使用技巧和注意事项,需要的朋友参考一下 1.概述: C语言中的单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始。 链表中最简单的一种是单向链表,它包含两个域,一个信息域和一个指针域。这个链接指向列表中的下一个节点,而最后一个节点则指向一个空值。 如下图所示
本文向大家介绍C语言单链队列的表示与实现实例详解,包括了C语言单链队列的表示与实现实例详解的使用技巧和注意事项,需要的朋友参考一下 1.概述: C语言的队列(queue),是指先进先出(FIFO, First-In-First-Out)的线性表。在具体应用中通常用链表或者数组来实现。队列只允许在后端(称为rear)进行插入操作,在前端(称为front)进行删除操作。 而单链队列使用链表作为基本数据
本文向大家介绍C语言双向链表的表示与实现实例详解,包括了C语言双向链表的表示与实现实例详解的使用技巧和注意事项,需要的朋友参考一下 1.概述: C语言中一种更复杂的链表是“双向链表”或“双面链表”。其表中的每个节点有两个连接:一个指向前一个节点,(当这个“连接”为第一个“连接”时,指向空值或者空列表);而另一个指向下一个节点,(当这个“连接”为最后一个“连接”时,指向空值或者空列表) 一个双向链表
本文向大家介绍数据结构 C语言实现循环单链表的实例,包括了数据结构 C语言实现循环单链表的实例的使用技巧和注意事项,需要的朋友参考一下 数据结构 C语言实现循环单链表的实例 实例代码: 如图: 感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
本文向大家介绍C语言栈的表示与实现实例详解,包括了C语言栈的表示与实现实例详解的使用技巧和注意事项,需要的朋友参考一下 1.基本概念: C语言的栈是指限定仅在表尾进行插入和删除操作的线性表。 栈作为C语言中一种常用的数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一
本文向大家介绍C语言单链表的实现,包括了C语言单链表的实现的使用技巧和注意事项,需要的朋友参考一下 单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。 链表结构: SList.h SList.cpp Test.cpp 以上内容是小编给大家介绍的C语言单链表的实现代码,希望对大家有所帮助!