循环双链表的手动构建总结
来源:互联网 发布:多用户建站cms系统 编辑:程序博客网 时间:2024/05/17 07:40
我们常用的是单链表的算法。虽然双链表和循环双链表的算法常常被拿来作为一种设计的思路,也常假想有一个循环双链表,对它进行操作,实际上我从没动手写过循环双链表。
在手动实现单链表的习题多道以后,有了一种对简单代码的熟悉度,以及轻微的掌控感。我觉得自己知道自己写的是什么,并能在大脑中视觉化执行路径了。作为一个开始时,在自己大脑中跑代码会有轻微恐慌的人来说,这是一个进步了。
也让我明白,行动是打开枷锁的钥匙。不敢说唯一,因为或许还要其他的途径。
通过写算法的过程,我感受到的不仅仅是作为一个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;}
这种是直接反应思路的一种代码结构,看着有些丑,至于怎样重构,我没有思路。
以上。
- 循环双链表的手动构建总结
- 循环链表的构建
- 手动构建PE文件
- Querydsl 手动构建Predicate
- 不通过rss文件,程序手动构建CEikEdwin的问题
- 手动利用Apache Ant构建部署自己的Java项目
- 循环的总结
- 实现手动触摸和自动无限循环的gallery
- Gallery自动循环滚动以及手动滚动的平滑切换
- Gallery自动循环滚动以及手动滚动的平滑切换
- Gallery自动循环滚动以及手动滚动的平滑切换
- ViewPager,实现真正的无限循环(定时+手动)
- ViewPager,实现真正的无限循环(定时+手动)
- Gallery自动循环滚动以及手动滚动的平滑切换
- Gallery自动循环滚动以及手动滚动的平滑切换
- ViewPager,实现真正的无限循环(定时+手动)
- OC手动内存管理的规则总结
- List循环与Map循环的总结
- SQL Server 异常处理机制(Begin try Begin Catch)
- 2017顺丰科技java开发
- Linux下各类环境搭建
- hadoop 2.x之HDFS HA讲解之六 HA机器规划
- 使用gradle编译打包java项目
- 循环双链表的手动构建总结
- Python 实现火车票查询工具--实验楼
- 【NOIP2012模拟10.9】电费结算
- Android个人学习小结2016.8
- iOS 中 Block 和 Closures 简介
- 内存缓存LruCache实现原理
- Hadoop(07) MapReduce原理
- Android Studio 汉化包
- 活久见的重构 - iOS 10 UserNotifications 框架解析