单链表结构体
#include "stdio.h"
#include "malloc.h"
#define TRUE 1
#define FALSE 0
typedef int ElemType; // 单链表存储元素的数据类型
// 定义单链表结构体
typedef struct Node(){
ElemType data; // 单链表结点数据域
struct Node *next; // 单链表结点地址域(指向下一个结点)
}*LinkList, Node;
复制代码
头插法构造单链表
代码实现
/*
* 头插法创建单链表(带头结点)
* datas 接收数组,用于赋值链表的结点数据
* len datas数组的长度,便于遍历
*/
LinkList CreateHeadListH(ElemType *datas, int len){
// 创建头结点
LinkList head, new_node;
head = (LinkList)malloc(sizeof(Node));
// head -> data = len; // 可以把链表长度存在头结点的数据域中
head -> next = NULL;
// 分配新节点并用头插法链接起来
for(int i=0;i<len;i++){
new_node = (LinkList)malloc(sizeof(Node));
new_node -> data = datas[i];
new_node -> next = head -> next;
head -> next = new_node;
}
return head;
}
复制代码
头插法过程
头插法往单链表头部插入,假设
datas[] = {2, 4, 6};
复制代码
首先创建头结点
分配第一个新节点时
head
结点的数据域为空 head -> data = NULL,
,地址域为空 head -> next = NULL;
new_code -> data = datas[0]; --> new_code -> data = 2;
new_code -> next = head -> next; --> new_code -> next = NULL;
复制代码
然后让 head
结点的地址域指向新结点(这里指第一个结点)
head -> next = new_code1;
复制代码
最终形成
分配第二个新结点时
head
结点的数据域为空 head -> data = NULL,
,地址域也为第一个结点的地址 head -> next = new_node1;
new_code -> data = datas[1]; --> new_code -> data = 4;
复制代码
让第二结点的地址域指向第一个结点(此时第一个结点位置存在 head
结点的地址域)
new_code -> next = head -> next; --> new_code -> next = new_code1;
复制代码
然后让 head
头结点的地址域指向第二个结点的位置
head -> next = new_code2;
复制代码
最终形成
分配第三个新结点后
关键代码
头插法每次插入新结点时都是往头结点处插入。
new_node -> next = head -> next; // 先让新结点地址域指向头结点地址域的结点位置
head -> next = new_node; // 然后让头结点的地址域指向新结点位置
复制代码
如此循环就形成了头插法构造单链表。
尾插法构造单链表
代码实现
/*
* 尾插法创建单链表(带头结点)
* datas 接收数组,用于赋值链表的结点数据
* len datas数组的长度,便于遍历
*/
LinkList CreateHeadListT(ElemType *datas, int len){
// 创建头结点
LinkList head, p, new_node;
head = (LinkList)malloc(sizeof(Node));
head -> next = NULL;
p = head;
// 分配新节点并用尾插法链接起来
for(int i=0;i<len;i++){
new_node = (LinkList)malloc(sizeof(Node));
new_node -> data = datas[i];
new_node -> next = NULL;
p -> next = new_node;
p = new_node;
}
return head;
}
复制代码
尾插法过程
尾插法往单链表尾部插入,还是假设单链表的结点数据分别为。
datas[] = {2, 4, 6};
复制代码
创建头结点跟头插法是一样的我就不重复叙述了。
分配第一个新结点时
head
结点的数据域为空 head -> data = NULL,
,地址域为空 head -> next = NULL;
变量p等于头结点 p = head;
。
先让新结点赋值
new_code -> data = datas[0]; --> new_code -> data = 2;
new_code -> next = NULL; --> new_code -> next = NULL
复制代码
后让链表链接起来
p -> next = new_code;
p = new_code;
复制代码
一开始 p = head
所以让头结点的地址域指向新结点,,后让 p
等于新结点(此时新结点代表第一个结点)。
分配第二个新结点时
head
结点的数据域为空 head -> data = NULL,
,地址域为空 head -> next = new_node1;
此时变量 p
就等于第一个结点,不再等于头结点。
继续让新结点与单链表链接起来
p -> next = new_code;
p = new_code;
复制代码
让第一个结点的地址域指向新结点(此时新结点代表第二个结点),让p等于第二个结点。
分配第三个新结点后
关键代码
p -> next = new_code; // 让p的地址域指向新结点
p = new_code; // 然后让p等于新插入进来的结点(一直等于最后一个结点)
复制代码
尾插法每次插入新结点时都是往尾结点处插入。
如此循环就形成了尾插法构造单链表。
单链表头尾插法对比
同样是数据 datas[] = {2, 4, 6, 8};
但链接的效果是不一致的,思想也不同。
头插法: head --> 8 --> 6 --> 4 --> 2
结点一直往 单链表头部插入,先进入的数据结点链接在末尾端(刚好逆序),有点像栈的特性,先进后出。
尾插法: head --> 2 --> 4 --> 6 --> 8
结点一直往 单链表尾部插入,先进入的数据结点还是在前驱。
源代码
源代码已上传到 GitHub Data-Structure-of-C,欢迎大家来访。
✍ 码字不易,万水千山总是情,点赞再走行不行,还望各位大侠多多支持❤️