线性表(三)——双向链表的表示和实现

在上篇文章中我们分析讨论了线性表的链式存储结构。链式存储结构表示的线性表主要分为单链表、单循环链表和双向循环链表三种。单链表和单循环链表在上篇文章已经做过讲解了,这篇文章将分析讨论链式存储结构中的双向链表的实现原理。

线性表-概述
线性表(一)——顺序表
线性表(二)——单链表的表示和实现
线性表(三)——双向链表的表示和实现

1、 双向链表的存储结构

双向链表中每一个结点除后继指针域外还有一个前驱指针域。和单链表一样,双向链表也有带头结点和不带头结点两种结构,带头结点的双向链表更为常见。另外,双向链表也可以有循环和非循坏两种结构,循环结构的双向链表更为常用。本文只讨论带头结点的双向循环链表的实现。
在双向循环链表中,每个结点包括三个域,分别是data域、next域和prior域,其中data域为数据域,next域为指向后继结点的指针域,prior域为指向前驱结点的指针域。如下图所示是双向循环链表结点的结构图。


由此总结出用C语言表示的双向循环链表如下:

typedef struct Node{
    DataType   data;//存放数据
    struct Node *next; //存放指向后继结点的指针
    struct Node *prior; //存放指向前驱结点的指针
} DLNode;

在单链表中查找当前结点的后继结点并不困难,可以通过当前结点的next指针进行,但是要查看当前结点的前驱结点,就要从头指针head开始重新进行。对于一个需要频繁进行查找当前结点的后继结点和当前结点的前驱结点的程序来说,使用单链表的时间效率是非常低的,双向链表是有效解决这类问题的最佳选择。
带头结点的双向循环链表的结构图如下图所示。


2、双向循环链表的操作实现

在双向循环链表中,设指针p指向双向循环链表中的第i个结点,则p->next指向第i+1个结点,p->next->prior仍指向第i个结点,即p->next->prior==p;同理p->prior指向的是第i-1个结点,p->prior->next仍指向第i个结点,即p->prior->next==p。

2.1、初始化 ListInitiate(DLNode **head)

在初始化操作前,头指针参数head没有具体的地址值,在初始化操作时,头指针参数head才得到了具体的地址值,而这个地址值要返回给调用函数,所以此时头指针参数head要设计成指针的指针类型。

void ListInitiate(DLNode **head) {
    *head = (DLNode *) malloc(sizeof(DLNode));
    (*head)->prior = *head;
    (*head)->next = *head;
}

2.2、插入数据元素 ListInsert(DLNode *head, int i, DataType x)

在带头结点的双向循环链表head第i (0\leq i\leq size)个位置前插入数据元素x的结点,插入成功返回1,插入失败返回0。

int ListInsert(DLNode *head, int i, DataType x) {
    DLNode *p = head->next;
    int j = 0;
    while (p != head && j < i) {
        p = p->next;
        j++;
    }

    if (j != i) {
        printf("插入的位置错误");
        return 0;
    }

    DLNode *s = (DLNode *) malloc(sizeof(DLNode));
    s->data = x;

    s->prior = p->prior;
    p->prior->next = s;
    s->next = p;
    p->prior = s;
    return 1;
}
  1. 首先在链表中找到第i个位置的结点用p表示。
  2. 动态申请一个结点存储空间并由指针s指示,并把数据元素x赋值给新结点的数据元素域s->data = x;
  3. 修改新结点的前驱结点的指针指向p的前驱结点:s->prior = p->prior,p的前驱结点的后继结点指针指向新结点s:p->prior->next = s。
  4. 新结点s的后继结点指针指向p:s->next = p。
  5. p的前驱结点指针指向s。

插入操作如下图所示:


2.3、删除数据元素 ListDelete(DLNode *head, int i, DataType *x)

删除带头结点的双向循环链表的第i(0\leq i\leq size)个结点,被删除的结点的数据域值由x带回,删除成功返回1,删除失败返回0。

int ListDelete(DLNode *head, int i, DataType *x) {
    DLNode *p = head->next;
    int j = 0;
    while (p->next != head && j < i) {
        p = p->next;
        j++;
    }
    *x = p->data;
    if(j!=i){
        printf("删除位置参数错误");
        return 0;
    }
    p->prior->next = p->next;
    p->next->prior = p->prior;
    free(p);
    return 1;
}
  1. 首先在链表中找到第i个位置的结点用p表示。
  2. 将第i个结点的数据元素的值赋值给x:*x = p->data。
  3. 修改p的前驱结点的后继结点的指针指向p的后继结点:p->prior->next = p->next。
  4. 修改p的后继结点的前驱结点的指针指向p的前驱结点。

删除操作如下图所示:

2.4、获取当前元素个数ListLength(DLNode *head)

int ListLength(DLNode *head){
    DLNode *p = head;
    int size = 0;
    while (p->next != head){
        p = p->next;
        size++;
    }
    return size;
}
  1. 在循环前指针变量p指向头结点,计数变量size赋值0。
  2. 循环结束的条件为p->next != head,在循环中,每次让指针p指向它的值指向后继结点,让计数变量size加1。
  3. 函数返回计数变量size。

2.5 销毁单链表ListDestory(DLNode **head)

和单链表一样,双向循环链表的结点空间是程序动态申请的,而系统只负责自动回收程序中静态分配的内存空间。

void ListDestory(DLNode **head){
    DLNode *p = *head;
    DLNode *p1;
    int n = ListLength(*head);
    for (int i = 0; i <= n; i++) {
        p1 = p;
        p = p->next;
        free(p1);
    }
    *head = NULL;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352