• C语言双向链表讲解


    一、双向链表的概念

        双向链表基于单链表。单链表是单向的,有一个头结点,一个尾结点,要访问任何结点,都必须知道头结点,不能逆着进行。而双链表添加了一个指针域,通过两个指针域,分别指向结点的前结点和后结点。这样的话,可以通过双链表的任何结点,访问到它的前结点和后结点。

        在双向链表中,结点除含有数据域外,还有两个链域,一个存储直接后继结点的地址,一般称为右链域;一个存储直接前驱结点地址,一般称之为左链域。

        双向链表结构示意图

        

    表头为空,表头的后继节点为"节点10"(数据为10的节点);"节点10"的后继节点是"节点20"(数据为10的节点),"节点20"的前继节点是"节点10";"节点20"的后继节点是"节点30","节点30"的前继节点是"节点20";...;末尾节点的后继节点是表头。

    双链表删除节点

    删除"节点30"
    删除之前:"节点20"的后继节点为"节点30","节点30" 的前继节点为"节点20"。"节点30"的后继节点为"节点40","节点40" 的前继节点为"节点30"。
    删除之后:"节点20"的后继节点为"节点40","节点40" 的前继节点为"节点20"。

    双链表添加节点

    在"节点10"与"节点20"之间添加"节点15"
    添加之前:"节点10"的后继节点为"节点20","节点20" 的前继节点为"节点10"。
    添加之后:"节点10"的后继节点为"节点15","节点15" 的前继节点为"节点10"。"节点15"的后继节点为"节点20","节点20" 的前继节点为"节点15"。

    二、C语言实现双向链表

    2.1 头文件

     1 #pragma once
     2 //新建双向链表。成功返回链表头,否则,返回NULL
     3 extern int create_dLink();
     4 //撤销双向链表,成功返回0,否则返回-1
     5 extern int destory_dLink();
     6 //双向列表是否为空,为空返回1,否则返回0
     7 extern int  is_empty_dLink();
     8 //双向链表的大小
     9 extern int dLink_size();
    10 //获取索引index位置的元素,成功返回节点指针,否则返回NULL
    11 extern  void* dLink_get(int index);
    12 //获取双向链表中第一个元素,成功返回节点指针,否则返回NULL
    13 extern void* dLink_getFirst();
    14 //获取双向链表中最后一个元素,成功返回节点指针,否则返回NULL
    15 extern void* dLink_getTail();
    16 /*
    17 链表中增加
    18 */
    19 //在Index位置插值value,成功返回0,否则返回-1;
    20 extern int dLink_insert(int index,void * pVal);
    21 //在表头插入值
    22 extern int dLink_insert_head(void *pVal);
    23 //在表尾插入值
    24 extern int dLink_insert_tail(void *pVal);
    25 /*
    26 链表中删除
    27 */
    28 //在index处删除
    29 extern int  dLink_delete(int index);
    30 //删除第一个节点
    31 extern int dLink_delete_first();
    32 //闪电湖第二个节点
    33 extern int dLink_delete_tail();
    View Code
    2.2 .c
      1 #include<stdio.h>
      2 #include "double_link.h"
      3 #include<malloc.h>
      4 
      5 //双向链表节点
      6 typedef struct My_node
      7 {
      8     struct My_node *prev;
      9     struct  My_node *pNext;
     10     void * p;
     11 }my_node;
     12 //b表头不存放元素值
     13 my_node *phead = NULL;
     14 //节点的个数
     15 int node_count = 0;
     16 //创建节点,成功返回节点指针,否则,返回NULL
     17 my_node* create_node(void *pVal)
     18 {
     19     my_node *pnode = NULL;
     20     pnode = (my_node*)malloc(sizeof(My_node));
     21     if (!pnode)
     22     {
     23         printf("create pnode error
    ");
     24         return NULL;
     25     }
     26     //默认的,pnode的前一节点和后一节点都指向他自己
     27     pnode->prev  = pnode->pNext = pnode;
     28     //节点的值为pVal
     29     pnode->p = pVal;
     30     return pnode;
     31 }
     32 
     33 //新建双向链表 成功返回0 否则返回-1
     34 int create_dLink()
     35 {
     36     phead = create_node(NULL);
     37     if (!phead)
     38         return -1;
     39     //设置节点的个数
     40     node_count = 0;
     41     return 0;
     42 }
     43 
     44 int destory_dLink()
     45 {
     46     if (!phead)
     47     {
     48         printf("%s failed! dlink is null!
    ", __func__);
     49          return -1;
     50     }
     51     My_node*pnode = phead->pNext;
     52     my_node* ptmp = NULL;
     53     if (pnode!=phead)
     54     {
     55         ptmp = pnode;
     56         pnode = pnode->pNext;
     57         free(pnode);
     58     }
     59     free(phead);
     60     phead = NULL;
     61     node_count = 0;
     62     return 0;
     63 }
     64 
     65 int is_empty_dLink()
     66 {
     67     return node_count==0;
     68 }
     69 
     70 int dLink_size()
     71 {
     72     return node_count;
     73 }
     74 //获取双向链表中第Index位置的节点
     75 my_node* get_node(int index)
     76 {
     77     if (index<0 || index >= node_count)
     78     {
     79         printf("%s failed ! index out of bound
    ", __func__);
     80         return NULL;
     81     }
     82     //正向查找
     83     if (index <= (node_count / 2))
     84     {
     85         int i = 0;
     86         my_node *pnode = phead->pNext;
     87         while ((i++)<index)
     88         {
     89             pnode = pnode->pNext;
     90         }
     91         return pnode;
     92     }
     93     //反向查找
     94     int j = 0;
     95     int rindex = node_count - index - 1;
     96     my_node *rnode = phead->prev;
     97     while ((j++)<rindex)
     98     {
     99         rnode = rnode->prev;
    100     }
    101     return rnode;
    102 }
    103 void * dLink_get(int index)
    104 {
    105     my_node *pindex = get_node(index);
    106     if (!pindex)
    107     {
    108         printf("%s failed!
    ", __func__);
    109         return NULL;
    110     }
    111     return pindex->p;
    112 }
    113 
    114 //获取第一个节点
    115 void * dLink_getFirst()
    116 {
    117     return get_node(0) ;
    118 }
    119 //获取最后一个节点
    120 void * dLink_getTail()
    121 {
    122     return get_node(node_count-1);
    123 }
    124 //将值插入到index位置,成功返回0;否则 返回-1
    125 int dLink_insert(int index, void * pVal)
    126 {
    127     //插入表头
    128     if (index == 0)
    129         return dLink_insert_head(pVal);
    130     //获取要插入位置对应的节点
    131     my_node* pindex = get_node(index);
    132     if (!pindex)
    133         return -1;
    134     //创建节点
    135     my_node* pnode = create_node(pVal);
    136     if (!pnode)
    137         return -1;
    138     pnode->prev = pindex->prev;
    139     pnode->pNext = pindex;
    140     pindex->prev->pNext = pnode;
    141     pindex->prev = pnode;
    142     node_count++;
    143     return 0;
    144 }
    145 //数值插入表头
    146 int dLink_insert_head(void * pVal)
    147 {
    148     my_node* pnode = create_node(pVal);
    149     if (!pnode)
    150         return -1;
    151     pnode->prev = phead;
    152     pnode->pNext = phead->pNext;
    153     
    154     phead->pNext->prev = pnode;
    155     phead->pNext = pnode;
    156     node_count++;
    157     return 0;
    158 }
    159 
    160 int dLink_insert_tail(void * pVal)
    161 {
    162     my_node* pnode = create_node(pVal);
    163     if (!pnode)
    164         return -1;
    165     pnode->pNext = phead;
    166     pnode->prev = phead->prev;
    167     phead->prev->pNext = pnode;
    168     phead->prev = pnode;
    169     return 0;
    170 }
    171 
    172 int dLink_delete(int index)
    173 {
    174     my_node* pindex = get_node(index);
    175     if (!pindex)
    176     {
    177         printf("%s failed! the index in out of bound
    ",__func__);
    178         return -1;
    179     }
    180     pindex->pNext->prev = pindex->prev;
    181     pindex->prev->pNext = pindex->pNext;
    182     free(pindex);
    183     node_count--;
    184     return 0;
    185 }
    186 
    187 int dLink_delete_first()
    188 {
    189     return dLink_delete(0);
    190 }
    191 
    192 int dLink_delete_tail()
    193 {
    194     return dLink_delete(node_count-1);
    195 }
    View Code

    2.3 test测试代码

     1 #include<stdio.h>
     2 #include"double_link.h"
     3 //1.双向链表操作数为int
     4 void int_test()
     5 {
     6     int arr[10] = {11,55,67,90,21,45,23,59,79,10};
     7     printf("xxxxxxxxxxxxxxxxx
    ");
     8     create_dLink();                    //创建链表
     9     dLink_insert(0, &arr[0]);        //双向链表表头插入
    10     dLink_insert(0, &arr[1]);        //双向链表表头插入
    11     dLink_insert(0, &arr[2]);        //双向链表表头插入
    12     dLink_insert(0, &arr[3]);        //双向链表表头插入
    13     dLink_insert(0, &arr[4]);        //双向链表表头插入
    14     dLink_insert(0, &arr[5]);        //双向链表表头插入
    15     printf("is_empty_dLink()=%d
    ",is_empty_dLink());    //双向链表是否为空
    16     printf("dLink_size()=%d
    ", dLink_size());                    //双向链表的大小
    17     //遍历双向链表
    18     int i ;
    19     int * p ;
    20     int sz = dLink_size();
    21     for ( i = 0; i < sz; i++)
    22     {
    23         p = (int*)dLink_get(i);
    24         printf("dLink_get(%d)=%d
    ",i,*p);
    25     }
    26     destory_dLink();
    27 }
    28 
    29 //2.操作数为字符串
    30 void string_test()
    31 {
    32     char* str[] = {"one","two","three","four","five"};
    33     create_dLink();                    //创建链表
    34     dLink_insert(0, str[0]);        //双向链表表头插入
    35     dLink_insert(0, str[1]);        //双向链表表头插入
    36     dLink_insert(0, str[2]);        //双向链表表头插入
    37     printf("is_empty_dLink()=%d
    ", is_empty_dLink());    //双向链表是否为空
    38     printf("dLink_size()=%d
    ", dLink_size());                    //双向链表的大小
    39                                                                 //遍历双向链表
    40     int i ;
    41     char * p ;
    42     int sz = dLink_size();
    43     for (i = 0; i < sz; i++)
    44     {
    45         p = (char*)dLink_get(i);
    46         printf("dLink_get(%d)=%s
    ", i, p);
    47     }
    48     destory_dLink();
    49 }
    50 //3.双向链表为结构体
    51 typedef struct MyStruct
    52 {
    53     int id;
    54     char name[20];
    55 } stu;
    56 stu arr_stu[] =
    57 {
    58     {1000,"lii"},
    59     { 1001,"mike" },
    60     { 1002,"lucky" },
    61     { 1003,"eric" },
    62 };
    63 #define arr_stu_size  ((sizeof(arr_stu))/(sizeof(arr_stu[0])))
    64 void stuc_test()
    65 {
    66     create_dLink();                    //创建链表
    67     dLink_insert(0, &arr_stu[0]);        //双向链表表头插入
    68     dLink_insert(0, &arr_stu[1]);        //双向链表表头插入
    69     dLink_insert(0, &arr_stu[2]);        //双向链表表头插入
    70     printf("is_empty_dLink()=%d
    ", is_empty_dLink());    //双向链表是否为空
    71     printf("dLink_size()=%d
    ", dLink_size());                    //双向链表的大小
    72                                                                 //遍历双向链表
    73     int i ;
    74     stu * p ;
    75     int sz = dLink_size();
    76     for (i = 0; i < sz; i++)
    77     {
    78         p = (stu*)dLink_get(i);
    79         printf("dLink_get(%d)=[%d,%s]
    ", i, p->id,p->name);
    80     }
    81     destory_dLink();
    82 }
    83 int main()
    84 {
    85     int_test();
    86     string_test();
    87     stuc_test();
    88     
    89     return 0;
    90 }
    View Code

    2.34结果显示

  • 相关阅读:
    Java网络编程
    loj#6517. 「雅礼集训 2018 Day11」字符串(回滚莫队)
    bzoj4241: 历史研究(回滚莫队)
    洛谷P5050 【模板】多项式多点求值
    loj#6053. 简单的函数(Min_25筛)
    【BZOJ4144】[AMPPZ2014]Petrol(最短路+最小生成树+并查集)
    51nod 1781 Pinball(线段树)
    CF1110D Jongmah
    CF1106F Lunar New Year and a Recursive Sequence(矩阵快速幂+bsgs+exgcd)
    20. Valid Parentheses
  • 原文地址:https://www.cnblogs.com/506941763lcj/p/11432527.html
Copyright © 2020-2023  润新知