循环双链表的手动构建总结

来源:互联网 发布:多用户建站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;}

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

以上。

0 0
原创粉丝点击