线性表的链式存储实现(不带头结点)

简介: 线性表的链式存储实现(不带头结点)

建议使用带头结点的版本,因为不带头结点的版本有一些缺陷:

在插入或删除操作中,如果返回类型不是链表,那么形参类型一定是指向头结点的指针(也就是二级指针),因为传递指针实参时,形参实际上是实参的副本,所以实参的指向是一直不变的,如果在插入过程中插在了头指针的下一个位置(也就是第一个结点的位置),如果返回类型不是链表或形参不是二级指针,那么插入操作对原链表时无效的,而如果删除释放了第一个结点,那么由于实参的指向始终是第一个结点的那块内存,那么实参指针就是指向一块不知名的内存,成为野指针。总的来说,不带头结点的版本,在删除或插入操作中,如果返回类型不是链表或形参不是二级指针,那么该操作不能作用在第一个结点上

关于指针作为形参的问题可以参考:https://www.cnblogs.com/hi3254014978/p/9478307.html

LinkList.h

 1 #ifndef LINKLIST_H_INCLUDE
 2 #define LINKLIST_H_INCLUDE
 3 
 4 #include <stdio.h>
 5 #include <stdlib.h>
 6 #include <stdbool.h>
 7 
 8 #define ERROR -1
 9 
10 typedef int ElementType;
11 
12 typedef struct LNode* PtrToNode;
13 struct LNode{
14     ElementType Data;
15     PtrToNode Next;
16 };
17 
18 typedef PtrToNode Position;        //这里的位置某个结点的结点指针
19 typedef PtrToNode List;
20 
21 List L;
22 
23 //链表长度
24 int Length(List L);
25 
26 //根据位序查找元素
27 ElementType FindKth(List L, int K);
28 
29 //根据元素查找相应的结点
30 Position Find(List L, ElementType X);
31 
32 //在指定位置之后插入元素
33 List Insert(List L, ElementType X, int i);
34 
35 bool Delete(List *L, int i);
36 
37 void printList(List L);
38 
39 
40 
41 
42 #endif

LinkList.c

  1 #include "LinkList.h"
  2 
  3 int Length(List L)
  4 {
  5     int cnt = 0;
  6     List p = L;        //当前p指向第一个结点
  7     while (p)
  8     {
  9         cnt++;
 10         p = p->Next;
 11     
 12     }
 13     return cnt;
 14 
 15 }
 16 
 17 ElementType FindKth(List L, int K)
 18 {
 19     Position p = L;
 20     int cnt = 1;
 21     while (p && cnt < K)
 22     {
 23         p = p->Next;
 24         cnt++;
 25     }
 26     if ((cnt == K) && p)
 27         return p->Data;
 28     else
 29         return ERROR;
 30 }
 31 
 32 Position Find(List L, ElementType X)
 33 {
 34     Position p = L;
 35     while (p && p->Data != X)
 36         p = p->Next;
 37     if (p)
 38         return p;
 39     else
 40         return NULL;
 41 }
 42 
 43 List Insert(List L, ElementType X, int i)
 44 {
 45     Position tmp, pre;
 46     tmp = (Position)malloc(sizeof(struct LNode));
 47     if (i == 1)
 48     {
 49         tmp->Data = X;
 50         tmp->Next = L;
 51         return tmp;
 52     }
 53 
 54     else
 55     {
 56         int cnt = 1;
 57         pre = L;
 58         while (pre && cnt < i - 1)
 59         {
 60             pre = pre->Next;
 61             cnt++;
 62         }
 63         if (pre == NULL || cnt != i - 1)        //如果所招结点不再L中
 64         {
 65             printf("Insert position parameter error!\n");
 66             free(tmp);
 67             return L;
 68         }
 69         else
 70         {
 71             tmp->Data = X;
 72             tmp->Next = pre->Next;
 73             pre->Next = tmp;
 74             return L;
 75         }
 76     }
 77 }
 78 
 79 bool Delete(List *L, int i)
 80 {
 81     Position tmp, pre;
 82     int cnt = 1;
 83     pre = *L;
 84     if (i == 1 && pre)
 85     {
 86         *L = (*L)->Next;        //如果这里没有传*L,而是L,那么这里的L只是实参的副本,
 87                                 //所以如果删除并释放第一个结点后,因为实参的L还是指向第一个结点的,所以第一个结点被释放后,
 88                                 //实参L会只想一块不知名的内存,成为野指针,所以建议使用带头结点的链表
 89         free(pre);
 90         return true;
 91     }
 92     else
 93     {
 94         while (pre && cnt < i - 1)
 95         {
 96             pre = pre->Next;
 97             cnt++;
 98         }
 99         if (pre == NULL || cnt != i - 1 || pre->Next == NULL)        //i出错或链表为空
100         {
101             printf("Delete position parameter error!\n");
102             return false;
103         }
104         else
105         {
106             tmp = pre->Next;
107             pre->Next = tmp->Next;
108             free(tmp);
109             return true;
110         }
111     }
112     
113 }
114 
115 void printList(List L)
116 {
117     Position p;
118     p = L;
119     while (p)
120     {
121         printf("%d ", p->Data);
122         p = p->Next;
123     }
124     printf("\n");
125     return ;
126 }


相关文章
|
7月前
|
存储
【链表OJ】链表中倒数第k个结点 合并两个链表(含哨兵位) 分割链表 链表的回文结构
【链表OJ】链表中倒数第k个结点 合并两个链表(含哨兵位) 分割链表 链表的回文结构
|
11月前
|
存储
线性表的链式存储——链表
线性表的链式存储——链表
128 0
|
11月前
|
存储 编译器
【链表之单链表】
什么是链表 概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。 通俗地讲,就是一个结构体有两个成员,一个是存放数据的成员,一个是指针成员,通常的单链表是第一个节点的指针成员存着下一个节点的地址,下一个节点的指针成员又存下一个节点的地址,这样每个节点之间连接起来,就叫做链表。 本文主要讲的是链表中的一种重要的形式:单链表。
|
12月前
|
存储 算法 C++
线性表和链表
线性表和链表
95 0
初识线性链表
线性链表概述及其结构 所谓“线性”,即为一组数据元素形成前后关系。线性表主要以2种形式在内存中存放,一种是以数组的形式,用数组存放时是连续存放的,当我们需要对其中一个数据元素进行删除或者插入时,需要移动其他数据,并且用数组还需要申请合适的内存空间,太小装不下,太大会造成内存空间浪费。这时,就需要我们的线性链表出手,链表不需要在内存里面连续存放,而是以指针将各数据单元链接起来,所以,我们在进行删除或者插入数据元素时,不需要移动其他数据元素。 现在正式介绍链表,链表是由一系列的结点组成,每个节点包含两个域,一个是数据域,主要用来保存用户数据,可以是任意数据类型;另一个叫指针域,用来保存下一
初识线性链表
顺序循环队列和链式存储队列(带头结点和不带头结点)
顺序循环队列和链式存储队列(带头结点和不带头结点)
线性表的链式存储实现(带头结点)
线性表的链式存储实现(带头结点)
链表——单链表的反转
单链表的反转就是从原链表的第一个存 数据的结点开始,依次递归调用反转每一个结点,直到把最后一个结点反转完毕
93 0
链表——单链表的反转
|
存储 算法 C++
数据结构学习笔记——链表的相关知识(单链表带头结点和不带头结点的基本操作)(上)
数据结构学习笔记——链表的相关知识(单链表带头结点和不带头结点的基本操作)
数据结构学习笔记——链表的相关知识(单链表带头结点和不带头结点的基本操作)(上)