数据结构算法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

  四.测试

原文地址:https://www.cnblogs.com/zhaoyu1995/p/5564339.html