1、双向链表可以从任何一个节点访问前一个节点,当然也可以访问后一个节点,以至整个链表。一般是在需要大批量的另外储存数据在链表中的位置的时候用。2.3 循环链表在一个循环链表中, 首节点和末节点被连接在一起。这种方式在单向和双向链表中皆可实现。要转换一个循环链表,你开始于任意一个节点然后沿着列表的任一方向直到返回开始的节点。指向整个列表的指针可以被称作访问指针。循环链表中第一个节点之前就是最后一个节点,反之亦然。3 链表常见用途 常用于组织删除、检索较少,而添加、遍历较多的数据。4 链表和数组的区别 数组在内存中是逐个存放的,也就是说倘若数组的第一个元素在地址A,则数组第二个元素就在地址A+1。而链
2、表则不是,链表每个节点没有相对固定的位置关系。某个节点在地址A其后的节点不一定是A+1,而在内存的其他空闲区域,呈现一种随机的状态。数组一旦显式的被申明后,其大小就固定了,不能动态进行扩充。而链表则可以,可以动态生成节点并且添加到已有的链表中。链表灵活,但是空间和时间额外耗费较大;数组大小固定,元素位置固定,但是操作不灵活,且容易浪费空间,但是时间耗费较小,尤其是元素变化不大的时候效率很高。双向链表比单向的更灵活,但是空间耗费也更大。从内存存储来看,(静态)数组从栈中分配空间, 对于程序员方便快速,但是自由度小;链表从堆中分配空间, 自由度大但是申请管理比较麻烦。附录:(链表的部分常见操作)1
3、 单向链表/*线性表的单链表存储结构*/typedef struct LNode ElemType data; struct LNode *next;LNode, *LinkList;/*带有头结点的单链表的基本操作(12个)*/void InitList(LinkList *L) /* 操作结果:构造一个空的线性表L */ *L=(LinkList)malloc(sizeof(struct LNode); /* 产生头结点,并使L指向此头结点 */ if(!*L) /* 存储分配失败*/ exit(OVERFLOW); (*L)-next=NULL; /* 指针域为空 */void Dest
4、royList(LinkList *L) /* 初始條件:线性表L已存在。操作结果:销毁线性表L */ LinkList q; while(*L) q=(*L)-next; free(*L); *L=q; void ClearList(LinkList L) /* 不改变L */ /* 初始条件:将L重置为空表 */ LinkList p,q; p=L- /* p指向第一个结点 */ while(p) /* 没到表尾 */ q=p- free(p); p=q; L- /* 头结点指针域为空 */Status ListEmpty(LinkList L)若L为空表,则返回TRUE,否则返回FALS
5、E */ return L-next = NULL;int ListLength(LinkList L)返回L中数据元素个数 */ int i=0; LinkList p=L- i+; p=p- return i;Status GetElem(LinkList L,int i,ElemType *e) /* L为带头结点的单链表的头指针。当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR */ int j=1; /* j为计数器 */ while(p&j i) /* 第i个元素不存在 */ return ERROR; *e=p-data; /* 取第i个元素 */ return OK
6、;int LocateElem(LinkList L,ElemType e,Status(*compare)(ElemType,ElemType) /* 初始条件: 线性表L已存在,compare()是数据元素判定函数(满足为1,否则为0) */ /* 操作结果: 返回L中第1个与e满足关系compare()的数据元素的位序。 */ /* 若这样的数据元素不存在,则返回值为0 */ while(p) if(compare(p-data,e) /* 找到这样的数据元素 */ return 0;Status PriorElem(LinkList L,ElemType cur_e,ElemType
7、*pre_e) 线性表L已存在 */ 若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱, */ /* 返回OK;否则操作失败,pre_e无定义,返回INFEASIBLE */ LinkList q,p=L- while(p-next) /* p所指结点有后继 */ q=p- /* q为p的后继 */ if(q-data=cur_e) *pre_e=p- /* p向后移 */ return INFEASIBLE;Status NextElem(LinkList L,ElemType cur_e,ElemType *next_e)线性表L已存在 */ /* 操作结果:若cur_
8、e是L的数据元素,且不是最后一个,则用next_e返回它的后继, */ /* 返回OK;否则操作失败,next_e无定义,返回INFEASIBLE */ if(p- *next_e=p-next-Status ListInsert(LinkList L,int i,ElemType e) /* 在带头结点的单链线性表L中第i个位置之前插入元素e */ int j=0; LinkList p=L,s; i-1) /* 寻找第i-1个结点 */i-1) /* i小于1或者大于表长 */ s=(LinkList)malloc(sizeof(struct LNode); /* 生成新结点 */ s-d
9、ata=e; /* 插入L中 */next=p- p-next=s;Status ListDelete(LinkList L,int i,ElemType *e) /* 在带头结点的单链线性表L中,删除第i个元素,并由e返回其值 */ LinkList p=L,q;next&jnext|ji-1) /* 删除位置不合理 */ /* 删除并释放结点 */next=q- *e=q- free(q);void ListTraverse(LinkList L,void(*vi)(ElemType)/* vi的形参类型为ElemType,与bo2-1.c中相应函数的形参类型ElemType&不同 */依
10、次对L的每个数据元素调用函数vi() */ vi(p-data); printf(n);2 双向链表/* 线性表的双向链表存储结构 */typedef struct DuLNode struct DuLNode *prior,*next;DuLNode,*DuLinkList;/*带头结点的双向循环链表的基本操作*/void InitList(DuLinkList *L) /* 产生空的双向循环链表L */ *L=(DuLinkList)malloc(sizeof(DuLNode); if(*L)next=(*L)-prior=*L; elsevoid DestroyList(DuLinkLi
11、st *L)销毁双向循环链表L */ DuLinkList q,p=(*L)- while(p!=*L) /* p没到表头 */ *L=NULL;void ClearList(DuLinkList L) /* 不改变L */L已存在。 DuLinkList q,p=L-=L) /* p没到表头 */next=L-prior=L; /* 头结点的两个指针域均指向自身 */Status ListEmpty(DuLinkList L) if(L-next=L&L-prior=L) return TRUE; return FALSE;int ListLength(DuLinkList L) DuLin
12、kList p=L-Status GetElem(DuLinkList L,int i,ElemType *e) /* 当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR */=L&jnext; if(p=L|jint LocateElem(DuLinkList L,ElemType e,Status(*compare)(ElemType,ElemType)L已存在,compare()是数据元素判定函数 */返回L中第1个与e满足关系compare()的数据元素的位序。 /* p指向第1个元素 */=L)Status PriorElem(DuLinkList L,ElemType c
13、ur_e,ElemType *pre_e)若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱, */ /* 否则操作失败,pre_e无定义 */ /* p指向第2个元素 */prior-Status NextElem(DuLinkList L,ElemType cur_e,ElemType *next_e) /* 否则操作失败,next_e无定义 */DuLinkList GetElemP(DuLinkList L,int i) /* 另加 */ /* 在双向链表L中返回第i个元素的地址。i为0,返回头结点的地址。若第i个元素不存在,*/ /* 返回NULL */ int j
14、; DuLinkList p=L; /* p指向头结点 */ if(iListLength(L) /* i值不合法 */ return NULL; for(j=1;=i;j+) return p;Status ListInsert(DuLinkList L,int i,ElemType e) /* 在带头结点的双链循环线性表L中第i个位置之前插入元素e,i的合法值为1i表长+1 */ /* 改进算法2.18,否则无法在第表长+1个结点之前插入元素 */ DuLinkList p,s;1|iListLength(L)+1) /* i值不合法 */ p=GetElemP(L,i-1); /* 在L
15、中确定第i个元素前驱的位置指针p */p) /* p=NULL,即第i个元素的前驱不存在(设头结点为第1个元素的前驱) */ s=(DuLinkList)malloc(sizeof(DuLNode);s) return OVERFLOW;prior=p; /* 在第i-1个元素之后插入 */prior=s;Status ListDelete(DuLinkList L,int i,ElemType *e) /* 删除带头结点的双链循环线性表L的第i个元素,i的合法值为1i表长 */ DuLinkList p;1) /* i值不合法 */ p=GetElemP(L,i); /* 在L中确定第i个元素的位置指针p */p) /* p=NULL,即第i个元素不存在 */?没有考虑链表头?链表尾?prior=p-prior;void ListTraverse(DuLinkList L,void(*visit)(ElemType) /* 由双链循环线性表L的头结点出发,正序对每个数据元素调用函数visit() */ visit(p-void ListTraverseBack(DuLinkList L,void(*visit)(ElemType) /* 由双链循环线性表L的头结点出发,逆序对每个数据元素调用函数visit()。另加 */ /* p指向尾结点 */
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1