数据结构(4)-线性表之双向链表

定义

在单向链表的元素中,添加一个指向前驱元素(也就是前一个元素)的指针域。元素中既有指向前驱元素的指针,又有指向后继元素的指针。这种形式的链表叫做双向链表。

其存储结构如下:

typedef int ElementType;

typedef struct DouNode{
    ElementType data;
    struct DouNode *next;
    struct DouNode *prior;
}DouNode;

typedef struct DouNode * linkList;

双向链表

初始化双向链表

TStatus InItDoubleLinkList(LinkList *dl) {
    (*dl) = (LinkList)malloc(sizeof(DouNode));
    if (*dl == NULL) {
        return T_ERROR;
    }
    (*dl)->data = -1;
    (*dl)->next = NULL;
    (*dl)->prior = NULL;
    return T_OK;
}
双向插入.png

插入双向链表的元素

双向链表由于存在两个指针域,所以插入的时候需要对其进行处理。

在第i个位置插入元素,大概步骤如下:

  • 创建新结点q
  • 遍历链表,找到需要插入的位置的前一个元素p
  • 将新元素q的前驱指向p,后继指向p->next
  • p->next的前驱指向新元素q
  • p的后继指向新元素q
TStatus InsertElement(LinkList *dl, int i, ElementType e) {
    if (*dl == NULL) {
        return T_ERROR;
    }
    LinkList p = (*dl);
    int j = 1;
    while (p && j < i) {
        p = p->next;
        j += 1;
    }
    if (p == NULL || j > i) {
        return T_ERROR;
    }
    
    // 新插入的元素
    LinkList q = (LinkList)malloc(sizeof(DouNode));
    q->data = e;
    
    // q的指向
    q->next = p->next;
    q->prior = p;
    
    // q后继元素的指向
    if (p->next != NULL) {
        p->next->prior = q;
    }
    
    // p的指向
    p->next = q;
    
    return T_OK;
}

删除双向链表的元素

双向删除.png

删除第i个位置的元素,大概步骤如下:

  • 遍历链表,找到想要删除的位置的前一个元素p
  • 创建新结点q,将要删除的元素赋值给p
  • p->next指向q->next,将q->next的前驱指向p
  • 释放q
TStatus DeleteElement(LinkList *dl, int i, ElementType *e) {
    if (*dl == NULL) {
        return T_ERROR;
    }
    LinkList p = (*dl);
    int j = 1;
    // 1234
    while (p && j < i) {
        p = p->next;
        j += 1;
    }
    if (p == NULL || j > i) {
        return T_ERROR;
    }
    
    LinkList delQ = p->next;
    *e = delQ->data;
    p->next = delQ->next;
    if (delQ->next != NULL) {
        delQ->next->prior = p;
    }
    
    free(delQ);
    
    return T_OK;
}

也可以通过数据来删除具有相同的数据的元素,此处我们只考虑链表中最多只有一个元素数据为传入的数据。

TStatus DeleteElementWithData(LinkList *dl, ElementType e) {
    if (*dl == NULL) {
        return T_ERROR;
    }
    LinkList p = (*dl);
    
    while (p != NULL) {
        if (p->data == e) {
            break;
        }
        p = p->next;
    }
    
    if (p == NULL) {
        return T_ERROR;
    }
    // 要删除的前一个元素
    LinkList preQ = p->prior;
    preQ->next = p->next;
    if (p->next != NULL) {
        p->next->prior = preQ;
    }
    free(p);
    
    return T_OK;
}

获取元素

获取双向链表第i个位置的元素。

  • 遍历链表找到第i个位置前一个位置的元素p
  • 容错判断
  • 返回p->next
TStatus GetElement(LinkList *dl, int i, ElementType *e) {
    if (*dl == NULL || i < 1) {
        return T_ERROR;
    }
    
    LinkList p = (*dl);
    int j = 1;
    
    while (p && j < i) {
        p = p->next;
        j += 1;
    }
    
    if (p->next == NULL && j > i) {
        return T_ERROR;
    }
    
    *e = p->next->data;
    
    return T_OK;
}

整表创建

采用尾插法整表创建双向链表:

  • 初始化链表
  • 遍历传入的数据,循环创建结点,加到链表的尾部
TStatus createDoubleLinkList(LinkList *dl, int arr[], int size) {
    *dl = (LinkList)malloc(sizeof(DouNode));
    if (*dl == NULL) {
        return T_ERROR;
    }
    (*dl)->data = -1;
    (*dl)->prior = NULL;
    (*dl)->next = NULL;
    
    LinkList r = (*dl);
    LinkList p;
    for (int i = 0; i < size; i++) {
        int e = arr[i];
        p = (LinkList)malloc(sizeof(DouNode));
        if (p == NULL) {
            return T_ERROR;
        }
        p->data = e;
        p->prior = r;
        p->next = NULL;
        r->next = p;
        r = p;
    }
    
    return T_OK;
}

双向循环链表

双向循环链表的概念其实和单向循环链表类似,也是将链表中最后一个结点的next针由空指针改为指向头指针指向的元素,不同的是我们还需要将头指针指向的元素的前驱指针prior指向最后一个结点,这样链表就形成了一个环。

双向循环.png

初始化双向循环链表

初始化双向循环链表的时候,需要将自己的nextprior都指向自己。

TStatus InItDoubleLinkList(LinkList *dl) {
    (*dl) = (LinkList)malloc(sizeof(DouNode));
    if (*dl == NULL) {
        return T_ERROR;
    }
    (*dl)->data = -1;
    (*dl)->next = (*dl);
    (*dl)->prior = (*dl);
    return T_OK;
}

双向循环链表删除元素

TStatus DeleteElement(LinkList *dl, int i, ElementType *e) {
    if (*dl == NULL) {
        return T_ERROR;
    }
    
    LinkList p = (*dl);
    int j = 1;
    
    // 找到需要删除的位置的前一个位置
    while (p && j < i && p->next != (*dl)) {
        p = p->next;
        j += 1;
    }
    
    if (p->next == NULL || j > i) {
        return T_ERROR;
    }
    
    LinkList delQ = p->next;
    *e = delQ->data;
    delQ->prior = p;
    p->next = delQ->next;
    free(delQ);
    
    return T_OK;
}

可以看出来,双向循环链表和双向链表的操作类似,只是多了循环的相关处理。

线性表总结

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

推荐阅读更多精彩内容