• 数据结构算法C语言实现(五)---2.3重新定义线性链表及其基本操作


      一.简述

      ...由于链表在空间的合理利用上和插入、删除时不需要移动等的优点,因此在很多场合下,它是线性表的首选存储结构。然而,它也存在着实现某些基本操作,如求线性表的长度时不如顺序存储结构的缺点;另一方面,由于在链表中,结点之间的关系用指针来表示,则数据元素在线性表中的“位序”的概念已经淡化,而被数据元素在线性链表中的“位置”所代替。为此,从实际应用的角度重新定义线性链表及其基本操作。....(Page37) 

      此外,书上一些地方我认为存在错误,所以写代码时做了修改和注释。并且,由于一些基本操作书中没有具体使用的实例,所以我只实现了算法2.20和算法2.21中出现的基本操作,其他操作会在需要的时候 再做实现。

      二.头文件

      1 //LinkList.h
      2 /**
      3 《数据结构(C语言版)》 Page 37
      4 ....为此,从实际应用角度出发重新定义线性链表及其基本操作....
      5 */
      6 /**
      7 author:zhaoyu
      8 email:zhaoyu1995.com@gmail.com
      9 date:2016-6-4
     10 note:realize my textbook <<数据结构(C语言版)>>
     11 */
     12 #ifndef _LINKLIST_H_
     13 #define _LINKLIST_H_
     14 #include "head.h"
     15 #include <cstdlib>
     16 #define ElemType int
     17 typedef struct LNode{
     18     ElemType data;
     19     struct LNode *next;
     20 }*Link, *Position;
     21 typedef struct{//链表类型
     22     Link head, tail;//分别指向线性链表中的头结点和最后一个结点
     23     int len;//指示线性链表中数据元素的个数
     24 }LinkList;
     25 Status MakeNode(Link &p, ElemType e)
     26 {
     27     //分配由 p 指向的值为 e 的结点,并返回 OK;若分配失败,则返回 ERROR
     28     p = (Link)malloc(sizeof(struct LNode));
     29     if (!p)
     30     {
     31         return ERROR;
     32     }
     33     p->data = e;
     34     p->next = NULL;
     35     return OK;
     36 }
     37 Status FreeNode(Link &p)
     38 {
     39     //释放 p 所指节点
     40     p = NULL;//便于回收???释放后再次使用
     41     free(p);
     42 }
     43 Status InitList(LinkList &L)
     44 {
     45     //构造一个空的线性表L
     46     L.head = (Link)malloc(sizeof(struct LNode));
     47     L.head->data = 100;
     48     L.head->next = NULL;
     49     L.tail = L.head->next;
     50     L.len = 0;
     51 }
     52 Status ClearList(LinkList &L)
     53 {
     54     //将线性链表置为空表并释放原链表的结点空间
     55 }
     56 Status InsFirst(LinkList &L, Link &h, Link &s)
     57 {
     58     //已知 h 指向线性链表的头结点,将 s 所指节点插入在第一个结点之前
     59     //note:这里的参数与书上有些不一样,LinkList &L是我添加的
     60     //因为插入新的元素之后,链表长度应该同步变化
     61     //链表的插入是基于地址的,所以我全部加了引用
     62     //这一个函数与书上参数完全不同
     63     //更新 2016-5-5 16:46
     64     //通过分析算法2.20发现 h 不是绝对的头结点,而是接受一个 h
     65     //就以它为头结点作参考操作其它元素
     66     //这个函数花了不少时间,值得反复思考
     67     if (NULL == h)
     68     {
     69         return ERROR;
     70     }
     71     else
     72     {
     73         s->next = h->next;
     74         h->next = s;
     75     }
     76     L.len++;
     77     return OK;
     78 }
     79 Status DelFirst(Link &h, Link &q)
     80 {
     81     //已知 h 指向线性链表的头结点,删除链表中的第一个节点并以 q 返回
     82     if (h == NULL)
     83     {
     84         return ERROR;
     85     }
     86     q = h->next;
     87     h->next = q->next;
     88     q->next = NULL;
     89     return OK;
     90 }
     91 Status Append(LinkList &L, Link &s)
     92 {
     93     //将指针 s 所指(彼此以指针相链)的一串结点
     94     //链接在线性链表 L 最后一个结点
     95     Link q = L.head;
     96     while (q->next != NULL)
     97     {
     98         q = q->next;
     99     }
    100     q->next = s;
    101     int cnt = 0;
    102     Link temp = s;
    103     while (temp != NULL)
    104     {
    105         cnt++;
    106         if (NULL == temp->next)
    107         {
    108             L.tail = temp;//注意更新尾指针
    109         }
    110         temp = temp->next;
    111     }
    112 
    113     L.len += cnt;
    114     //注意要根据这一串结点长度增加链表长度
    115     return OK;
    116 }
    117 Status Remove(LinkList &L, Link &q)
    118 {
    119     //删除线性链表 L 中的尾结点并以 q 返回,改变链表的尾指针指向新的尾结点
    120 }
    121 Status InsBefore(LinkList &L, Link &p, Link s)
    122 {
    123     //已知 p 指向线性链表 L 中的一个结点,将 s 所指结点插入 p 所指节点之前
    124     //并修改指针 p 指向新插入的节点
    125 }
    126 Status InsAfter(LinkList &L, Link &p, Link s)
    127 {
    128     //已知 p 指向线性链表 L 中的一个结点,将 s 所指结点插入 p 所指节点之后
    129     //并修改指针 p 指向新插入的节点
    130 }
    131 Status SetCurElem(Link &p, ElemType e)
    132 {
    133     //已知 p 指向线性链表中的一个结点,用 e 更新 p 所指结点中数据元素的值
    134 }
    135 ElemType GetCurElem(Link p)
    136 {
    137     //已知 p 指向线性链表中的一个节点,返回 p 所指结点中数据元素的值
    138     if (p != NULL)
    139     {
    140         return p->data;
    141     }
    142     else
    143     {
    144         exit(ERROR);
    145     }
    146 }
    147 Status ListEmpty(LinkList L)
    148 {
    149     //若线性链表 L 为空,则返回 TRUE,否则返回 FALSE
    150 }
    151 int ListLength(LinkList L)
    152 {
    153     //返回线性链表 L 中元素的个数
    154 
    155 }
    156 Position GetHead(LinkList L)
    157 {
    158     //返回线性链表 L 中头结点的位置
    159     return L.head;
    160 }
    161 Position GetLast(LinkList L)
    162 {
    163     //返回线性链表 L 中最后一个结点的位置
    164 }
    165 Position PriorPos(LinkList L, Link p)
    166 {
    167     //已知 p 指向线性链表 L 中的一个结点,返回 p 所指结点直接前驱的位置
    168     //若无前驱,则返回NULL
    169 }
    170 Position NextPos(LinkList L, Link p)
    171 {
    172     //已知 p 指向线性链表 L 中的一个节点,返回 p 所指结点
    173     //的直接后继的位置,若无后继,返回 NULL
    174     Link q = L.head;
    175     while (q != NULL)
    176     {
    177         if(q == p)
    178         {
    179             return p->next;
    180         }
    181         q = q->next;
    182     }
    183     return NULL;
    184 }
    185 Status LocatePos(LinkList L, int i, Link &p)
    186 {
    187     //返回 p 指示线性链表 L 中第 i 个结点的位置并返回 OK
    188     //i 值不合法时返回ERROR
    189     int cnt = 2;
    190     p = L.head;
    191     if (i > L.len || i < 1)
    192     {
    193         return ERROR;
    194     }
    195     while (cnt <= i)
    196     {
    197         p = p->next;
    198         cnt++;
    199     }
    200     return OK;
    201 
    202 }
    203 Position LocateElem(LinkList L, ElemType e, Status (* compare)(ElemType, ElemType))
    204 {
    205     //返回线性链表中第一个与 e 满足函数compare() 判定关系的元素的位置
    206     //若不存在这样的元素,返回 NULL
    207 }
    208 Status ListTraverse(LinkList L, Status (* visit)())
    209 {
    210     //依次对 L 中每个元素调用函数 visit(),一旦visit() 失败,则操作失败。
    211 }
    212 /**
    213 My Code
    214 */
    215 void PrintList(LinkList L)
    216 {
    217     Link p = L.head->next;
    218     int cnt = 1;
    219     while (p != NULL && cnt <= L.len)
    220     {
    221         printf("%d	", p->data);
    222         p = p->next;
    223         cnt++;
    224     }
    225     printf("
    ");
    226 }
    227 int compare(ElemType a, ElemType b)
    228 {
    229     if (a < b)
    230     {
    231         return -1;
    232     }
    233     else if (a == b)
    234     {
    235         return 0;
    236     }
    237     else
    238     {
    239         return 1;
    240     }
    241 }
    242 #endif
    View Code

      三.CPP文件

      1 //LinkList.h
      2 /**
      3 《数据结构(C语言版)》 Page 37
      4 ....为此,从实际应用角度出发重新定义线性链表及其基本操作....
      5 */
      6 /**
      7 author:zhaoyu
      8 email:zhaoyu1995.com@gmail.com
      9 date:2016-6-4
     10 note:realize my textbook <<数据结构(C语言版)>>
     11 */
     12 #ifndef _LINKLIST_H_
     13 #define _LINKLIST_H_
     14 #include "head.h"
     15 #include <cstdlib>
     16 #define ElemType int
     17 typedef struct LNode{
     18     ElemType data;
     19     struct LNode *next;
     20 }*Link, *Position;
     21 typedef struct{//链表类型
     22     Link head, tail;//分别指向线性链表中的头结点和最后一个结点
     23     int len;//指示线性链表中数据元素的个数
     24 }LinkList;
     25 Status MakeNode(Link &p, ElemType e)
     26 {
     27     //分配由 p 指向的值为 e 的结点,并返回 OK;若分配失败,则返回 ERROR
     28     p = (Link)malloc(sizeof(struct LNode));
     29     if (!p)
     30     {
     31         return ERROR;
     32     }
     33     p->data = e;
     34     p->next = NULL;
     35     return OK;
     36 }
     37 Status FreeNode(Link &p)
     38 {
     39     //释放 p 所指节点
     40     p = NULL;//便于回收???释放后再次使用
     41     free(p);
     42 }
     43 Status InitList(LinkList &L)
     44 {
     45     //构造一个空的线性表L
     46     L.head = (Link)malloc(sizeof(struct LNode));
     47     L.head->data = 100;
     48     L.head->next = NULL;
     49     L.tail = L.head->next;
     50     L.len = 0;
     51 }
     52 Status ClearList(LinkList &L)
     53 {
     54     //将线性链表置为空表并释放原链表的结点空间
     55 }
     56 Status InsFirst(LinkList &L, Link &h, Link &s)
     57 {
     58     //已知 h 指向线性链表的头结点,将 s 所指节点插入在第一个结点之前
     59     //note:这里的参数与书上有些不一样,LinkList &L是我添加的
     60     //因为插入新的元素之后,链表长度应该同步变化
     61     //链表的插入是基于地址的,所以我全部加了引用
     62     //这一个函数与书上参数完全不同
     63     //更新 2016-5-5 16:46
     64     //通过分析算法2.20发现 h 不是绝对的头结点,而是接受一个 h
     65     //就以它为头结点作参考操作其它元素
     66     //这个函数花了不少时间,值得反复思考
     67     if (NULL == h)
     68     {
     69         return ERROR;
     70     }
     71     else
     72     {
     73         s->next = h->next;
     74         h->next = s;
     75     }
     76     L.len++;
     77     return OK;
     78 }
     79 Status DelFirst(Link &h, Link &q)
     80 {
     81     //已知 h 指向线性链表的头结点,删除链表中的第一个节点并以 q 返回
     82     if (h == NULL)
     83     {
     84         return ERROR;
     85     }
     86     q = h->next;
     87     h->next = q->next;
     88     q->next = NULL;
     89     return OK;
     90 }
     91 Status Append(LinkList &L, Link &s)
     92 {
     93     //将指针 s 所指(彼此以指针相链)的一串结点
     94     //链接在线性链表 L 最后一个结点
     95     Link q = L.head;
     96     while (q->next != NULL)
     97     {
     98         q = q->next;
     99     }
    100     q->next = s;
    101     int cnt = 0;
    102     Link temp = s;
    103     while (temp != NULL)
    104     {
    105         cnt++;
    106         temp = temp->next;
    107         if (NULL == temp->next)
    108         {
    109             L.tail = temp;//注意更新尾指针
    110         }
    111     }
    112 
    113     L.len += cnt;
    114     //注意要根据这一串结点长度增加链表长度
    115     return OK;
    116 }
    117 Status Remove(LinkList &L, Link &q)
    118 {
    119     //删除线性链表 L 中的尾结点并以 q 返回,改变链表的尾指针指向新的尾结点
    120 }
    121 Status InsBefore(LinkList &L, Link &p, Link s)
    122 {
    123     //已知 p 指向线性链表 L 中的一个结点,将 s 所指结点插入 p 所指节点之前
    124     //并修改指针 p 指向新插入的节点
    125 }
    126 Status InsAfter(LinkList &L, Link &p, Link s)
    127 {
    128     //已知 p 指向线性链表 L 中的一个结点,将 s 所指结点插入 p 所指节点之后
    129     //并修改指针 p 指向新插入的节点
    130 }
    131 Status SetCurElem(Link &p, ElemType e)
    132 {
    133     //已知 p 指向线性链表中的一个结点,用 e 更新 p 所指结点中数据元素的值
    134 }
    135 ElemType GetCurElem(Link p)
    136 {
    137     //已知 p 指向线性链表中的一个节点,返回 p 所指结点中数据元素的值
    138     if (p != NULL)
    139     {
    140         return p->data;
    141     }
    142     else
    143     {
    144         exit(ERROR);
    145     }
    146 }
    147 Status ListEmpty(LinkList L)
    148 {
    149     //若线性链表 L 为空,则返回 TRUE,否则返回 FALSE
    150 }
    151 int ListLength(LinkList L)
    152 {
    153     //返回线性链表 L 中元素的个数
    154 
    155 }
    156 Position GetHead(LinkList L)
    157 {
    158     //返回线性链表 L 中头结点的位置
    159     return L.head;
    160 }
    161 Position GetLast(LinkList L)
    162 {
    163     //返回线性链表 L 中最后一个结点的位置
    164 }
    165 Position PriorPos(LinkList L, Link p)
    166 {
    167     //已知 p 指向线性链表 L 中的一个结点,返回 p 所指结点直接前驱的位置
    168     //若无前驱,则返回NULL
    169 }
    170 Position NextPos(LinkList L, Link p)
    171 {
    172     //已知 p 指向线性链表 L 中的一个节点,返回 p 所指结点
    173     //的直接后继的位置,若无后继,返回 NULL
    174     Link q = L.head;
    175     while (q != NULL)
    176     {
    177         if(q == p)
    178         {
    179             return p->next;
    180         }
    181         q = q->next;
    182     }
    183     return NULL;
    184 }
    185 Status LocatePos(LinkList L, int i, Link &p)
    186 {
    187     //返回 p 指示线性链表 L 中第 i 个结点的位置并返回 OK
    188     //i 值不合法时返回ERROR
    189     int cnt = 2;
    190     p = L.head;
    191     if (i > L.len || i < 1)
    192     {
    193         return ERROR;
    194     }
    195     while (cnt <= i)
    196     {
    197         p = p->next;
    198         cnt++;
    199     }
    200     return OK;
    201 
    202 }
    203 Position LocateElem(LinkList L, ElemType e, Status (* compare)(ElemType, ElemType))
    204 {
    205     //返回线性链表中第一个与 e 满足函数compare() 判定关系的元素的位置
    206     //若不存在这样的元素,返回 NULL
    207 }
    208 Status ListTraverse(LinkList L, Status (* visit)())
    209 {
    210     //依次对 L 中每个元素调用函数 visit(),一旦visit() 失败,则操作失败。
    211 }
    212 /**
    213 My Code
    214 */
    215 void PrintList(LinkList L)
    216 {
    217     Link p = L.head->next;
    218     int cnt = 1;
    219     while (p != NULL && cnt <= L.len)
    220     {
    221         printf("%d	", p->data);
    222         p = p->next;
    223         cnt++;
    224     }
    225     printf("
    ");
    226 }
    227 int compare(ElemType a, ElemType b)
    228 {
    229     if (a < b)
    230     {
    231         return -1;
    232     }
    233     else if (a == b)
    234     {
    235         return 0;
    236     }
    237     else
    238     {
    239         return 1;
    240     }
    241 }
    242 #endif
    View Code

      四.测试

  • 相关阅读:
    重置 Mac 上的 NVRAM 或 PRAM
    为什么我的mac插入耳机耳机没有声音呢?
    Redis 实现安全队列
    设计模式之十三:适配器模式(Adapter)
    关于cocos2dx手游lua文件加密的解决方式
    Django中载入js和css文件
    CCNA 例题精选
    JNI/NDK开发指南(四)——字符串处理
    error when loading the sdk 发现了元素 d:skin 开头无效内容
    Webx学习(一)
  • 原文地址:https://www.cnblogs.com/zhaoyu1995/p/5564339.html
Copyright © 2020-2023  润新知