zoukankan      html  css  js  c++  java
  • 单链表——带头节点

    一、链表简介

      1 数据结构中,链表是最基础的。然而链表根据不同的需求分成的种类很多,单向或双向链表,循环或非循环链表,带头节点或者不带头节点的链表。

      2 本文实现——带头节点的单链表。

      3 由于仅仅是学习链表的基本操作,所以在数据字段仅仅设置一个字段;

         由于仅仅是学习基本操作,不涉及复杂的算法思想,所以不会很难,主要以代码为主,附上必要的解释即可。

    二、具体实现

      整体分析:带有头节点的单链表的操作很方便,主要体现在插入和删除时不需要判断是否是第一个元素。

        1) 头文件定义如下:

        
     1 #ifndef LinearList_LinkList_h
     2 #define LinearList_LinkList_h
     3 
     4 #include <stdio.h>
     5 #include <stdlib.h>
     6 
     7 #define OK 1
     8 #define ERROR 0
     9 
    10 
    11 typedef int Status;
    12 typedef int ElemType;
    13 
    14 
    15 typedef struct LNode {
    16     ElemType data;
    17     struct LNode *pNext;
    18 }LNode, *LinkList;
    19 
    20 //LinkList with head
    21 Status CreateLinkListFromHead(LinkList *L, int nInputLength);
    22 Status CreateLinkListFromRear(LinkList *L, int nInputLength);
    23 Status InsertToLinkList(LinkList *L, int nIndex, ElemType eElem);
    24 Status DeleteFromLinkList(LinkList *L, int nIndex, ElemType *pElem);
    25 Status DestroyLinkList(LinkList *L);
    26 Status PrintLinkList(LinkList L);
    27 
    28 #endif
    LinkList.h

         2)具体实现:

        1 建立单链表:

          思路: a)校验参数

            b)校验长度是否合法(不校验也行。这里主要是为了防止非法输入,快速返回)

            c)建立头节点。(也有一种方法:单独写一个建立头节点的函数。此处直接嵌入在建表的过程中。)

            d)循环建立节点,然后选择不同的插入方法插入。

              

         详解插入:

            a)插入代码:

            设pNode指向待插入位置的前一个插入点,pInsertNode指向待插入的节点本身,则插入代码如下:

            pInsertNode->pNext = pNode->pNext;

            pNode->pNext = pInsertNode;

            b)插入的方法:

              头插法:每次插入点都选择在头节点的后一个节点,也就是整个有效链表的第一个位置。

                  pNode指向待插入节点本身,L指向表头节点。

                  此时代码如下:

                  (在建立头节点时,一定要先设置头节点的指针域为空 L->pNext = NULL,否则到最后就无法设置表尾为空了。)

                  pNode->pNext = L->pNext;

                  L->pNext = pNode;

              代码如下:

                
     1 Status CreateLinkListFromHead(LinkList *L, int nInputLength) {
     2     if (NULL == L) {
     3         printf("Error parament.");
     4         return ERROR;
     5     }
     6     
     7     *L = (LinkList)malloc(sizeof(LNode));
     8     if (NULL == *L) {
     9         printf("Out of memory.");
    10         return ERROR;
    11     }
    12     (*L)->pNext = NULL; //because list is created from head. So make the list empty
    13     
    14     if (nInputLength < 1) {
    15         printf("Error length.");
    16         return ERROR;
    17     }
    18     
    19     LNode *pNode;
    20     int nValue;
    21     
    22     printf("Input the values:");
    23     for (int i = 1; i <= nInputLength; i++) {
    24         scanf("%d", &nValue);
    25         
    26         pNode = (LinkList)malloc(sizeof(LNode));
    27         if (NULL == pNode) {
    28             printf("Out of memory.");
    29             return ERROR;
    30         }
    31         pNode->data = nValue;
    32         
    33         pNode->pNext = (*L)->pNext;
    34         (*L)->pNext = pNode;
    35     }
    36     
    37     return OK;
    38 }
    CreateLinkListFromHead

              尾插法:每次插入点都选择在链表的表尾处。因此需要额外增加一个指针(pRear)用于标示链表表尾。

                  起初,pRear指向表头节点pRear = L;pNode指向待插入节点本身

                  插入代码如下:

                  pRear->pNext = pNode;

                  pRear = pRear->pNext;

                  到最后一定要设置表尾为空:pRear->pNext = NULL;

              代码如下:

                
     1 Status CreateLinkListFromRear(LinkList *L, int nInputLength) {
     2     if (NULL == L) {
     3         printf("Error parament.");
     4         return ERROR;
     5     }
     6     
     7     //build the head
     8     *L = (LinkList)malloc(sizeof(LNode));
     9     if (NULL == *L) {
    10         printf("Out of memory.");
    11         return ERROR;
    12     }
    13     (*L)->pNext = NULL; //make the list empty
    14     
    15     if (nInputLength < 1) {
    16         printf("Invalid input length.");
    17         return ERROR;
    18     }
    19 
    20     int nValue;
    21     LNode *pNode;
    22     LNode *pRear = *L;
    23     
    24     printf("Input the values:");
    25     for (int i = 1; i <= nInputLength; i++) {
    26         scanf("%d", &nValue);
    27         
    28         pNode = (LinkList)malloc(sizeof(LNode));
    29         if (NULL == pNode) {
    30             printf("Out of memory.");
    31             return ERROR;
    32         }
    33         pNode->data = nValue;
    34         
    35         pRear->pNext = pNode;
    36         pRear = pRear->pNext;
    37     }
    38     
    39     pRear->pNext = NULL;
    40     
    41     return OK;
    42 }
    CreateLinkListFromRear

         2 插入节点:

              思路:a)校验参数

                 b)建立待插入节点

                 c)找到待插入点

                 d)插入

              分析:纯粹的插入就是那两行代码,然而重点在于插入点的合法性判断以及插入点的定位。

                 合法:当插入点大于表长时应该返回错误;

                 插入点:一般来讲,会定位到当前带插入点的前一个位置;

                (其实也可以直接定位到带插入点处,插入后交换前后元素即可。但当数据元素过多时不适合。)    

              代码如下:

                
     1 Status InsertToLinkList(LinkList *L, int nIndex, ElemType eElem) {
     2     if (NULL == L) {
     3         printf("Error parament.");
     4         return ERROR;
     5     }
     6     
     7     if (nIndex < 1) {
     8         printf("Invalid insert point.");
     9         return ERROR;
    10     }
    11     
    12     int i = 0;
    13     LNode *pNode;
    14     LNode *qNode;
    15     
    16     qNode = (LinkList)malloc(sizeof(LNode));
    17     if (NULL == qNode) {
    18         printf("Out of memory.");
    19         return ERROR;
    20     }
    21     qNode->data = eElem;
    22     
    23     //the key--find the insert point
    24     pNode = *L;
    25     while (NULL != pNode->pNext && i < nIndex - 1) {
    26         pNode = pNode->pNext;
    27         i++;
    28     }
    29     
    30     //invalid insert point
    31     if (i < nIndex - 1) {
    32         printf("Invalid Insert point.");
    33         return ERROR;
    34     }
    35     
    36     //insert
    37     qNode->pNext = pNode->pNext;
    38     pNode->pNext = qNode;
    39     
    40     
    41     return OK;
    42 }
    InsertToLinkList

         3 删除节点:(删除和插入类似)

              思路:a)校验参数

                 b)判断链表是否为空

                 c)找到待插入点

                 d)取出待删除元素中的值

                 e)删除

              分析:纯粹的删除代码也就固定的两行,然而重点在于删除点的定位和删除后指针的处理

                删除点定位:也是需要定位到待删除点的前一个位置;

                删除后处理:free和置空

              代码如下:

                
     1 Status DeleteFromLinkList(LinkList *L, int nIndex, ElemType *pElem) {
     2     if (NULL == L || NULL == pElem) {
     3         printf("Error parament.");
     4         return ERROR;
     5     }
     6     
     7     if (NULL == (*L)->pNext) {
     8         printf("The list is empty.");
     9         return ERROR;
    10     }
    11     
    12     if (nIndex < 1) {
    13         printf("Invalid delete point.");
    14         return ERROR;
    15     }
    16     
    17     int i = 0;
    18     LNode *qNode;
    19     LNode *pNode = *L;  //  in case of the first valid delete point, the pNode should point to the head.
    20     
    21     while (NULL != pNode->pNext && i < nIndex - 1) {
    22         pNode = pNode->pNext;
    23         i++;
    24     }
    25     
    26     if (NULL == pNode->pNext) { // nIndex - 1 == i
    27         printf("Invalid delete point.");
    28         return ERROR;
    29     }
    30     
    31     qNode = pNode->pNext;
    32     pNode->pNext = qNode->pNext;
    33     
    34     *pElem = qNode->data;
    35     free(qNode);
    36     qNode = NULL;
    37     
    38     return OK;
    39 }
    DeleteFromLinkList 

          4 销毁链表

              思路:a)校验参数

                 b)判断是否为空

                 c)遍历链表,依次删除。

              分析:销毁链表比较简单,只需要完整遍历这条链表即可。

             代码如下:

              
     1 Status DestroyLinkList(LinkList *L) {
     2     if (NULL == L) {
     3         printf("Error parament.");
     4         return ERROR;
     5     }
     6     
     7     if (NULL == (*L)->pNext) {
     8         printf("The list is empty.");
     9         return ERROR;
    10     }
    11     
    12     LNode *pNode = (*L)->pNext;
    13     while (NULL != pNode) {
    14         (*L)->pNext = pNode->pNext;
    15         free(pNode);
    16         
    17         pNode = (*L)->pNext;
    18     }
    19     
    20     (*L)->pNext = NULL;
    21     pNode = NULL;
    22     
    23     return OK;
    24 }
    DestroyLinkList

    三、附上完整版链表实现代码,方便完整拷贝,测试等。

      1 #include "LinkList.h"
      2 
      3 
      4 /*-----------------LinkList withhead-------------------------------------------------*/
      5 
      6 Status CreateLinkListFromHead(LinkList *L, int nInputLength) {
      7     if (NULL == L) {
      8         printf("Error parament.");
      9         return ERROR;
     10     }
     11     
     12     *L = (LinkList)malloc(sizeof(LNode));
     13     if (NULL == *L) {
     14         printf("Out of memory.");
     15         return ERROR;
     16     }
     17     (*L)->pNext = NULL; //because list is created from head. So make the list empty
     18     
     19     if (nInputLength < 1) {
     20         printf("Error length.");
     21         return ERROR;
     22     }
     23     
     24     LNode *pNode;
     25     int nValue;
     26     
     27     printf("Input the values:");
     28     for (int i = 1; i <= nInputLength; i++) {
     29         scanf("%d", &nValue);
     30         
     31         pNode = (LinkList)malloc(sizeof(LNode));
     32         if (NULL == pNode) {
     33             printf("Out of memory.");
     34             return ERROR;
     35         }
     36         pNode->data = nValue;
     37         
     38         pNode->pNext = (*L)->pNext;
     39         (*L)->pNext = pNode;
     40     }
     41     
     42     return OK;
     43 }
     44 
     45 Status CreateLinkListFromRear(LinkList *L, int nInputLength) {
     46     if (NULL == L) {
     47         printf("Error parament.");
     48         return ERROR;
     49     }
     50     
     51     //build the head
     52     *L = (LinkList)malloc(sizeof(LNode));
     53     if (NULL == *L) {
     54         printf("Out of memory.");
     55         return ERROR;
     56     }
     57     (*L)->pNext = NULL; //make the list empty
     58     
     59     if (nInputLength < 1) {
     60         printf("Invalid input length.");
     61         return ERROR;
     62     }
     63 
     64     int nValue;
     65     LNode *pNode;
     66     LNode *pRear = *L;
     67     
     68     printf("Input the values:");
     69     for (int i = 1; i <= nInputLength; i++) {
     70         scanf("%d", &nValue);
     71         
     72         pNode = (LinkList)malloc(sizeof(LNode));
     73         if (NULL == pNode) {
     74             printf("Out of memory.");
     75             return ERROR;
     76         }
     77         pNode->data = nValue;
     78         
     79         pRear->pNext = pNode;
     80         pRear = pRear->pNext;
     81     }
     82     
     83     pRear->pNext = NULL;
     84     
     85     return OK;
     86 }
     87 
     88 
     89 Status InsertToLinkList(LinkList *L, int nIndex, ElemType eElem) {
     90     if (NULL == L) {
     91         printf("Error parament.");
     92         return ERROR;
     93     }
     94     
     95     if (nIndex < 1) {
     96         printf("Invalid insert point.");
     97         return ERROR;
     98     }
     99     
    100     int i = 0;
    101     LNode *pNode;
    102     LNode *qNode;
    103     
    104     qNode = (LinkList)malloc(sizeof(LNode));
    105     if (NULL == qNode) {
    106         printf("Out of memory.");
    107         return ERROR;
    108     }
    109     qNode->data = eElem;
    110     
    111     //the key--find the insert point
    112     pNode = *L;
    113     while (NULL != pNode->pNext && i < nIndex - 1) {
    114         pNode = pNode->pNext;
    115         i++;
    116     }
    117     
    118     //invalid insert point
    119     if (i < nIndex - 1) {
    120         printf("Invalid Insert point.");
    121         return ERROR;
    122     }
    123     
    124     //insert
    125     qNode->pNext = pNode->pNext;
    126     pNode->pNext = qNode;
    127     
    128     
    129     return OK;
    130 }
    131 
    132 Status DeleteFromLinkList(LinkList *L, int nIndex, ElemType *pElem) {
    133     if (NULL == L || NULL == pElem) {
    134         printf("Error parament.");
    135         return ERROR;
    136     }
    137     
    138     if (NULL == (*L)->pNext) {
    139         printf("The list is empty.");
    140         return ERROR;
    141     }
    142     
    143     if (nIndex < 1) {
    144         printf("Invalid delete point.");
    145         return ERROR;
    146     }
    147     
    148     int i = 0;
    149     LNode *qNode;
    150     LNode *pNode = *L;  //  in case of the first valid delete point, the pNode should point to the head.
    151     
    152     while (NULL != pNode->pNext && i < nIndex - 1) {
    153         pNode = pNode->pNext;
    154         i++;
    155     }
    156     
    157     if (NULL == pNode->pNext) { // nIndex - 1 == i
    158         printf("Invalid delete point.");
    159         return ERROR;
    160     }
    161     
    162     qNode = pNode->pNext;
    163     pNode->pNext = qNode->pNext;
    164     
    165     *pElem = qNode->data;
    166     free(qNode);
    167     qNode = NULL;
    168     
    169     return OK;
    170 }
    171 
    172 Status DestroyLinkList(LinkList *L) {
    173     if (NULL == L) {
    174         printf("Error parament.");
    175         return ERROR;
    176     }
    177     
    178     if (NULL == (*L)->pNext) {
    179         printf("The list is empty.");
    180         return ERROR;
    181     }
    182     
    183     LNode *pNode = (*L)->pNext;
    184     while (NULL != pNode) {
    185         (*L)->pNext = pNode->pNext;
    186         free(pNode);
    187         
    188         pNode = (*L)->pNext;
    189     }
    190     
    191     (*L)->pNext = NULL;
    192     pNode = NULL;
    193     
    194     return OK;
    195 }
    196 
    197 Status PrintLinkList(LinkList L) {
    198     if (NULL == L) {
    199         printf("Error parament.");
    200         return ERROR;
    201     }
    202     
    203     if (NULL == L->pNext) {
    204         printf("The list is empty.");
    205         return ERROR;
    206     }
    207     
    208     LNode *pNode = L->pNext;
    209     
    210     while (NULL != pNode) {
    211         printf("%d ", pNode->data);
    212         pNode = pNode->pNext;
    213     }
    214     
    215     return OK;
    216 }
    LinkList.h

        

    ————————————————————————————————————————————————————————————————— 一个理想主义者的追梦旅程
  • 相关阅读:
    Bootsrap 的 Carousel
    Bootstrap 的 Tooltip 和 Popover
    JavaScript 继承
    Bootstrap 的 Collapse
    Bootstrap 组件之 Panel
    Bootstrap 组件之 List group
    Bootstrap 组件之 Nav
    使用 classList API
    Bootstrap 的 Dropdown
    Bootstrap 的 Modal
  • 原文地址:https://www.cnblogs.com/michaelGood/p/4603222.html
Copyright © 2011-2022 走看看