我们常用的是单链表的算法。虽然双链表和循环双链表的算法常常被拿来作为一种设计的思路,也常假想有一个循环双链表,对它进行操作,实际上我从没动手写过循环双链表。

在手动实现单链表的习题多道以后,有了一种对简单代码的熟悉度,以及轻微的掌控感。我觉得自己知道自己写的是什么,并能在大脑中视觉化执行路径了。作为一个开始时,在自己大脑中跑代码会有轻微恐慌的人来说,这是一个进步了。

也让我明白,行动是打开枷锁的钥匙。不敢说唯一,因为或许还要其他的途径。

通过写算法的过程,我感受到的不仅仅是作为一个coder写作的乐趣,更能慢慢实践那些听到的道理。很长时间,我会在一天中不专注的时间里,有轻度的抑郁症患者才有的症状。比如,怀疑一个明显的道理,逼着自己去证明,证明不了就会引起下一次的雪崩式的恐慌。担心自己就此分崩离析。然后任由它去后才发现,不过是柳暗花明的又一番景象,什么都没改变。

开始深深赞同,颠倒妄想或许指的就是这些念头。善护念的重要性就隐含其中。我不清楚颠倒妄想究竟能不能带来物质上变化,曾经我担心会让自己变得不能思考,变得更笨或者怎样,发现并没有。只是当你的念头沉浸在痛苦的妄想中时,内心好痛苦。

我说的话都是自己经历过,痛苦过。我很多次挣扎时,希望有人过来和我讲一讲其中的道理,告诉我不要怕。没有任何人来。但是我很感激,它逼着你去思考,去从其他途径去了解我们是什么。最感激的是遇到了书中的老师,遇到了佛经中那些让我升起信心的佛陀的话。

好像跑偏了。但是,我想说的仍然是:写代码是一种思考。思考本身是无为法,那么对其他事物的思考,和写代码都是殊途同归。

我们总是在自己的脑海中构建一个交织的世界。每天吸收新的知识,新的知识将添加进原有的知识网路。每天的思考,会让头脑中的知识互相之间再次加强连接或者形成新的连接。

这样的过程便会让你认知像指数于洋爆炸。想一想,人真的是一个神奇物种。可以不断去套索认知的边界。

希望以上的文字能给你带来的是信心而不是困惑。

回到循环双链表的构建问题。

由一道题目开始:

判断一个带头的循环双链表是否对称

思路:首先得构建一个循环双链表,主要是明晰结点的特征是有两个指针域。单纯的双链表会有两个结点的指针域为空:头结点的prior指针域和尾结点的next指针域。循环就是让头结点的prior指针域指向尾结点,尾结点的next指针指向头结点。判断是否对称只需要两个方向遍历,如果有奇数个结点,两个方向游走的指针相同时表示对称。偶数个结点,判断的是正向指针的next结点与反向指针的prior结点相同并且数值相同。正反向遍历时,结点值相同时才相向移动。否则,途中有不同的就退出,判断为不对称。

代码会更清晰:

#include <iostream>
#include <ctime>
#include <vector>
#include <algorithm>using namespace std;
typedef int ElemType;
#define MAX 100typedef struct Node
{ElemType data;struct Node *prior; // 前向指针struct Node *next; // 后向指针
}SNode, *SList;// 生成一个循环双链表,数值随机生成
// 返回指向生成链表的头结点指针SList generateSymList(int n) // n是结点个数
{srand((unsigned)time(NULL));// 定义头结点SList sl = (SList)malloc(sizeof(SNode));sl->prior = NULL;sl->next = NULL;SNode *r = sl;//尾插法建立链表:元素递增有序for(int i = 0; i < n; i++){SNode *s = (SNode*)malloc(sizeof(SNode));s->data = rand() % MAX; // 随机值s->prior = r;s->next = sl; //r->next = s;sl->prior = s; //需要更新的是sl的prior,r跟踪是工作结点r = s;}return sl;
}bool IsSymmetrical(SList sl) // sl是循环双链表的头结点
{SNode *p = sl->next; // 第一个结点SNode *q = sl->prior; // 最后一个结点while(p && q){if(p == q || (p->next == q && q->prior == p && p->data == q->data))// 如果比较到p和q相等或者对称{return true;}else{if(p->data == q->data) // 只有数据相同时,才有机会进行下一次的比较{p = p->next;q = q->prior;}else // 否则直接判定不对称{return false;}}}return false;
}int main()
{int n;cout << "Input the number of nodes: ";cin >> n ;SList sl = generateSymList(n);// 正向输出SNode *p = sl->next; //指向第一个结点cout << "正向 : ";while(p != sl->prior) //p指向最后一个结点时结束{cout << p->data << " ";p = p->next;}cout << p->data; //最后一个结点值需要特别输出cout << endl;// 反向输出p = sl->prior; //指向最后一个结点cout << "反向 : ";while(p != sl->next) //p指向第一个结点时结束{cout << p->data << " ";p = p->prior;}cout << p->data; //第一个结点也需要特别输出cout << endl;// 题目的主要逻辑bool b = IsSymmetrical(sl);if(b){cout << "Yes!" << endl;}else{cout << "No!" << endl;}return 0;
}

如果要代码解析的话,先看结点特征:

typedef struct Node
{ElemType data;struct Node *prior; // 前向指针struct Node *next; // 后向指针
}SNode, *SList;

生成过程:

SList generateSymList(int n) // n是结点个数
{srand((unsigned)time(NULL));// 定义头结点SList sl = (SList)malloc(sizeof(SNode));sl->prior = NULL;sl->next = NULL;SNode *r = sl;//尾插法建立链表for(int i = 0; i < n; i++){SNode *s = (SNode*)malloc(sizeof(SNode));s->data = rand() % MAX; // 随机值s->prior = r;s->next = sl; //新的结点next域指向头结点,因为用r在跟踪当前工作结点,因此,这个结点的next域会更新为指向下一个结点r->next = s; // 这句就是在更新新结点的前驱的next域指向新结点sl->prior = s; //需要更新的是sl的prior,r跟踪是工作结点r = s;}return sl;
}

判断过程:

bool IsSymmetrical(SList sl) // sl是循环双链表的头结点
{SNode *p = sl->next; // 第一个结点SNode *q = sl->prior; // 最后一个结点while(p && q){if(p == q || (p->next == q && q->prior == p && p->data == q->data))// 如果比较到p和q相等或者对称{return true;}else{if(p->data == q->data) // 只有数据相同时,才有机会进行下一次的比较{p = p->next;q = q->prior;}else // 否则直接判定不对称{return false;}}}return false;
}

这种是直接反应思路的一种代码结构,看着有些丑,至于怎样重构,我没有思路。

以上。

循环双链表的手动构建总结相关推荐

  1. 建立循环双链表(尾插法)

    该方法是将节点插入在当前循环双链表的表尾上,为此增加一个尾指针r ,并始终指向当前链表的尾节点,最后让r->next 指向头结点.头结点的prior 指向尾节点. 注意:这里头结点,尾节点 要相 ...

  2. 建立循环双链表(头插法)

    该方法从一个空表开始,读取数组a中元素,生成新节点,将读取的数据存在该节点的数据域中,然后将该新节点插入到当前节点的表头上,直到结束为止. 双链表的存储结构: typedef strcut DLink ...

  3. 第四周实践项目6 循环双链表应用

    /* *Copyright (c) 2017,烟台大学计算机与控制工程学院 *All rights reserved. *文件名称:项目6-设非空线性表ha和hb都用带头节点的循环双链表表示.设计一个 ...

  4. 【数据结构】线性表的链式表示-循环单链表、循环双链表、静态链表

    循环单链表 从任何一个结点出发都能访问到链表的每一个元素 判空条件不是头节点的后继指针是否为空,而是它是否等于头指针 有时对单链表常做的操作实在表头和表尾进行的,此时可对循环单链表不设头指针而仅设尾指 ...

  5. (王道408考研数据结构)第二章线性表-第三节3:循环单链表和循环双链表

    文章目录 一:循环链表定义 二:循环单链表 三:循环双链表 一:循环链表定义 循环链表:规定好头尾结点的指向形成成环状 循环单链表:其尾节点的next指针由原本的空改为指向头结点 循环双链表:其尾节点 ...

  6. 判断循环双链表是否对称

    题目:设计一个算法判断带头结点的循环双链表是否对称 分析:         简单分析,我们可以设置两个指针,pre和next,从头结点出发,进行比较,若pre与next所指值不同,则不对称,若pre和 ...

  7. 数据结构-循环双链表

    循环链表,就是把链表给首尾相连,即尾结点的next指向L头结点,而循环双链表不仅尾结点指向头结点,且头结点的prior指向尾结点,判断为空时,只要看尾结点下一个是否指向头结点,循环链表的操作和链表的操 ...

  8. [C语言实现]带你手撕带头循环双链表

    目录 什么是双链表? 带头结点的优势: 双链表的实现: 什么是循环双链表? 众所周知,顺序表的插入和删除有时候需要大量移动数据,并且每次开辟空间都可能会浪费大量内存和CPU资源,于是我们有了链表,我们 ...

  9. 线性表文档之循环双链表

    循环双链表 定义 概念 循环双链表就是在双链表的基础上,见链表的尾结点和链表的第一个结点连接起来,形成一个循环. 如果是带头结点的循环双链表,则将链表的尾结点的 next 指针指向链表的头结点,将链表 ...

最新文章

  1. 淘宝亿级高并发分布式架构演进之路
  2. 使用Spring MVC统一异常处理实战
  3. php 公交 查询系统,php定做单城市公交路线查询系统
  4. .net函数查询_特来电智能分析平台动态查询架构创新实践
  5. BNU10791:DOTA选人
  6. MySql事务隔离级别概述
  7. mysql 错误提示_Mysql必读mysql常见的错误提示问题处理小结
  8. Java编写ASCII码转换
  9. 2019蓝桥杯决赛Java_2019年蓝桥杯省赛总结
  10. window驱动备份与安装
  11. 云初起微方案中下单人、联系人、下载者三者之间是什么关系?
  12. 安卓-LBS地图显示
  13. Unity动画系统学习方向
  14. 大学软件工程总结,总结到位
  15. 这才是陆奇看重的创业者:最小19岁,开拖拉机的斯坦福毕业生,弃医从文的武大学生……...
  16. 神经网络知识梳理——从神经元到深度学习
  17. 【缓存】@Caching和@CacheConfig
  18. nodejs websocket 实现简易聊天室功能
  19. 团队成长的一些方式方法
  20. 大疆工程师:如何利用6年时间成为一名优秀的机器人工程师

热门文章

  1. 多吉搜索不能用了_「转载」一个纯粹的中文搜索引擎:「Doge Doge」多吉搜索
  2. vba有下拉框的模糊查找_巧用数据验证制作模糊匹配的下拉列表
  3. fileservice 类代码放哪里_一步步开发Windows服务(Windows Service)[转]
  4. MySQL-数据类型 整理总结
  5. 银行考试计算机重点知识,银行计算机考试试题
  6. 顺德职业技术学院计算机专业录取线,顺德职业技术学院录取分数线2021是多少分(附历年录取分数线)...
  7. Java InputStream转换为String
  8. Python字符串转换为小写字母– str.lower()
  9. linux的shell类型_Linux中有哪些不同类型的Shell?
  10. Java中的Collections类– java.util.Collections