当前位置:博客首页>>C/C++ >> 阅读正文

双向链表的实现(头插尾插和删除、遍历)

作者: 郑晓 分类: C/C++, 数据结构 发布于: 2017-03-09 12:38 浏览:5,141 评论(2)


关于双向链表和循环链表,维基上的解释是:

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

循环链表是一种链式存储结构,它的最后一个结点指向头结点,形成一个环。因此,从循环链表中的任何一个结点出发都能找到任何其他结点。循环链表的操作和单链表的操作基本一致,差别仅仅在于算法中的循环条件有所不同。

#include <stdio.h>
#include <stdlib.h>
//定义链接节点结构 包含了节点的数据域、前后指针域
typedef struct node {
    char *data;
    struct node *next;
    struct node *prior;
} node;
//定义链表结构 包含链表头节点指针、链表长度
typedef struct {
    node *head;
    int len;
}LinkedList;
//初始化双向链表 包括生成表头,初始化表长度
LinkedList * init() {
    LinkedList *L = NULL;
    L = (LinkedList *)malloc(sizeof(LinkedList));
    node *head =  (node *)malloc(sizeof(node));
    head->next = head;
    head->prior= head;
    L->head = head;
    L->len = 0;
    return L;
}
//向链表头部插入数据
void add_to_head(LinkedList *L, char *data) {
    node *dnode = (node *)malloc(sizeof(node));
    dnode->data = data;
    dnode->next = L->head->next;
    dnode->prior= L->head;
    L->head->next->prior = dnode;
    L->head->next = dnode;
    L->len++;
}
//向链表尾部插入数据
void add_to_tail(LinkedList *L, char *data) {
    node *dnode = (node *)malloc(sizeof(node));
    dnode->data = data;
    dnode->next = L->head;
    dnode->prior= L->head->prior;
    dnode->prior->next = dnode;
    L->head->prior = dnode;
    L->len++;
}
//从链表中删除下标为index的节点,index从0开始。
//index在链表前半段时从头部遍历 index在链表后半段时从头部逆向遍历
void del_data(LinkedList *L, int index) {
    if(index > L->len) {
        printf("index error");
        return;
    }
    node * node_tmp = NULL;
    int i=0;
    if(index < L->len/2) {
        node_tmp = L->head->next;
        for(i=0; i<index; i++) {
            node_tmp = node_tmp->next;
        }
    } else {
        node_tmp = L->head->prior;
        for(i=0; i<L->len-index; i++) {
            node_tmp = node_tmp->prior;
        }
    }
    node_tmp->prior->next = node_tmp->next;
    node_tmp->next->prior = node_tmp->prior;
    free(node_tmp);
    L->len--;
}
//遍历并打印链表(正向)
void foreach(LinkedList *L) {
    node *n = L->head->next;
    while(n != L->head) {
        printf("%s\n", n->data);
        n = n->next;
    }
}
//遍历并打印链表(逆向)
void rforeach(LinkedList *L) {
    node *n = L->head->prior;
    while(n != L->head) {
        printf("%s\n", n->data);
        n = n->prior;
    }
}
int main() {
    LinkedList *L;
    L = init();
    add_to_tail(L, "C");
    add_to_tail(L, "C++");
    add_to_tail(L, "C#");
    add_to_tail(L, "java");
    add_to_tail(L, "php");
    add_to_tail(L, "python");
    add_to_tail(L, "ruby");
    add_to_tail(L, "object-c");
    printf("打印链表\n");
    foreach(L);
    printf("删除index=2的元素 打印链表\n");
    del_data(L, 2);
    foreach(L);
    printf("逆向打印链表\n");
    rforeach(L);
    return;
}

以上代码的运行结果:

       

本文采用知识共享署名-非商业性使用 3.0 中国大陆许可协议进行许可,转载时请注明出处及相应链接。

本文永久链接: https://www.zh30.com/doubly-linked-list-1.html

双向链表的实现(头插尾插和删除、遍历):目前有2 条留言

用户评论头像 啊啊啊发表于 2020年12月16日 15:16[回复]

大神牛啊
Raymond[1周前]
给力啊, 终于找到一个能用的方法了
啊啊啊啊啊[1周前]
真的三个都是错的
123[1周前]
有没有pull时出现过js或css文
wj[1周前]
墙了
郑晓[3周前]
恭喜

用户评论头像 啊啊啊发表于 2020年12月16日 15:15[回复]

牛逼啊 大神

发表评论

change vcode