单链表创建的两种方式
导语:在前面的博客中我们分别介绍了单链表的反转实现以及单链表插入的实现,都是基于单链表创建之后的操作,本片博客将介绍如何创建单链表或者说是单链表创建的两种方式。
创建单链表
单链表就是一种特殊的结构体组合而成的数据结构,关于单链表的创建方式有很多种,大同小异。在这里我们将详细的介绍一下头插法创建链表和尾插法创建链表。
如上所示单链表就是由可能不连续的数据所组合而成的数据结构。 其中每个数据分为两部分,一部分是数据存储的位置,称为数据域(data),另外指针所存储的地方,称为指针域。
typedef struct Node{
int data;//存储数据域
struct Node *next;//存储指针域
}LNode,*LinkedList
头插法创建链表
思路:从一个空表开始,重复读入数据,生成新结点,将所读入数据存储到新结点的数据域中,然后在将新结点插入到当前链表的表头结点之后。
代码:
Linkedlist Create_list(LinkedList head){
head = (Linkedlist)malloc(sizeof(Lnode));//为头指针开辟内存空间
Lnode *node = null;//定义新结点
int count = 0;//创建结点个数
head->next = null;
node = head->hext;//将最后一个结点的指针域保持为null
printf("输入结点个数:");
scanf("%d",&count);
for(int i=0;i<count;i++){
node = (Linkedlist)malloc(sizeof(Lnode));//为新结点开辟空间
node->data = i;//为新结点的数据域赋值
node->next = head->next;//将头指针指向下一个结点的地址赋给新创建的结点的next
head->next = node;//将头指针指向新创建的结点
}
return head;
}
//核心代码
node->data = i;//为新结点的数据域赋值
node->next = head->next;//将头指针指向下一个结点的地址赋给新创建的结点的next
head->next = node;//将头指针指向新创建的结点
图解:
假设将A->B依次插入
文解:
创建第一个结点:第一次从堆中开辟一块内存空间给node,将head与第一个结点连接起来,之前说过head指向的是null;
插入第一个结点时,将头指针指向的next赋给新创建结点的next,这样插入第一个结点的next就是null;
接着将数据域node地址赋给head->next,也就是说head->next指向的是新创建的结点,然后新创建结点node->next指向null
创建第二个结点:因为使用头插法,所以新开辟的内存空间需要插入头指针指向的下一个地址;
我们申请到新的一块存储区域后,需要将 node->next 指向上一个结点的首地址,而新node的地址则赋给 head->next,也就是node->next = head->next;
接下来再将头结点的next所指向的地址赋为新创建node的地址,也就是head->next = node,此时最后一个结点,也就是第一次创建的结点的指针域为 NULL
尾插法创建链表
思路:将新结点插到当前单链表的表尾上,增加尾指针,使之指向当前单链表的表尾
代码:
Linklist Creat_list(Linklist head) {
head = (Linklist)malloc(sizeof(Lnode)); // 为头指针开辟内存空间
Linklist node = NULL; // 定义结点
Linklist end = NULL; // 定义尾结点
head->next = NULL; // 初始化头结点指向的下一个地址为 NULL
end = head; // 未创建其余结点之前,只有一个头结点
int count = 0 ; // 结点个数
printf("请输入结点个数: ");
scanf("%d", &count);
for (int i = 0; i < count; i++) {
node = (Linklist)malloc(sizeof(Lnode)); // 为新结点开辟新内存
node->data = i; // 新结点的数据域赋值
end->next = node;
end = node;
}
end->next = NULL;
}
//核心代码
end->next = node;
end = node;
图解:
假设依次A->B插入,end为尾指针
文解:
创建第一个结点:刚开始为头结点开辟内存空间,因为此时除过头结点没有新的结点的建立,接着将头结点的指针域 head->next 的地址赋为 NULL。
因此,整个链表只有一个头结点有效,因此 head此时既是头结点,又是尾结点。所以将头结点的地址赋给尾结点 end 因此:end = head。
此时end 就是 head, head 就是 end。 end->next 也自然指向的是 NULL
创建第二个结点: 第一个结点,end 和 head 共用一块内存空间。现在从堆中心开辟出一块内存给 node,将 node 的数据域赋值后,此时 end 中存储的地址是 head 的地址;
此时,end->next 代表的是头结点的指针域,因此 end->next = node 代表的就是新开辟的 node 的地址赋给 head 的下一个结点地址;
此时,end->next 的地址是新创建的 node 的地址,而此时 end 的地址还是 head 的地址;因此 end = node ,这条作用就是将新建的结点 node 的地址赋给尾结点 end。 此时 end 的地址不再是头结点,而是新建的结点 node。
结语:你懂了吗?