zoukankan      html  css  js  c++  java
  • 无头结点的单链表(C语言)

    1.单链表:

      在顺序表中,用一组地址连续的存储单元来一次存放线性表的结点,因此结点的逻辑顺序与物理顺序是一致的。但链表却不同,链表是用一组任意的存储单元来存放 线性表的结点,这组存储单元可以是连续的,也可以是非连续的,甚至是零散分布在内存的任何位置上。因此,链表中结点的逻辑顺序与物理顺序不一定相同。为了正确表示节点间的逻辑关系,必须在存储线性表的每个数据元素的同时,存储指示其后继结点的地址信息,这两部分信息共同构成了单链表结点的结构,如下图:

        结点包括两个域,数据域用来存放结点的值,指针域用来存储数据元素的直接后继的地址(或位置)。线性表正是通过每个结点的指针域将线性表的n个结点按其逻辑顺序连接在一起的。由于此线性表的每个节点只有一个next指针域,故将这种链表叫做单链表。

          由于单链表中的每一个结点除了第一个节点外,它们的存储地址存放在其前驱结点的指针域中,由于第一个节点无前驱,所以应该设一个头指针指向第一个节点,本文中设置了first指针指向第一个结点。单链表中的最后一个节点无直接后继,所以指定单链表的最后一个结点的指针域为"空"(NULL)。

      一般情况下,使用链表,只关心链表中结点的逻辑顺序,并不关心每个结点的实际存储位置,因此通常用箭头来表示链域中的指针,于是链表就可以更直观地画成用箭头链接起来的结点序列,如图:

      有时候,为了操作的统一方便,可以在单链表的第一个结点前附设一个头结点,头结点的数据域可以存储一些关于线性表的长度等附加信息,也可以不存储任何信息,对头结点的数据域无特别规定,而头结点的指针域用来存储指向第一个结点的指针(即第一个结点的存储位置)。如果线性表为空,则头结点的指针域为"空"。如图所示:

          

    2.单链表操作

       头插过程:

      头插的方式如上图所示。采用头插法得到的单链表的逻辑顺序与输入元素顺序相反,亦称头插法为逆序建表法。在这只介绍头插法的示意图,对于尾插、头删、尾删、可以参考《数据结构----用C语言描述》(耿国华主编)这本书。下面的代码中,实现了头插、尾插、头删、尾删,读者可以仔细研究研究。(本文所编写的代码是在VS2013编译环境下运行的)

    3.运行代码:

      Linklist.h文件包括各个操作函数的声明以及包含的头文件,test.c包含了测试代码,Linklist.c文件里主要是各个操作函数的具体实现。

     1 //Linklist.h
     2 #pragma once
     3 #include<stdio.h>
     4 #include<assert.h>
     5 #include<stdlib.h>
     6 
     7 typedef int LDataType;
     8 typedef struct Linklist
     9 {
    10     LDataType data;
    11     struct Linklist *next;
    12 }Linklist, *pLinklist;
    13 
    14 //接口函数
    15 pLinklist BuyNewNode(LDataType data);//动态生成新节点
    16 void InitLinklist(pLinklist *pL);//初始化单链表
    17 void PushBackLinklist(pLinklist *pL, LDataType data);//尾插
    18 void PushFrontLinklist(pLinklist *pL, LDataType data);//头插
    19 void PopBackLinklist(pLinklist *pL);//尾删
    20 void PopFrontLinklist(pLinklist *pL);//头删
    21 void PrintLinklist(Linklist *pL);//打印单链表
    22 pLinklist FindLinklist(pLinklist *pL, LDataType data);//查找指定元素,返回指定元素的位置
    23 void InsertLinklist(pLinklist *pL, pLinklist p, LDataType data);//指定位置插入
    24 void RemoveLinklist(pLinklist *pL, LDataType data);//删除第一个指定元素
    25 void RemoveAllLinklist(pLinklist *pL, LDataType data);//删除所有的指定元素
    26 int IsEmptyLinklist(pLinklist pL);//判断链表是否为空,为空返回1;不为空返回0;
    27 void DestoryLinklist(pLinklist *pL);//销毁单链表

      1 //Linklist.c
      2 #include"Linklist.h"
      3 pLinklist BuyNewNode(LDataType data)//生成新节点
      4 {
      5     pLinklist NewNode = (pLinklist)malloc(sizeof(Linklist));
      6     if (NewNode == NULL)
      7     {
      8         printf("动态开辟内存空间失败
    ");
      9         return;
     10     }
     11     NewNode->data = data;
     12     NewNode->next = NULL;
     13     return NewNode;
     14 }
     15 void InitLinklist(pLinklist *pL)//初始化
     16 {
     17     assert(pL != NULL);
     18     (*pL) = NULL;
     19 }
     20 void PushBackLinklist(pLinklist *pL, LDataType data)//尾插
     21 {
     22     assert(pL != NULL);
     23     pLinklist NewNode = BuyNewNode(data);
     24     if (*pL == NULL)
     25     {
     26         *pL = NewNode;
     27         return;
     28     }
     29     pLinklist cur = *pL;
     30     while (cur->next)
     31     {
     32         cur = cur->next;
     33     }
     34     cur->next = NewNode;
     35 }
     36 void PushFrontLinklist(pLinklist *pL, LDataType data)//头插
     37 {
     38     assert(pL != NULL);
     39     pLinklist NewNode = BuyNewNode(data);
     40     if (*pL == NULL)
     41     {
     42         *pL = NewNode;
     43         return;
     44     }
     45     NewNode->next = *pL;
     46     *pL = NewNode;
     47 }
     48 int IsEmptyLinklist(pLinklist pL)//判断是否为空链表
     49 {
     50     if (pL == NULL)
     51         return 1;
     52     return 0;
     53 }
     54 void PopBackLinklist(pLinklist *pL)//尾删
     55 {
     56     assert(pL != NULL);
     57     if (IsEmptyLinklist(*pL))//链表为空,没有节点
     58     {
     59         printf("链表为空,删除操作失败
    ");
     60         return;
     61     }
     62     pLinklist cur = *pL;
     63     pLinklist pre = NULL;//保存cur的前一个节点
     64     if (cur->next == NULL)//有一个节点
     65     {
     66         *pL = NULL;
     67         free(cur);
     68         cur = NULL;
     69         return;
     70     }
     71     while (cur->next)
     72     {
     73         pre = cur;
     74         cur = cur->next;
     75     }
     76     pre->next = NULL;
     77     free(cur);
     78     cur = NULL;
     79 }
     80 void PopFrontLinklist(pLinklist *pL)//头删
     81 {
     82     assert(pL != NULL);
     83     if (*pL == NULL)
     84     {
     85         printf("链表为空,删除操作失败
    ");
     86         return;
     87     }
     88     pLinklist cur = *pL;
     89     *pL = cur->next;
     90     free(cur);
     91     cur = NULL;
     92 }
     93 pLinklist FindLinklist(pLinklist *pL, LDataType data)//查找指定元素,返回指定元素的位置
     94 {
     95     assert(pL != NULL);
     96     pLinklist cur = *pL;
     97     while (cur)
     98     {
     99         if (cur->data == data)
    100         {
    101             return cur;
    102         }
    103         cur = cur->next;
    104     }
    105     return NULL;
    106 }
    107 void InsertLinklist(pLinklist *pL, pLinklist p, LDataType data)//指定位置前面插入
    108 {
    109     assert(pL != NULL);
    110     pLinklist NewNode = BuyNewNode(data);
    111     pLinklist cur = *pL;
    112     while (cur->next != p)
    113     {
    114         cur = cur->next;
    115     }
    116     NewNode->next = p;
    117     cur->next = NewNode;
    118 }
    119 void RemoveLinklist(pLinklist *pL, LDataType data)//删除第一个指定元素
    120 {
    121     assert(pL != NULL);
    122     pLinklist cur = NULL;
    123     pLinklist p = *pL;
    124     pLinklist pre = NULL;
    125     cur = FindLinklist(pL, data);//找到要删除的指定元素
    126     if (cur == NULL)
    127     {
    128         printf("没找到要删除的指定元素,删除失败
    ");
    129         return;
    130     }
    131     if (*pL == cur)//位于第一个节点
    132     {
    133         *pL= cur->next;
    134         free(cur);
    135         cur = NULL;
    136         return;
    137     }
    138     while (p!= cur)
    139     {
    140         pre = p;
    141         p = p->next;
    142     }
    143     pre->next = cur->next;
    144     free(cur);
    145     cur = NULL;
    146 }
    147 void RemoveAllLinklist(pLinklist *pL, LDataType data)//删除所有的指定元素
    148 {
    149     assert(pL != NULL);
    150     pLinklist cur = NULL;
    151     pLinklist p = *pL;
    152     pLinklist pre = *pL;
    153     while (p)
    154     {
    155         
    156         if (p->data == data && (*pL) == p)
    157         {
    158             pre = p;
    159             p = p->next;
    160             *pL = p;
    161             free(pre);
    162             pre = NULL;
    163         }
    164         else if (p->data == data)
    165         {
    166             cur = p;
    167             p = p->next;
    168             pre->next = p;
    169             free(cur);
    170             cur = NULL;
    171         }
    172         else
    173         {
    174             pre = p;
    175             p = p->next;
    176         }
    177     }
    178 
    179 }
    180 void PrintLinklist(Linklist *pL)//打印单链表
    181 {
    182     pLinklist cur = pL;
    183     while (cur)
    184     {
    185         printf("%d-->", cur->data);
    186         cur = cur->next;
    187     }
    188     printf("NULL
    ");
    189 }
    190 void DestoryLinklist(pLinklist *pL)//销毁单链表,放置内存溢出
    191 {
    192     assert(pL != NULL);
    193     pLinklist cur = *pL;
    194     pLinklist pre = NULL;//保存cur的前一个节点
    195     if (*pL == NULL)
    196     {
    197         printf("链表为空
    ");
    198         return;
    199     }
    200     if (cur->next == NULL)//只有一个节点
    201     {
    202         *pL = NULL;
    203         free(cur);
    204         cur = NULL;
    205         return;
    206     }
    207     while (cur)
    208     {
    209         pre = cur;
    210         cur = cur->next;
    211         free(pre);
    212         pre = NULL;
    213     }
    214 }
     1 //test.c测试函数
     2 #include"Linklist.h"
     3 
     4 void test()
     5 {
     6     pLinklist cur = NULL;//用来接收FindLinklist的返回值
     7     Linklist *first = NULL;
     8     InitLinklist(&first);//初始化
     9     //PushBackLinklist(&first, 1);//尾插元素
    10     //PushBackLinklist(&first, 2);
    11     //PushBackLinklist(&first, 3);
    12     //PushBackLinklist(&first, 4);
    13     //PushBackLinklist(&first, 5);
    14     //PrintLinklist(first);//打印单链表
    15     PushFrontLinklist(&first, 6);//头插元素
    16     PushFrontLinklist(&first, 7);
    17     PushFrontLinklist(&first, 8);
    18     PushFrontLinklist(&first, 9);
    19     PushFrontLinklist(&first, 10);
    20     //PopBackLinklist(&first);//尾删一个节点
    21     //PopFrontLinklist(&first);//头删一个节点
    22     //PrintLinklist(first);//打印单链表
    23     //DestoryLinklist(&first);
    24     //cur = FindLinklist(&first, 8);
    25     //InsertLinklist(&first, cur, 11);
    26     //printf("在8前面插入11得:");
    27     //PrintLinklist(first);//打印单链表
    28     //printf("删除11得:");
    29     //RemoveLinklist(&first, 11);
    30     //PrintLinklist(first);
    31     PushFrontLinklist(&first, 7);
    32     PushFrontLinklist(&first, 7);
    33     //RemoveLinklist(&first, 7);
    34     RemoveAllLinklist(&first, 7);
    35     PrintLinklist(first);
    36 
    37     //RemoveAllLinklist(&first, 7);//删除所有的7
    38 }
    39 int main()
    40 {
    41     test();
    42     system("pause");
    43     return 0;
    44 }

     4.尾插法建立单链表如下图:

      测试图:                                                                                                                         运行图:

     

     5.头插法建立单链表如下图:

       测试图:                                                                                    运行图:

     

    6.头删和尾删一个结点:

      测试图:                                                                              运行图:

     

     7.在指定位置插入元素:

      测试图:                                                                          运行图:

     

       除这几个操作外,还有删除指定元素RemoveLinklist(删除第一个找到的指定元素),删除所有的指定元素RemoveAllLinklist。因为本文中单链表的结点是动态开辟的,因此还要实现销毁函数DestoryLinklist,防止内存泄漏。

     

  • 相关阅读:
    解析3D打印切片软件:Cura
    步步为营,打造CQUI UI框架
    PHP为什么empty可以访问不存在的索引
    这是一篇关于魔法(Science)上网的教程
    【新阁教育】这样玩PLC,是不是有意思多了
    「新阁教育」西门子TIA实现BadApple完整实例
    C#数据结构-赫夫曼树
    C#数据结构-线索化二叉树
    SQL优化器-RBO与CBO分别是什么
    Linux下安装并配置VSCode(Visual Studio Code)
  • 原文地址:https://www.cnblogs.com/love-you1314/p/9690855.html
Copyright © 2011-2022 走看看