数据结构2.(双向链表,循环链表及内核链表)

1.双向链表

1.1双向链表的节点定义

cs 复制代码
//节点存放数据的类型 
 typedef int datatype;
 /* 节点类型 */
 typedef struct node 
{
 datatype data;        //存放数据空间              
struct node *ppre;         //存放前一个节点地址         
struct node *pnext;           //存放下一个节点地址      
}linknode;

1.2双向链表的创建

申请节点空间,对pnext和ppre赋值为NULL, 返回空白节点地址。

cs 复制代码
linknode *create_empty_linklist(void)
 {
    linknode *ptmpnode = NULL;
    ptmpnode = malloc(sizeof(linknode));
    if (NULL == ptmpnode)
    {
        perror("fail to malloc");
        return NULL;
    }
    ptmpnode->ppre = NULL;
    ptmpnode->pnext = NULL;
    return ptmpnode;
 }

1.3双向链表头插法

1)申请节点

2)存放数据

3)pnext赋值为phead->pnext

4)ppre赋值为phead的地址

5)phead->pnext赋值为新申请节点地址

6)如果有后一个节点,需要让后一个节点的ppre指向该节点

cs 复制代码
//双向链表头插
void insert_head_linklist(linknode *phead, datatype tmpdata)
{   
    linknode *ptmpnode = NULL;

    ptmpnode = malloc(sizeof(linknode));
    if (NULL == ptmpnode)
    {
        perror("fail to malloc");
        return;
    }
    ptmpnode->data = tmpdata;
    ptmpnode->pnext = phead->pnext;
    ptmpnode->ppre = phead;
    phead->pnext = ptmpnode;
    if (ptmpnode->pnext != NULL)
    {
        ptmpnode->pnext->ppre = ptmpnode;
    }
    return;
}

1.4双向链表的销毁

与单向链表相同

cs 复制代码
void destroy_linklist(linknode **pphead)//销毁需要传递二级指针,因为要将外部指针指向空
{
    linknode *pfreenode = NULL;
    linknode *ptmpnode = NULL;
    ptmpnode = *pphead;
    pfreenode = *pphead;
    while(ptmpnode != NULL)
    {
        ptmpnode = ptmpnode->pnext;
        free(pfreenode);
        pfreenode = ptmpnode;
    }
    *pphead = NULL;
}

1.5双向链表的遍历

与单向链表无异

cs 复制代码
void show_linklist(linknode *phead)
 {
    linknode *ptmpnode = NULL;
    ptmpnode = phead->pnext;
    while (ptmpnode != NULL)//判断下一个节点是不是空
    {
        printf("%d ", ptmpnode->data);
        ptmpnode = ptmpnode->pnext;
    }
    printf("\n");
    return;
 }

1.6双向链表的查找

与单向链表相同

cs 复制代码
//数返回链表中第一个指定元素节点的地址
 void find_linklist(linknode *phead, datatype tmpdata)
 {
    linknode *ptmpnode = NULL;
    linknode *pprenode = NULL;
    pprenode = phead;
    ptmpnode = pprenode->pnext;
    while (ptmpnode != NULL)
    {
        if (ptmpnode->data == tmpdata)
        {
            printf("%p\n",&pprenode->pnext);
            break;
        }
        else
        {
            ptmpnode = ptmpnode->pnext;
            pprenode = pprenode->pnext;
        }
    }
    return;
 }

1.7双向链表的修改

与双向链表一致

cs 复制代码
//将链表中指定元素的值更新为新值
 void update_linklist(linknode *phead, datatype olddata, datatype newdata)
 {
    linknode *ptmpnode = NULL;
    ptmpnode = phead;
    while (ptmpnode != NULL)
    {
        if (ptmpnode->data == olddata)
        {
            ptmpnode->data = newdata;
        }
        ptmpnode = ptmpnode->pnext;
    }
    return;
 }

1.8双向链表的删除

cs 复制代码
//删除链表中所有的某一指定元素
void delete_linklist(linknode *phead, datatype tmpdata)
{
    linknode *ptmpnode = NULL;
    linknode *pfreenode;
    ptmpnode = phead->pnext;
    while (ptmpnode != NULL)
    {
        if (ptmpnode->data == tmpdata)
        {
            ptmpnode->ppre->pnext = ptmpnode->pnext;
            if(ptmpnode->pnext!=NULL)
            {
                ptmpnode->pnext->ppre=ptmpnode->ppre;
            }
            pfreenode = ptmpnode;
            ptmpnode = ptmpnode->pnext;
            free(pfreenode);
            
        }
        else 
        {
            ptmpnode = ptmpnode->pnext;
        }
    }
    return;
}

1.9双向链表的尾插法

1)申请节点

2)将节点的pnext赋值为NULL

3)找到链表最后一个节点

4)将节点的ppre赋值为最后一个节点地址

5)将最后一个节点的pnext赋值为新申请节点

cs 复制代码
int insert_tail_linklist(linknode *phead, datatype tmpdata)
{
    linknode *ptmpnode = NULL;
    linknode *plastnode = NULL;

    ptmpnode = malloc(sizeof(linknode));
    if (NULL == ptmpnode)
    {
        perror("fail to malloc");
        return -1;
    }

    plastnode = phead;
    while (plastnode->pnext != NULL)
    {
        plastnode = plastnode->pnext;
    }

    ptmpnode->data = tmpdata;
    ptmpnode->pnext = NULL;
    ptmpnode->ppre = plastnode;
    plastnode->pnext = ptmpnode;

    return 0;
}

2.循环链表

2.1循环链表的创建

cs 复制代码
// 创建空链表 
linknode *create_empty_linklist(void)
{
    linknode *ptmpnode = NULL;

    ptmpnode = malloc(sizeof(linknode));
    if (NULL == ptmpnode)
    {
        perror("fail to malloc");
        return NULL;
    }

    ptmpnode->pnext = ptmpnode->ppre = ptmpnode;

    return ptmpnode;
}

2.2循环链表头插法

原理图解:

cs 复制代码
//头插法
void insert_head_linklist(linknode *phead, datatype tmpdata)
{
    linknode *ptmpnode = NULL;

    ptmpnode = malloc(sizeof(linknode));//申请节点
    if (NULL == ptmpnode)
    {
        perror("fail to malloc");
        return;
    }

    ptmpnode->data = tmpdata;//存放数据
    ptmpnode->pnext = phead->pnext;
    ptmpnode->ppre = phead;
    phead->pnext = ptmpnode;
    ptmpnode->pnext->ppre = ptmpnode;

    return;
}

2.3循环链表尾插法

原理图解:

cs 复制代码
//尾插法
void insert_tail_linklist(linknode *phead, datatype tmpdata)
{
    linknode *ptmpnode = NULL;

    ptmpnode = malloc(sizeof(linknode));
    if (NULL == ptmpnode)
    {
        perror("fail to malloc");
        return;
    }

    ptmpnode->data = tmpdata;
    ptmpnode->pnext = phead;
    ptmpnode->ppre = phead->ppre;
    phead->ppre->pnext = ptmpnode;
    phead->ppre = ptmpnode;

    return;
}

2.4循环链表的遍历

++与单向和双向链表不同,其ptmpnod在所有需要遍历的使用场景中,其判定条件均由(ptmpnode!=null)变为了(ptmpnode != phead);++

cs 复制代码
void show_linklist(linknode *phead)
{
    linknode *ptmpnode = NULL;

    ptmpnode = phead->pnext;
    while (ptmpnode != phead)
    {
        printf("%d ", ptmpnode->data);
        ptmpnode = ptmpnode->pnext;
    }
    printf("\n");

    return;
}

2.5循环链表元素的查找

与单向链表相同,仅循环判断条件改变

cs 复制代码
// 链表的查找
linknode *find_linklist(linknode *phead, datatype tmpdata)
{
    linknode *ptmpnode = NULL;

    ptmpnode = phead->pnext;
    while (ptmpnode != phead)
    {
        if (ptmpnode->data == tmpdata)
        {
            return ptmpnode;
        }
        ptmpnode = ptmpnode->pnext;
    }

    return NULL;
}

2.6循环链表元素修改

与单向链表相同,仅循环判断条件改变

cs 复制代码
// 链表的修改
int update_linklist(linknode *phead, datatype olddata, datatype newdata)
{
    linknode *ptmpnode = NULL;

    ptmpnode = phead->pnext;
    while (ptmpnode != phead)
    {
        if (ptmpnode->data == olddata)
        {
            ptmpnode->data = newdata;
        }
        ptmpnode = ptmpnode->pnext;
    }

    return 0;
}

2.7循环链表元素的删除

与单向链表相同,仅循环判断条件改变

cs 复制代码
// 链表节点的删除 
int delete_linklist(linknode *phead, datatype tmpdata)
{
    linknode *ptmpnode = NULL;
    linknode *pfreenode = NULL;

    ptmpnode = phead->pnext;
    while (ptmpnode != phead)
    {
        if (ptmpnode->data == tmpdata)
        {
            ptmpnode->ppre->pnext = ptmpnode->pnext;
            ptmpnode->pnext->ppre = ptmpnode->ppre;
            pfreenode = ptmpnode;
            ptmpnode = ptmpnode->pnext;
            free(pfreenode);
        }
        else
        {
        ptmpnode = ptmpnode->pnext;
        }
    }
    return 0;
}

2.8循环链表的销毁

与单向链表相同,仅循环判断条件改变

cs 复制代码
// 链表的销毁
int destroy_linklist(linknode **pphead)
{
    linknode *ptmpnode = NULL;
    linknode *pfreenode = NULL;

    ptmpnode = (*pphead)->pnext;
    pfreenode = ptmpnode;
    while (ptmpnode != *pphead)
    {
        ptmpnode = ptmpnode->pnext;
        free(pfreenode);
        pfreenode = ptmpnode;
    }
    free(*pphead);
    *pphead = NULL;

    return 0;
}

3.内核链表

参考list.h中关于内核链表的常见操作:

cs 复制代码
 /*
 */
 Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
 This file is part of GlusterFS.
 This file is licensed to you under your choice of the GNU Lesser
 General Public License, version 3 or any later version (LGPLv3 or
 later), or the GNU General Public License, version 2 (GPLv2), in all
 cases as published by the Free Software Foundation.
 #ifndef _LLIST_H
 #define _LLIST_H
 /* 内核链表中的节点类型 */
 struct list_head {
 struct list_head *next;
 struct list_head *prev;
 };
 /* 初始化空白头结点 */
 #define INIT_LIST_HEAD(head) do {           
\
 (head)->next = (head)->prev = head; \
 } while (0)
 /* 头插法 */
 static inline void
 list_add (struct list_head *new, struct list_head *head)
 {
 new->prev = head;
 new->next = head->next;
 new->prev->next = new;
 new->next->prev = new;
}
 /* 尾插法 */
 static inline void
 list_add_tail (struct list_head *new, struct list_head *head)
 {
    new->next = head;
    new->prev = head->prev;
    new->prev->next = new;
    new->next->prev = new;
 }
 /* 按指定顺序插入 */
 /* This function will insert the element to the list in a order.
   Order will be based on the compare function provided as a input.
   If element to be inserted in ascending order compare should return:
    0: if both the arguments are equal
   >0: if first argument is greater than second argument
   <0: if first argument is less than second argument */
 static inline void
 list_add_order (struct list_head *new, struct list_head *head,
                int (*compare)(struct list_head *, struct list_head *))
 {
        struct list_head *pos = head->prev;
        while ( pos != head ) {
                if (compare(new, pos) >= 0)
                        break;
                /* Iterate the list in the reverse order. This will 
have
                   better efficiency if the elements are inserted in 
the
                   ascending order */
                pos = pos->prev;
        }
        list_add (new, pos);
 }
 /* 将节点移出所属的链表 */
 static inline void
 list_del (struct list_head *old)
 {
    old->prev->next = old->next;
    old->next->prev = old->prev;
    old->next = (void *)0xbabebabe;
    old->prev = (void *)0xcafecafe;
 }
 /* 将节点移出所属的链表,并初始化 */
 static inline void
 list_del_init (struct list_head *old)
 {
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
    old->prev->next = old->next;
    old->next->prev = old->prev;
    old->next = old;
    old->prev = old;
 }
 /* 将节点移动到另一个链表的头部 */
 static inline void
 list_move (struct list_head *list, struct list_head *head)
 {
    list_del (list);
    list_add (list, head);
 }
 /* 将节点移动到另一个链表的尾部 */
 static inline void
 list_move_tail (struct list_head *list, struct list_head *head)
 {
    list_del (list);
    list_add_tail (list, head);
 }
 /* 判断链表是否为空 */
 static inline int
 list_empty (struct list_head *head)
 {
    return (head->next == head);
 }
 /* 将list链表所有元素拼到head链表的前面 */
 static inline void
 __list_splice (struct list_head *list, struct list_head *head)
 {
    (list->prev)->next = (head->next);
    (head->next)->prev = (list->prev);
    (head)->next = (list->next);
    (list->next)->prev = (head);
 }
 /* 将list链表所有元素拼到head链表的前面 */
 static inline void
 list_splice (struct list_head *list, struct list_head *head)
 {
    if (list_empty (list))
        return;
    __list_splice (list, head);
 }
 /* 将list链表所有元素拼到head链表的前面,并初始化list头结点 */
 /* Splice moves @list to the head of the list at @head. */
 static inline void
 list_splice_init (struct list_head *list, struct list_head *head)
 {
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
    if (list_empty (list))
        return;
    __list_splice (list, head);
    INIT_LIST_HEAD (list);
 }
 /* 将list链表所有元素追加到head链表的后面 */
 static inline void
 __list_append (struct list_head *list, struct list_head *head)
 {
    (head->prev)->next = (list->next);
        (list->next)->prev = (head->prev);
        (head->prev) = (list->prev);
        (list->prev)->next = head;
 }
 /* 将list链表所有元素追加到head链表的后面 */
 static inline void
 list_append (struct list_head *list, struct list_head *head)
 {
    if (list_empty (list))
        return;
    __list_append (list, head);
 }
 /* 将list链表所有元素追加到head链表的后面,并初始化list */
 /* Append moves @list to the end of @head */
 static inline void
 list_append_init (struct list_head *list, struct list_head *head)
 {
    if (list_empty (list))
        return;
    __list_append (list, head);
    INIT_LIST_HEAD (list);
 }
 /* 判断当前节点是否为最后一个节点 */
 static inline int
 list_is_last (struct list_head *list, struct list_head *head)
 {
        return (list->next == head);
 }
 /* 判断链表是否只有一个节点 */
 static inline int
 list_is_singular(struct list_head *head)
 {
        return !list_empty(head) && (head->next == head->prev);
 }
 /* 将旧节点用新节点替换 */
 /**
 * list_replace - replace old entry by new one
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 * @old : the element to be replaced
 * @new : the new element to insert
 *
 * If @old was empty, it will be overwritten.
 */
 static inline void list_replace(struct list_head *old,
                struct list_head *new)
 {
    new->next = old->next;
    new->next->prev = new;
    new->prev = old->prev;
    new->prev->next = new;
 }
 /* 将旧节点用新节点替换,并初始化旧节点 */
 static inline void list_replace_init(struct list_head *old,
                                     struct list_head *new)
 {
    list_replace(old, new);
    INIT_LIST_HEAD(old);
 }
 /* 内核链表左旋 */
 /**
 * list_rotate_left - rotate the list to the left
 * @head: the head of the list
 */
 static inline void list_rotate_left (struct list_head *head)
 {
    struct list_head *first;
    if (!list_empty (head)) {
        first = head->next;
        list_move_tail (first, head);
    }
 }
 /* 根据链表节点地址找到数据元素首地址 */
 #define list_entry(ptr, type, member)                   \
    ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
 /* 找到第一个数据元素地址 */
 #define list_first_entry(ptr, type, member)     \
        list_entry((ptr)->next, type, member)
 /* 找到最后一个数据元素地址 */
 #define list_last_entry(ptr, type, member)     \
        list_entry((ptr)->prev, type, member)
 /* 找到下一个数据元素地址 */
 #define list_next_entry(pos, member) \
        list_entry((pos)->member.next, typeof(*(pos)), member)
 /* 找到上一个数据元素地址 */
 #define list_prev_entry(pos, member) \
        list_entry((pos)->member.prev, typeof(*(pos)), member)
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
/* 遍历链表节点元素地址 */
 #define list_for_each(pos, head)                                        
\
    for (pos = (head)->next; pos != (head); pos = pos->next)
 /* 遍历所有数据元素首地址 */
 #define list_for_each_entry(pos, head, member)              \
    for (pos = list_entry((head)->next, typeof(*pos), member);  \
         &pos->member != (head);                    \
         pos = list_entry(pos->member.next, typeof(*pos), member))
 /* 遍历所有数据元素首地址(可以在遍历过程中修改数据元素指针) */
 #define list_for_each_entry_safe(pos, n, head, member)          \
    for (pos = list_entry((head)->next, typeof(*pos), member),  \
        n = list_entry(pos->member.next, typeof(*pos), member); \
         &pos->member != (head);                    \
         pos = n, n = list_entry(n->member.next, typeof(*n), member))
 /* 倒着遍历所有数据元素首地址 */
 #define list_for_each_entry_reverse(pos, head, member)                  
\
    for (pos = list_entry((head)->prev, typeof(*pos), member);      \
         &pos->member != (head);                                    \
         pos = list_entry(pos->member.prev, typeof(*pos), member))
 /* 倒着遍历所有数据元素首地址(可以在遍历过程中修改数据元素指针) */
 #define list_for_each_entry_safe_reverse(pos, n, head, member)          
\
    for (pos = list_entry((head)->prev, typeof(*pos), member),      \
            n = list_entry(pos->member.prev, typeof(*pos), member); \
         &pos->member != (head);                                    \
         pos = n, n = list_entry(n->member.prev, typeof(*n), member))
 /*
 * This list implementation has some advantages, but one disadvantage: 
you
 * can't use NULL to check whether you're at the head or tail.  Thus, 
the
 * address of the head has to be an argument for these macros.
 */
 /* 获得下一个数据元素空间首地址,如果没有返回NULL */
 #define list_next(ptr, head, type, member)      \
        (((ptr)->member.next == head) ? NULL    \
                                 : list_entry((ptr)->member.next, type, 
member))
 /* 获得上一个数据元素空间首地址,如果没有返回NULL */
 #define list_prev(ptr, head, type, member)      \
        (((ptr)->member.prev == head) ? NULL    \
                                 : list_entry((ptr)->member.prev, type, 
member))
 #endif /* _LLIST_H */
相关推荐
xiangweiqiang11 分钟前
用phpstudy安装php8.2后报错:意思是找不到php_redis.dll拓展时
开发语言·php
mitt_25 分钟前
go语言变量
开发语言·后端·golang
Christo325 分钟前
TFS-2022《A Novel Data-Driven Approach to Autonomous Fuzzy Clustering》
人工智能·算法·机器学习·支持向量机·tfs
木木子999930 分钟前
超平面(Hyperplane)是什么?
算法·机器学习·支持向量机·超平面·hyperplane
sakabu42 分钟前
cJSON库应用
c语言·笔记·学习
TravisBytes1 小时前
gRPC C++ 从 0 到 1 → 到线上:**超详细** 环境搭建、编码范式、性能调优与 DevOps 全攻略
开发语言·c++·devops
kngines1 小时前
【Node.js从 0 到 1:入门实战与项目驱动】1.1 什么是 Node.js?(定义、运行环境、与浏览器 JavaScript 的区别)
开发语言·javascript·node.js
Asu52021 小时前
思途Mybatis学习 0805
java·spring boot·学习·mybatis
星空下的曙光2 小时前
React 虚拟 DOM Diff 算法详解,Vue、Snabbdom 与 React 算法对比
vue.js·算法·react.js
♞沉寂2 小时前
数据结构——双向链表
数据结构·算法·链表