线性表的链式存储(C代码实现)

线性表的链式存储结构

线性表的实现分顺序存储结构链式存储结构。

上一节我们学学习了线性表的实现分顺序存储结构,并实现解顺序存储的基本操作。

这一节我们来学习线性表链式存储结构,那我们再想象一下我为什么我们要引入链式存储结构,万物存在必有其道理

主要还是因为线性存储结构存在着这样一个问题:当我们需要插入和删除元素时,就必须挪动大量与之无关的元素,因为线性存储结构结点与节点之间的关系是相邻关系,一个节点挨着一个节点

如为了插入或者删除一个元素移动大量的元素,这样就降低了程序运行效率。

当我们引入

顾名思义链式存储结构,数据与数据之间是以链式关系来产生连接的的,我们可以脑部一下锁链的样子,不扯淡了,进入正题--

我们如何定义一个链式存储结构的节点呢?

/*Node表示一个节点*/
typedef struct Node{
    int data;   //数据域
    struct Node* next;   //存放下一个节点的指针
}Node;
typedef struct Node* LinkList; /*取了一个别名,定义LinkList = Node*,用于存放节点的指针*/

一个节点包括一个数据域和指针域

我们将这种只带有一个指针域的线性表称为单链表

链表中第一个结点的存储位置叫做头指针。

单链表的第一个结点前附设一个结点,称为头结点

注意可以没有头节点,但是要是链表,就一定存在头指针。

那么问题来了,我们如何区分头节点和头指针呢?

头指针:是指向链表的指针,如果不存在头节点,那么头指针就会指向链表的第一个节点。

头节点:实际上是不存在的,只不过是为了链表的一些操作方便而设置的,头节点与第一个节点以链式关系相连,并且头节点的数据域没有意义,指针域存放第一个节点的地址。

单链表的插入

s->next =p->next;
p->next=s;    //注意前后顺序不能调

单链表的删除

q= p->next;
p->next = q->next;
free(q);

单链表的建表(头插法)

顾名思义直接插在第一位,就是头节点的后面。

 1 void CreateListHead(LinkList *L,int n){
 2
 3     LinkList p;
 4     *L = (Node*)malloc(sizeof(Node));  //生成的新节点节点要初始化
 5     (*L)->next=NULL;    //并指向空
 6
 7     for(int i=0;i<n;i++){
 8         p =(Node*)malloc(sizeof(Node)); //新生成的节点节点要初始化
 9         p->data=i;
10         p->next=(*L)->next;  //这里不能指向NULL
11         (*L)->next =p;   //两级指针
12     }
13 }

单链表的建表(尾插法)

 1 void CreateListTail(LinkList *L ,int n){
 2
 3     LinkList p,r;   //生成节点p,存放Node地址
 4     *L = (Node*)malloc(sizeof(Node));  //生成的头节点节点要初始化
 5     (*L)->next=NULL;
 6     r = *L;  //用于遍历
 7
 8     for(int i=0;i<n;i++){
 9         p =(Node*)malloc(sizeof(Node)); //新生成的节点节点要初始化
10         p->data=i;
11         r->next=p;
12         r=p;  //r指针移动到p上r ,以便
13     }
14     r->next=NULL; //最后一个指向空
15 }

单链表的遍历

1 void TraverseList(LinkList L){
2     LinkList p;
3     p = L->next;
4     while(p){
5         printf("%d ",p->data);
6          p=p->next;
7     }
8 }

清空单链表

 1 /*清空链表*/
 2 void ClearList(LinkList L){
 3     LinkList p ,q;
 4     p = L->next;     //指向第一个元素
 5     while(p){
 6         q=p->next;  //q指向了p的下一个
 7         free(p);   //释放内存
 8         p =q;
 9     }
10     L->next =NULL;     //头节点指向空
11 }

其它的一下操作见下面代码吧

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include "time.h"
  4
  5 /*Node表示一个节点*/
  6 typedef struct Node{
  7     int data;
  8     struct Node* next;
  9 }Node;
 10 typedef struct Node* LinkList; /*定义LinkList*/
 11
 12 /*初始化链表*/
 13 int InitList(LinkList *L){
 14     *L=(LinkList)malloc(sizeof(Node));  //这里的*L就是Node节点的指针对象
 15     if(!(*L))   //申请内存失败
 16         return 0;
 17     (*L)->next=NULL;
 18     return 1;
 19 }
 20
 21 //头插法,n表示插入的个数
 22 void CreateListHead(LinkList *L,int n){
 23
 24     LinkList p;
 25     *L = (Node*)malloc(sizeof(Node));  //生成的新节点节点要初始化
 26     (*L)->next=NULL;    //并指向空
 27
 28     for(int i=0;i<n;i++){
 29         p =(Node*)malloc(sizeof(Node)); //新生成的节点节点要初始化
 30         p->data=i;
 31         p->next=(*L)->next;  //这里不能指向NULL
 32         (*L)->next =p;   //两级指针
 33     }
 34 }
 35 //尾插法,n表示插入的个数
 36 void CreateListTail(LinkList *L ,int n){
 37
 38     LinkList p,r;   //生成节点p,存放Node地址
 39     *L = (Node*)malloc(sizeof(Node));  //生成的头节点节点要初始化
 40     (*L)->next=NULL;
 41     r = *L;  //用于遍历
 42
 43     for(int i=0;i<n;i++){
 44         p =(Node*)malloc(sizeof(Node)); //新生成的节点节点要初始化
 45         p->data=i;
 46         r->next=p;
 47         r=p;  //r指针移动到p上r ,以便
 48     }
 49     r->next=NULL; //最后一个指向空
 50 }
 51
 52 /*遍历链表*/
 53 void TraverseList(LinkList L){
 54     LinkList p;
 55     p = L->next;
 56     while(p){
 57         printf("%d ",p->data);
 58          p=p->next;
 59     }
 60 }
 61
 62 /*清空链表*/
 63 void ClearList(LinkList L){
 64     LinkList p ,q;
 65     p = L->next;     //指向第一个元素
 66     while(p){
 67         q=p->next;  //q指向了p的下一个
 68         free(p);   //释放内存
 69         p =q;
 70     }
 71     L->next =NULL;     //头节点指向空
 72 }
 73
 74 /*获取链表长度*/
 75 int GetLengthList(LinkList L){
 76     LinkList p;
 77     p=L->next;
 78     int count=0;   //计数器
 79     while(p){
 80         count++;
 81         p= p ->next;
 82     }
 83     return count;
 84
 85 }
 86
 87 /*删除元素*/
 88 void DeleteElem(LinkList L,int n){
 89     int count=0;
 90     LinkList p ,q;
 91     p =L;   //注意这里的p不在指向第一个节点了
 92     count =1;
 93     while(p->next && count<n){  //
 94         p =p->next;
 95         ++count;
 96     }
 97     if(!(p->next) || count>n)
 98         printf("没有找到可删除的元素");
 99     q= p->next;
100     p->next = q->next;
101      free(q);
102 }
103
104 /*插入元素 n是位置,c是数*/
105 void InsertElemList(LinkList L,int n,int c){
106
107     int count=0;
108     LinkList p,s;
109     p =L;   //注意这里的p不在指向第一个节点了
110     count =1;
111     while(p->next && count<n){  //
112         p =p->next;
113         ++count;
114     }
115     s =(Node*)malloc(sizeof(Node));
116     s->data=c;
117     s->next =p->next;
118     p->next=s;
119
120 }
121
122 /* 初始条件:顺序线性表L已存在 */
123 /* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
124 /* 若这样的数据元素不存在,则返回值为0 */
125 int LocateElem(LinkList L,int e){
126
127     LinkList p;
128     p =L->next;
129     while(p){
130         if(p->data == e)
131             return 1;
132         p =p->next;
133     }
134     return 0;
135 }
136
137 /*获取元素,n表示第几个,并返回查到的值*/
138 int GetElem(LinkList L,int n){
139
140     LinkList p;   //生成节点p,存放Node地址
141     p = L->next;   //p指向第一个元素
142     int count=1;   //计数器
143
144     while(p && count<n){ //查找
145         p = p->next;
146         count++;
147     }
148     if(!p || count>n){ //没找到
149         return 0;
150     }
151     int ret = p->data;    //找到
152     return ret;
153 }
154
155 /*判断链表是否为空*/
156 int ListElmpty(LinkList L){
157
158     if(L->next){
159         return 0;
160     }else{
161         return 1;
162     }
163 }
164
165 int main(){
166     LinkList L1;   //创建一个节点,用于头插法
167     LinkList L2;   //创建一个节点,用于尾插法
168
169     printf("......头插法......\n");
170     InitList(&L1);  //初始化
171     CreateListHead(&L1,5);
172     TraverseList(L1);
173     printf("\n");
174
175     printf("......尾插法......\n");
176     InitList(&L2);  //初始化
177     CreateListTail(&L2,5);
178     TraverseList(L2);
179     printf("\n");
180
181     //获取元素的值
182     int getElem= GetElem(L2,3);
183     printf("%d \n",getElem);
184
185     //获取长度
186     int GetLength=GetLengthList(L2);
187     printf("L1链表的长度:%d",GetLength);
188     printf("\n");
189
190     //删除L1中2号元素
191     printf("删除L1中2号元素:");
192     DeleteElem(L1,2);
193     TraverseList(L1);
194     printf("\n");
195
196     //在第三个位置插入11
197     printf("在第三个位置插入11元素:");
198     InsertElemList(L1,3,11);
199     TraverseList(L1);
200     printf("\n");
201
202     int localFind=LocateElem(L1,11);
203     printf("找到了吗: %d\nd",localFind);
204
205     //判断L1是否为空
206     int lstElempty=ListElmpty(L1);
207     printf("L1为空吗: %d\n",lstElempty);
208     //清空L1
209     ClearList(L1);
210     //在判断L1是否为空
211     lstElempty=ListElmpty(L1);
212     printf("L1为空吗: %d\n",lstElempty);
213
214     return 0;
215 }

写完插入和删除操作,我们便可以看出,链式存储结构对于插入和删除的优势是明显的,不需要进行大量的元素的移动。

当然单链表这么个优秀,也是存在缺点的

缺点就是其不便于进行查找和修改,每查找或者修改一个元素就要开始从头开始遍历  - -这么坑爹的吗 ?没错 就是这么坑爹 - -

所以当我们应用的场合不同 ,就用不同的存储结构。

原文地址:https://www.cnblogs.com/liuzeyu12a/p/10300110.html

时间: 2024-10-08 22:04:18

线性表的链式存储(C代码实现)的相关文章

线性表的链式存储之单链表的尾插法

对单链表进行遍历.查找.插入.删除等操作,最终效果如下: 相关C代码如下: /*线性表的链式存储之单链表的尾插法*/ #include <stdio.h> #include <stdlib.h> #include <malloc.h> /*定义变量*/ typedef int DataType; typedef struct node{     //定义链表结点数据结构 DataType data; struct node * pNext; }NODE; typedef

线性表的链式存储

线性表的链式存储 线性表的链式存储 基本概念 设计与实现 实现代码 优缺点 1. 基本概念 链式存储定义 为了表示每个数据元素与其直接后继元素之间的逻辑关系,每个元素除了存储本身的信息外,还需要存储指示其直接后继的信息. 表头结点 链表中的第一个结点,包含指向第一个数据元素的指针以及链表自身的一些信息 数据结点 链表中代表数据元素的结点,包含指向下一个数据元素的指针和数据元素的信息 尾结点 链表中的最后一个数据结点,其下一元素指针为空,表示无后继. 2.设计与实现 在C语言中可以用结构体来定义链

数据结构之线性表(链式存储结构)

线性表的实现分顺序存储结构和链式存储结构 上一节我们主要介绍了顺序存储结构,在最后我们还分别总结了顺序存储结构的优缺点, 对于顺序结构的缺点,我们有没有什么好的解决方法呢? 我们今天要介绍的线性表的链式存储结构就可以很好的解决顺序结构的缺点,一起来看. 顺序结构最大的缺点就是在进行插入和删除操作的时候,如果插入位置不理想,那么我们需要移动大量的元素,那产生这一问题的原因是什么呢? 仔细分析后,我们可以发现在顺序存储结构中,他们相邻的元素的存储位置也是相邻的,我们在申请内存的的时候,是一次性申请一

数据结构开发(5):线性表的链式存储结构

0.目录 1.线性表的链式存储结构 2.单链表的具体实现 3.顺序表和单链表的对比分析 4.小结 1.线性表的链式存储结构 顺序存储结构线性表的最大问题是: 插入和删除需要移动大量的元素!如何解决? 链式存储的定义: 为了表示每个数据元素与其直接后继元素之间的逻辑关系:数据元素除了存储本身的信息外,还需要存储其直接后继的信息. 链式存储逻辑结构: 基于链式存储结构的线性表中,每个结点都包含数据域和指针域 数据域:存储数据元素本身 指针域:存储相邻结点的地址 专业术语的统一: 顺序表 基于顺序存储

数据结构--线性表的链式存储结构

一 线性表的链式存储结构 A.链式存储的定义为了表示每个数据元素与直接后继元素之间的逻辑关系:数据元素除了存储本身的信息外,还需要存储其直接后继的信息图示B链式存储逻辑结构基于链式存储结构的线性表中,每个结点都包含数据域和指针域1.数据域:存储数据元素本身2.指针域:存储相邻结点的地址图示C链表中的基本概念1.头结点--链表中的辅助结点,包含指向第一个数据元素的指针(方便插入和删除)2.数据结点--链表中代表数据元素的结点,表现形式为:(数据元素,地址)3.尾节点--链表中的最后一个数据结点,包

线性表的链式存储结构

1 n个结点链结成一个链表,即为线性表的链式存储结构,由于每一个结点只包含一个指针域,因此称为单链表. 链表中第一个结点的存储位置成为头指针,那么整个链表的存取就必须是从头指针开始了. 有时候会在单链表的第一个结点前附设一个结点,称为头结点. 头指针与头结点的区别: 头指针: (1)头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针. (2)头指针具有标识作用,所以常用头指针冠以链表的名字. (3)无论链表是否为空,头指针都不为空.头指针是链表的必要元素. 头结点: (1)

leetcode_1题——Swap Nodes in Pairs(线性表的链式存储)

Swap Nodes in Pairs Total Accepted: 45110 Total Submissions: 138992My Submissions Question Solution Given a linked list, swap every two adjacent nodes and return its head. For example,Given 1->2->3->4, you should return the list as 2->1->4-

数据结构第三篇——线性表的链式存储之单链表

线性表的链式存储结构的特点是用一组任意的存储单元来存储线性表的数据元素,这些单元可以分散在内存中的任意位置上,其在物理上可以是连续的,也可以是不连续的.具有链式存储结构的线性表称为线性链表. 为了表示出每个数据元素与其后继之间的关系,除了存储数据元素本身的信息之外,还需存储指示其直接后继的信息.这可以用一个结点(node)来完整的表示. 将节点中存储数据元素本身信息的域称为数据域:存储其直接后继位置的域称为指针域.指针域中存储的信息称作指针或链. 一般情况下,链表中每个结点可以包含若干个数据域和

【数据结构】-线性表的链式存储结构

引言:由于线性表的顺序存储结构在插入和删除时需要大量移动数据元素,从而引入线性表的链式存储结构. 线性表的链式存储结构:用一组任意的存储单元(可以连续也可以不连续)存储线性表的数据元素. 为了表示数据元素ai和其直接后继ai+1之间的逻辑关系,对ai来说,除了存储其本身的数据信息外,还需要存储其直接后继的存储位置.这两部分信息组成数据元素ai的存储映像(结点).它包含两个域:其中存储数据元素信息的域称为数据域:存储直接后继存储位置的域称为指针域. n个结点链接成一个链表,称为线性链表,由于此链表