小猪的数据结构辅助教程——2.7 线性表中的双向循环链表
来源:互联网 发布:羊毛毡淘宝哪家好 编辑:程序博客网 时间:2024/04/26 22:26
小猪的数据结构辅助教程——2.7 线性表中的双向循环链表
标签(空格分隔): 数据结构
本节学习路线图与学习要点
学习要点:
1.了解引入双向循环链表的原因
2.熟悉双向循环链表的特点以及存储结构
3.掌握双向循环链表的一些基本操作的实现逻辑
4.掌握逆序输出双向循环链表元素逻辑
1.双向循环链表的引入
2.双向循环链表的存储结构
双向循环链表的特点:
上面也说了,空间换时间,比起循环链表只是多了一个指向前驱的指针
特点的话:
判断空表:L ->next = L -> prior = L;
存储结构:
typedef struct LNode{ ElemType data; //数据域 struct LNode *prior; //前驱指针 struct LNode *next; //后继指针}LNode; typedef struct LNode *LinkList;
双向循环链表的结构图:
3.相关基本操作的代码实现
1)构建空表
Status InitList(LinkList L){ L = (LinkList)malloc(sizeof(LNode)); if(!L)exit(ERROR); else L ->next = L ->prior = L; return OK;}
逻辑解析:
很简单,就是头结点自己指自己而已~
2)将表置空
void ClearList(LinkList L){ LinkList p = L ->next; //指向第一个结点 while(p != L) { p = p ->next; //指向下一个结点 free(p->prior); //释放该结点的前驱结点 } L ->next = L ->prior = L; //自己指自己 }
3)判断是否为空表
Status ListEmpty(LinkList L){ return L->next == L && L ->prior == L?TRUE:FALSE;}
4)销毁表
void DestoryList(LinkList L){ ClearList(L); free(L); L = NULL;}
5)获得表长度
int ListLength(LinkList L){ int i = 0; LinkList p = L ->next; while(p != L) { i++; p = p ->next; } return i;}
6)获得表中第i个元素的值
Status GetElem(LinkList L,int i,ElemType *e){ int j = 1; LinkList p = L ->next; //指向第一个结点 while(p != L && j < i) //指针后移 { j++; p = p ->next; } if(p == L || j > i)return ERROR; //找不到该元素 e = p ->data; return OK; }
7)查找表中是否存在满足条件的元素
int LocateElem(LinkList L,ElemType e,Status(*compare)(ElemType,ElemType)) { int i = 0; LinkList p = L ->next ->next; //指向第一个结点 while(p != L ->next) { i++; if(compare(p->data,e))return i; p = p ->next; } return 0; //找不到,返回0 }
8)获得某个节点的直接前驱
Status BeforeElem(LinkList L,ElemType choose,ElemType *before){ LinkList p = L ->next ->next; //指向第二个结点 while(p != L) //未指向头结点 { if(p ->data == choose) { before = p ->prior ->data; return OK; } p = p ->next; } return ERROR;}
9)获得某个节点的直接后继
Status NextElem(LinkList L,ElemType choose,ElemType *behind){ LinkList p = L ->next ->next; //指向第二个结点 while(p != L) { if(p ->prior ->data == choose) { behind = p ->data; return OK; } p = p ->next; } return ERROR;}
10)返回第i个元素的地址
LinkList GetElemAdd(LinkList L,int i){ int j; LinkList p = L; if(i < 0 || i > ListLength(L))return NULL; //判断i值位置是否合法 for(j = 1;j < = i;j++) { p = p ->next; } return p;}
11)往第i个位置插入元素
Status ListInsert(LinkList L,int i,ElemType e){ LinkList p,q; //判断i值是否合法 if(i < 1 || i > ListLength(L) + 1)return ERROR; p = GetElemAdd(L,i - 1); //NULL的话说明,第i个结点的前驱不存在, //这里假设头节点为第一个结点的前驱 if(!p)return ERROR; q = (LinkList)malloc(sizeof(LNode)); if(!q)return ERROR; q ->data = e; //给新结点赋值 q ->prior = p; //新结点的前驱为第i - 1个结点 q ->next = p ->next; //新结点的后记为第i个结点 p ->next ->prior = q; //第i个结点前驱指向新结点 p ->next = q; //第i-1个结点的后继指向新结点 return OK; }
实现逻辑图:
12)删除第i个位置的元素
Status ListDelete(LinkList L,int i,ElemType *e){ LinkList p; if(i < 1)return ERROR; //判断删除位置是否合法 p = GetElemAdd(L,i); if(!p)return ERROR; //为NULL说明第i个元素不存在 e = p ->data; p ->prior ->next = p ->next; //i-1个结点的后继指向滴i+1个结点 p ->next ->prior = p ->prior; //第i+1个结点的前驱指向第i - 1个结点 free(p); //释放第i个结点 return OK; }
实现逻辑图:
嘿嘿,是不是觉得少了个遍历表中元素的基本操作呢,别急,我们下面写个例子,
按正序遍历链表,以及逆序来遍历表中的所有元素~
4.简单例子:正序和逆序遍历表中元素
运行截图:
代码实现:
#include <stdio.h>#include<stdlib.h>#define OK 1#define ERROR 0#define TRUE 1#define FALSE 0typedef int ElemType; typedef int Status;typedef struct LNode{ ElemType data; //数据域 struct LNode *prior; //前驱指针 struct LNode *next; //后继指针}LNode; typedef struct LNode *LinkList;//定义一个创建N个结点的方法 LinkList ListCreate(int N) { LinkList p,q,head; int i,data; q = head; head = (LinkList)malloc(sizeof(LNode)); head ->prior = head; head ->next = head; p = head; for(i = 0;i < N;i++) { printf("请输入第%d个结点的值:",i + 1); scanf("%d",&data); q = (LinkList)malloc(sizeof(LNode)); q ->data = data; p ->next = q; q ->prior = p; q ->next = head; head ->prior = q; p = q; } return head; } //定义一个打印结点数据的方法 void PrintNode(ElemType e) { printf("%d\t",e); } //定义一个正序输出链表的方法 void ListTraverse(LinkList L) { LinkList p = L->next; //指向首元结点 while(p!=L) { PrintNode(p->data); p = p ->next; } printf("\n"); } //定义一个逆序输出链表的方法 void ListTraverseBack(LinkList L) { LinkList p = L ->prior; //指向最后一个结点 while(p!=L) { PrintNode(p->data); p = p ->prior; } printf("\n"); } int main() { LinkList p; int N = 0; printf("请输入双向链表的结点个数:"); scanf("%d", &N); p = ListCreate(N); printf("正序打印链表中的结点:\n"); ListTraverse(p); printf("逆序打印链表中的结点:\n"); ListTraverseBack(p); return 0; }
很简单,就不BB了~
5.本节示例代码下载:
https://github.com/coder-pig/Data-structure-auxiliary-tutorial/blob/master/List/list5.c
https://github.com/coder-pig/Data-structure-auxiliary-tutorial/blob/master/List/list6.c
1 0
- 小猪的数据结构辅助教程——2.7 线性表中的双向循环链表
- 小猪的数据结构辅助教程——2.4 线性表中的循环链表
- 小猪的数据结构辅助教程——2.3 线性表中的静态链表
- 小猪的数据结构辅助教程——2.1 线性表中的顺序表
- 小猪的数据结构辅助教程——2.2 线性表中的单链表
- 小猪的数据结构辅助教程——3.2 栈与队列中的链栈
- 小猪的数据结构辅助教程——前言
- 小猪的数据结构辅助教程——3.1 栈与队列中的顺序栈
- 小猪的数据结构辅助教程——1.数据结构与算法绪论
- 小猪的数据结构辅助教程——2.5 经典例子:约瑟夫问题的解决
- 小猪的数据结构辅助教程——3.3 栈的应用实例:逆波兰式(RPN)
- 数据结构与算法——线性表链式存储(双向循环链表)
- 小猪的数据结构辅助教程——2.6 经典例子:魔术师发牌问题和拉丁方阵问题
- <数据结构>线性表.循环链表和双向链表
- 数据结构---线性表----循环链表和双向链表
- 数据结构之线性结构--双向循环链表
- 数据结构之——循环双向链表的实现
- 【数据结构】-线性表-双向循环链表-1328:链表的基本操作【好题】
- [看书日记20151226]MeasureSpec和LayoutParams的对应关系 , View的工作流程
- 用递归计算阶乘!
- 8路监控音频怎么接
- 点子汇聚
- 8天学通MongoDB——第八天 驱动实践
- 小猪的数据结构辅助教程——2.7 线性表中的双向循环链表
- openwrt下安装lighttpd/webdav模块及改变安装目录
- 创建一个类的实例,修改类中定义为private的变量的值
- 计算兔子繁殖,斐波那契数列!
- project euler 103
- 很全的正则表达式
- 2015_12_26 A. The Text Splitting
- Educational Codeforces Round 4 总结
- project euler 104