前面的文章我们就一直说,学一个新东西之前一定要弄明白它的作用是什么,我们为什么要用它。之前讲C语言时我们讲到数组,数组的实质是一种顺序储存、随机访问、存储单元连续的线性表,既然存储单元连续,那么对其进行插入和删除操作时需要移动大量的数组元素,这时我们便需要用到链表。
链表是由结构体和指针配合使用构成的一种动态数据结构(大家要是对C语言的指针和结构体不熟练的话可以去看看我之前的文章—嵌入式开发之C语言基础五(指针详解)和嵌入式开发之C语言基础七(结构体详解)),实质是链式存储、顺序访问的线性表,用一组任意的存储单元来存储线性表中的数据,存储单元不一定是连续的。
链表中的每个元素称为一个节点,每个节点都可以存储在内存中的不同位置,每个节点都包括两部分:第一部分为数据域,用于存储元素本身的数据信息;第二部分为指针域,其是结构体指针,用于存储其直接后继的节点信息。
创建节点和链表
创建一个结构体,其成员包括用户数据即data和用于指向下一个结构体的结构体指针*next,这里我们所说的结构体就是节点,在main函数里我们对其data进行了赋值,对next进行了下一个节点的指向,这样一个节点就创建了,通过next给链接在了一起形成了链表。
再通过打印函数把链表打印出来:
既然有了链表,那么我们就可以对其进行增删查改等一系列操作:
获得节点数
上面这段代码就获得一个链表中的节点数,逻辑应该很简单,当p != NULL时就一直遍历,同时count一直++。
查询节点
上面这段代码就是查询一个链表中是否有某个节点,逻辑也很简单,一直遍历,同时一直与要查询的data进行判断。
从某个节点后面插入新节点
实现插入节点功能重点就在于能否把新节点与旧节点进行链接,上面代码的实现逻辑就是:找到要被插入的节点后将其指向后一个节点的结构体指针指向要插入节点,要插入的节点再将其指向后一个节点的结构体指针指向被插入的节点原本指向的下一个的节点。这里看代码比看文字讲解要容易理解一点,大家可以多看看代码。
从某个节点前面插入新节点
从某个节点前面插入新节点比从后面插入要多进行一次判断,判断是否为头节点,另一个要注意的地方就是while里的判断条件是用p->next来判断的,这是因为我们可以通过p来找到p的后一个,但是找不到p的前一个,所以这里我们灵活变换一下,代码实现逻辑和从后面插入大同小异。
删除节点
删除一个节点实现逻辑也很好理解,肯定也是要不断遍历,找到对应节点后把原本指向它的结构体指针指向它的下一个,然后按道理我们要把它free掉,但是经过测试和查找资料发现只有是malloc出来的空间才能使用free,不然运行会出现段错误。
从头插入节点
这段代码实现了从头节点开始插入新节点,所以这样出来的链表中节点的顺序要注意一下:第一个插入的节点是尾节点。我们分析这段代码可以看到只有我们不输入0就可以不断创建新节点,而且把每个新malloc出来的新节点的next指向上一个malloc出来的节点,这里要注意每次malloc一个新节点一定要把其next指向NULL,因为我之前是在虚拟机里写得代码,会默认malloc后节点的next会指向NULL,这也导致我把代码拷贝到windows中的编译器中运行会出现错误。
创建链表(头插法)
大家仔细看代码就可以发现这个所谓的创建链表就是把上段代码给拆分了,在函数creatLink中调用函数insertFromHead,当然这一定程度上是为了代码的实用性。
创建链表(尾插法)
上面的代码就是实现尾插法创建链表,这种方式创建出链表中节点的顺序也就是我们正常所认为的顺序,最先的就是头。和头插法不一样的是尾插法要先遍历的最后一个节点,再用最后一个节点的next指向新创建的节点 。
以上就是数据结构中关于链表的基础知识,希望大家自己也去实现一下这几个链表功能,整个代码我会放到下面,最后希望大家学业有成,共勉。
#include #include struct Test{int data;struct Test *next;};void print_Link(struct Test *head){struct Test *p = head;while(p != NULL){printf("%d ",p->data);p = p->next;}printf("\n");}int getNodeNum(struct Test *head){int count = 0;struct Test *p = head;while(p != NULL){count++;p = p->next;}return count;}int searchLink(struct Test *head,int data){struct Test *p = head;while(p != NULL){if (p->data == data){return (p->data);}p = p->next;}printf("not found\n");return 0;}struct Test* insertOneBehind(struct Test *head,int data,struct Test *new){struct Test *p = head;while(p != NULL){if (p->data == data){new->next = p->next;p->next = new;printf("insert ok!\n");return head;}p = p->next;}printf("insert fail\n");return head;}struct Test* insertOneFore(struct Test *head,int data,struct Test *new){struct Test *p = head;if (p->data == data){new->next = p;printf("insert ok!\n");return new;}while(p->next != NULL){if (p->next->data == data){new->next = p->next;p->next = new;printf("insert ok!\n");return head;}p = p->next;}printf("insert fail\n");return head;}struct Test* deletNode(struct Test *head,int data){struct Test *p = head;if (p->data == data){head = head->next;free(p);printf("delet ok!\n");return head;}while(p->next != NULL){if (p->next->data == data){//free(p->next);p->next = p->next->next;printf("delet ok!\n");return head;}p = p->next;}printf("delet fail\n");return head;}/*struct Test* insertFromHead(struct Test *head){struct Test *new;while(1){new = (struct Test*)malloc(sizeof(struct Test));new->next = NULL;printf("please input data:\n");scanf("%d",&(new->data));if (new->data == 0){printf("quit input\n");return head;}if (head == NULL){head = new;}else{new->next = head;head = new;}}return head;}*/struct Test* insertFromHead(struct Test *head,struct Test *new){if (head == NULL){head = new;}else{new->next = head;head = new;}return head;}struct Test* creatLink(struct Test *head){struct Test *new;while(1){new = (struct Test*)malloc(sizeof(struct Test));/**/new->next = NULL;printf("please input data:\n");scanf("%d",&(new->data));if (new->data == 0){printf("quit input\n");free(new);return head;}head = insertFromHead(head,new);}return head;}struct Test* insertFromTail(struct Test *head,struct Test *new){struct Test *p = head;if (p == NULL){p = new;return p;}while(p->next != NULL){p = p->next;}p->next = new;return head;}struct Test* creatLink2(struct Test *head){struct Test *new;while(1){new = (struct Test*)malloc(sizeof(struct Test));/**/new->next = NULL;printf("please input data:\n");scanf("%d",&(new->data));if (new->data == 0){printf("quit input\n");free(new);return head;}head = insertFromTail(head,new);}return head;}int main(){int i;int Count;int Data;int arr[3] = {1,2,3};int size = sizeof(arr)/sizeof(arr[0]); for (i = 0;i next = &t2;p->data = 1;///*1*/t1.next = &t2;t2.next = &t3;struct Test new1 = {1000,NULL};struct Test new2 = {100,NULL};struct Test *new3 = (struct Test*)malloc(sizeof(struct Test));new3->next = NULL;new3->data = 200; struct Test *head = p;struct Test *head2 =NULL;/*1printf("link mode:\n");printf("%d %d %d\n",t1.data,t1.next->data,t1.next->next->data);print_Link(&t1);Count = getNodeNum(&t1);printf("%d\n",Count);Data = searchLink(&t1,2);printf("%d\n",Data);1*//*2head = insertOneBehind(head,1,&new1);print_Link(head);head = insertOneFore(head,3,&new2);print_Link(head);head = deletNode(head,1);print_Link(head);2*//*3head = insertFromHead(head);//使用3功能时,把上面注释代码的注释给去掉print_Link(head);3*//*4head2 = creatLink(head2);print_Link(head2);4*//*5head2 = insertFromTail(head2,new3);print_Link(head2);5*//*6head2 = creatLink2(head2);print_Link(head2);6*/return 0;}