一、链表的基础知识
链表是C语言中比较常用的一种数据结构,相对与上几篇文章的队列结构来说,链表是在一种物理存储单元上非连续、非顺序的存储结构。链表中的每个节点都是通过链表中的指针链接次序实现的;一般来说每个节点都会包含以下两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
链表又会分成很多个类型:单线链表,单向循环链表,双向链表,双向循环链表等;
这篇文章我们主要聊聊单向链表,单向链表又分为以下两种类型:
- 无头节点链表:无头节点链表表示的是头节点中是没有数据域的,只包含了指针域
- 有头节点链表:有头节点链表表示的是头节点中既有指针域也有数据域
二、单向链表的常用接口
- 链表的创建
- 链表的插入:头插和尾插
- 链表节点的删除
- 链表的销毁
- 链表的遍历
- …
三、单向链表的实现
1、无头节点的单向链表
链表的数据定义
typedef struct {
uint8_t id;
} USER_DATA_T;
typedef struct list{
struct list *next;
USER_DATA_T data;
} LIST_T;
LIST_T *head_list = NULL; //链表头节点指针
链表的创建
// 创建链表
int list_creat(void)
{
if (NULL == head_list) {
head_list = (LIST_T *)malloc(sizeof(LIST_T));
if (NULL == head_list) {
return -1;
}
head_list->next = NULL;
}
return 0;
}
链表的插入:头插和尾插
//链表的头插,在头节点后面插入数据
int list_inset_head(USER_DATA_T *data)
{
if (NULL == head_list) {
if (list_creat() != 0) {
return -1;
}
}
LIST_T *p_node = (LIST_T *)malloc(sizeof(LIST_T));
memset(p_node, 0, sizeof(LIST_T));
memcpy(&p_node->data, data, sizeof(USER_DATA_T));
p_node->next = head_list->next;
head_list->next = (struct list *)p_node;
return 0;
}
//链表的尾插,在最后节点插入数据
int list_inset_tail(USER_DATA_T *data)
{
if (NULL == head_list) {
if (list_creat() != 0) {
return -1;
}
}
//创建节点数据
LIST_T *p_node = (LIST_T *)malloc(sizeof(LIST_T));
memset(p_node, 0, sizeof(LIST_T));
memcpy(&p_node->data, data, sizeof(USER_DATA_T));
p_node->next = NULL;
LIST_T *p_list = head_list;
while (p_list) {
if (p_list->next) {
p_list = (LIST_T *)p_list->next;
continue;
}
p_list->next = (struct list *)p_node;
return 0;
}
}
链表的删除:根据数据内容或者节点序号
// 根据数据内容删除节点
void list_node_del_by_data(USER_DATA_T *data)
{
if (NULL == head_list) {
return;
}
LIST_T *p_list = (LIST_T *)head_list;
LIST_T *q = NULL;
while (p_list->next) {
if (0 == memcmp(data, &p_list->next->data, sizeof(USER_DATA_T))) {
q = (LIST_T *)p_list->next;
p_list->next = q->next;
free(q);
q = NULL;
}
p_list = (LIST_T *)p_list->next;
}
}
// 根据节点编号删除节点:头节点为0,数据节点从1开始
void list_node_del_by_index(uint8_t index)
{
if ((NULL == head_list) || (0 == index)) {
return;
}
uint8_t cnt = 1;
LIST_T *q = NULL;
LIST_T *p_list = (LIST_T *)head_list;
while (p_list) {
if (cnt == index) {
q = p_list->next;
p_list->next = q->next;
free(q);
q = NULL;
return;
}
p_list = (LIST_T *)p_list->next;
cnt++;
}
}
链表的销毁
//链表销毁
int list_destory(void)
{
if (NULL == head_list) {
return -1;
}
LIST_T *p_list = NULL, *q = NULL;
for (p_list = head_list->next; p_list != NULL; p_list = q) {
q = p_list->next;
free(p_list);
}
free(head_list);
return 0;
}
链表的遍历
//遍历链表
void list_traverse(void)
{
if ((NULL == head_list) || (NULL == head_list->next)) {
return;
}
LIST_T *p_node = (LIST_T *)head_list->next;
while (p_node) {
printf("node data:%d\r\n", p_node->data);
p_node = (LIST_T *)p_node->next;
}
}
2、有头节点的单向链表
链表的创建
// 创建链表
int list_creat(USER_DATA_T *data)
{
if (NULL == head_list) {
head_list = (LIST_T *)malloc(sizeof(LIST_T));
if (NULL == head_list) {
return -1;
}
memcpy(&head_list->data, data, sizeof(USER_DATA_T));
head_list->next = NULL;
}
return 0;
}
链表的插入:头插和尾插
//链表的头插,在头节点前面插入数据
int list_inset_head(USER_DATA_T *data)
{
if (NULL == head_list) {
return -1;
}
LIST_T *p_node = (LIST_T *)malloc(sizeof(LIST_T));
memset(p_node, 0, sizeof(LIST_T));
memcpy(&p_node->data, data, sizeof(USER_DATA_T));
p_node->next = head_list;
head_list = p_node;
return 0;
}
//链表的尾插,在最后节点插入数据
int list_inset_tail(USER_DATA_T *data)
{
if (NULL == head_list) {
return -1;
}
//创建节点数据
LIST_T *p_node = (LIST_T *)malloc(sizeof(LIST_T));
memset(p_node, 0, sizeof(LIST_T));
memcpy(&p_node->data, data, sizeof(USER_DATA_T));
p_node->next = NULL;
LIST_T *p_list = head_list;
while (p_list) {
if (p_list->next) {
p_list = (LIST_T *)p_list->next;
continue;
}
p_list->next = (struct list *)p_node;
return 0;
}
}
链表节点的删除:根据数据或者节点序号删除
// 根据数据内容删除节点
void list_node_del_by_data(USER_DATA_T *data)
{
if (NULL == head_list) {
return;
}
LIST_T *p_list = (LIST_T *)head_list;
LIST_T *q = NULL;
while (p_list) {
if (0 == memcmp(data, &p_list->data, sizeof(USER_DATA_T))) {
if (p_list == head_list) {
q = head_list;
head_list = head_list->next;
free(q);
q = NULL;
p_list = head_list;
} else {
q->next = p_list->next;
free(p_list);
p_list = NULL;
q = (LIST_T *)q->next;
}
continue;
}
q = p_list;
p_list = (LIST_T *)p_list->next;
}
}
// 根据节点编号删除节点:头节点为0
void list_node_del_by_index(uint8_t index)
{
if (NULL == head_list) {
return;
}
uint8_t cnt = 0;
LIST_T *q = NULL;
LIST_T *p_list = (LIST_T *)head_list;
while (p_list) {
if (cnt == index) {
if (0 == index) {
q = head_list;
head_list = head_list->next;
free(q);
q = NULL;
} else {
q->next = p_list->next;
free(p_list);
p_list = NULL;
}
return;
}
q = p_list;
p_list = (LIST_T *)p_list->next;
cnt++;
}
}
链表节点的查找
// 根据数据内容查找节点
LIST_T *list_node_find(USER_DATA_T *data)
{
if (NULL == head_list) {
return;
}
LIST_T *p_list = (LIST_T *)head_list;
while (p_list) {
if (0 == memcmp(data, &p_list->data, sizeof(USER_DATA_T))) {
return p_list;
}
p_list = (LIST_T *)p_list->next;
}
}
3、demo程序
demo测试代码
int main(void)
{
USER_DATA_T data = {0};
list_creat();
data.id = 3;
list_inset_head(&data);
data.id = 2;
list_inset_head(&data);
data.id = 4;
list_inset_tail(&data);
data.id = 5;
list_inset_tail(&data);
data.id = 1;
list_inset_head(&data);
data.id = 3;
list_inset_head(&data);
data.id = 3;
list_node_del_by_data(&data);
list_node_del_by_index(3);
list_traverse();
list_destory();
list_traverse();
return 0;
}