链表!
对于数据的存储,在我们初学者来说通常来说第一反应基本上是开数组,谈到多种数据不过就是多开几组数组,或者说用结构体,但是这仅仅只是对于已知数据多少的一种判断,但如果是对于未知数量的不同数据组的存储,那可能会束手无策。但问题总的有解决的途径,所以这种时候,链表就是一个不错的选择!
链表,基于结构体,并运用指针的存储地址的特性对未知数量的数据进行存储。其特点:
- n个节点离散分配;
- 每一个节点之间通过指针相连;
- 每一个节点有一个前驱节点和一个后继节点;
- 首节点没有前驱节点,尾节点没有后继节点。
学习链表需要掌握的一些必备知识:
首节点:存放第一个有效数据的节点
头节点:在单链表的第一个结点之前附设一个结点,它没有直接前驱,称之为头结点,头结点的数据域可以不存储任何信息,指针域指向第一个节点(首节点)的地址。头结点的作用是使所有链表(包括空表)的头指针非空
头指针:指向头节点的指针
尾节点:存放最后一个有效数据的节点
尾指针:指向尾节点的指针
链表通过我自己的理解,我认为就是通过指针和malloc(开数据空间)函数
反复调用结构体,对多组数据的存储。
#include <stdio.h> #include <stdlib.h> struct link *AppendNode(struct link *head){ //声明创建节点函数 struct link *p = NULL,*pr = head; //创建p指针,初始化为NULL;创建pr指针,通过pr指针来给指针域赋值 int data ; p = (struct link *)malloc(sizeof(struct link)) ; //为指针p申请内存空间,必须操作,因为p是新创建的节点 if(p == NULL){ //如果申请内存失败,则退出程序 printf("NO enough momery to allocate!\n"); exit(0); } if(head == NULL){ //如果头指针为NULL,说明现在链表是空表 head = p; //使head指针指向p的地址(p已经通过malloc申请了内存,所以有地址) }else{ //此时链表已经有头节点 ,再一次执行了AppendNode函数 //注:假如这是第二次添加节点 //因为第一次添加头节点时,pr = head,和头指针一样指向头节点的地址 while(pr->next!= NULL){ //当pr指向的地址,即此时的p的指针域不为NULL(即p不是尾节点) pr = pr->next; //使pr指向头节点的指针域 } pr->next = p; //使pr的指针域指向新键节点的地址,此时的next指针域是头节点的指针域 } printf("Input node data:"); scanf("%d",&data); p->data = data; //给p的数据域赋值 p->next = NULL; //新添加的节点位于表尾,所以它的指针域为NULL return head; //返回head的地址 } void DisplayNode(struct link *head){ //输出函数,打印链表 struct link *p = head; // 定义p指针使其指向头节点 int j = 1; //定义j记录这是第几个数值 while(p != NULL){ //因为p = p->next,所以直到尾节点打印结束 printf("%5d%10d\n",j,p->data); p = p->next; //因为节点已经创建成功,所以p的指向由头节点指向下一个节点(每一个节点的指针域都指向了下一个节点) j++; } } void DeleteMemory(struct link *head){ //释放资源函数 struct link *p = head,*pr = NULL; //定义p指针指向头节点 while(p != NULL){ //当p的指针域不为NULL pr = p; //将每一个节点的地址赋值给pr指针 p = p->next; //使p指向下一个节点 free(pr); //释放此时pr指向节点的内存 } } //定义结构体 struct link{ int data; //定义数据域 struct link *next; //定义指针域 }; int main(){ int i =0; //定义i,记录创建的节点数 char c; struct link *head = NULL; //创建头指针,初始化为NULL printf("DO you wang to append a new node(Y or N)?"); scanf(" %c",&c); while(c == 'Y' || c == 'y'){ //如果确定继续添加结点 head = AppendNode(head); //通过函数获得链表的地址,AppendNode函数返回的是链表的头指针 //可以根据头指针指向的地址来获取链表中保存的数据 DisplayNode(head); //根据头指针打印链表 printf("DO you want to append a new node(Y or N)?"); scanf(" %c",&c); i++; } printf("%d new nodes hava been appended!\n",i); DeleteMemory(head); //释放占用的内存 }
大佬源码:https://blog.csdn.net/qq_41481924/article/details/85340787
初学链表,通过注解和理解完整的看懂了一篇,感觉还可以。
注:学习过程中也发现,链表中对头结点和尾节点的声名至关重要,未作声名则会不知链表地址,不能释放链表所占用的空间,导致程序越用越卡,特此注释,提醒自己!!