一、链表是什么
链表是一种通过指针串联在一起的线性结构,在内存中是分散存储的(数组在内存中连续分布),链表由一系列节点组成,每个节点都由数据域和指针域组成。主要有三种类型的链表:
1、单链表(本章介绍内容)
2、双链表
3、循环链表
链表与数组对比:
插入/删除 时间复杂度 | 查询 时间复杂度 | 适用场景 | |
数组 | O(n) | O(1) | 内容固定,查询较为频繁 |
链表 | O(1) | O(n) | 内容不固定,较少查询 |
二、单链表定义
1、一个单链表的节点:
编辑
- 数据域data:存放数据的地方
- 指针域*next:指向下一个节点的地址
2、将节点链接起来,每个节点的*next指针指向下一节点,最后一个节点的指针指向NULL,就形成了单链表。
编辑
3、头指针的作用
设置一个头指针指向整条链表的首节点,这样对首节点的操作将和其余节点一致,无需使用两套处理逻辑。
三、节点结构体
typedef struct node {
int data; /**数据域*/
struct node *next; /**指向下一个节点*/
}list_node;
因为每个节点的数据结构都是一样的,都为struct node,所以指针域*next的类型也是struct node。
四、创建链表
list_node* list_init()
{
/**从内存动态申请 #1*/
list_node *head = (list_node *)malloc(sizeof(list_node));
/** #2*/
if(head == NULL) {
return NULL;
}
/**初始化头指针 #3*/
head->data = 0;
head->next = NULL; //链表暂无节点,指针赋为NULL
/** #4*/
return head;
}
1、malloc动态申请list_node大小(8个字节)的内存,作为链表的头指针;
2、if(head == NULL) 对malloc的返回值进行判断;
3、初始化头指针,头指针的数据域data没有什么作用,可以用来代表链表的节点数量;
4、返回头指针。
五、插入节点
int list_insert(list_node *head, int data, int pos/** #1*/)
{
list_node *p = head;
/**如果要插入的位置比链表长,则属于非法操作 #2*/
if (pos > p->data) {
return -1;
}
/**动态申请一个节点*/
list_node *node = (list_node *)malloc(sizeof(list_node));
if (node == NULL) {
return -1;
}
node->data = data;
node->next = NULL;
/**遍历链表,找到要插入的位置 #3*/
for (int i=0; i<pos; i++) {
p = p->next;
}
/**插入节点 #4*/
node->next = p->next;
p->next = node;
/**链表长度加1*/
head->data++;
return 0;
}
1、参数pos代表节点插入的位置,首节点的位置为0;
2、对插入位置进行判断,不能大于链表长度,异常返回-1;
3、遍历链表找到新节点要插在哪个节点之后,p指向这个节点;
4、如下图假设node4要插入到node1与node2之间,此时的p指针指向节点为node1,新创建的节点指针node指向node4;
node->next = p->next; 即为 node4->next=node1->next=node2
p->next = node; 即为 node1->next=node4
编辑
六、删除节点
int list_delete_node(list_node *head, int pos)
{
list_node *p = head;
/**删除的位置比链表长,则属于非法操作*/
if (pos > p->data) {
return -1;
}
/**遍历链表,找到要删除的节点的前一个节点的指针*/
for (int i=0; i<pos; i++) {
p = p->next;
}
/**记录将被删除的节点, 用于最后释放该节点内存 #1*/
list_node *p2 = p->next;
/**跳过被删除的节点,释放内存,完成删除 #2*/
p->next = p->next->next;
free(p2);
head->data--;
return 0;
}
1、被删除的节点的内存需要进行释放,避免内存泄漏;
2、如下图,假设要删除node2,则只需直接将node1的next指针指向node3
七、测试
目录结构
./
├── build //编译目录
├── CMakeLists.txt //cmake 配置文件
├── list_01.c //源码
├── list_01.h
└── test.c //测试文件
工程采用cmake构建,文件均经过测试,编译步骤如下:
1、mkdir build && cd build
2、cmake ../ && make
3、./list_test
源码路径在公众号(Linux杂记)同标题的文章里哈!!
标签:node,10,--,list,C语言,链表,next,节点,指针 From: https://www.cnblogs.com/linux-misc/p/16654317.html