1.链表操作
1.1普通链表操作
#include "usart.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct person {
char *name;
int age;
struct person *couple;
};
struct person w;
struct person h;
int main(int argc, char **arg)
{
HAL_Init();
MX_USART1_UART_Init();
w.name = "w";
w.age = 30;
w.couple = &h;
h.name = "h";
h.age = 30;
h.couple = &w;
printf("w's couple is %s\r\n", w.couple->name);
while(1)
{
}
}
/*
w's couple is h
*/
#include "usart.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct person {
char *name;
int age;
struct person *next;
};
struct list {
char *name; /* A班 */
struct person *next;
};
int main(int argc, char **arg)
{
struct list a_list;
struct person p1;
a_list.name = "A";
a_list.next = NULL; /* 空链表 */
p1.name = "a1";
p1.next = NULL;
a_list.next = &p1;
printf("a list: %s\r\n", a_list.next->name);
while(1)
{
}
}
/*
a list: a1
*/
1.2普通链表的创建和添加操作
1.3普通链表的删除操作
1.4普通链表的排序
#include "usart.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct person {
char *name;
int age;
struct person *next;
};
struct list {
char *name; /* A班 */
struct person *next;
};
void InitList(struct list *pList, char *name)
{
pList->name = name;
pList->next = NULL;
}
void AddItemToList(struct list *pList, struct person *new_person)
{
struct person *last;
/* 如果是空链表 */
if (pList->next == NULL)
{
pList->next = new_person;
new_person->next =NULL;
return;
}
last = pList->next;
while (last->next)
{
last = last->next;
}
/* last->next == NULL */
last->next = new_person;
new_person->next =NULL;
}
void DelItemFromList(struct list *pList, struct person *person)
{
struct person *p = pList->next;
struct person *pre = NULL;
/* 找到person */
while (p != NULL && p != person)
{
/* 后面还有人, 移动到下一个 */
pre = p;
p = p->next;
}
/* 退出的条件: p==NULL, p == person */
if (p == NULL)
{
printf("can not find the person to del\r\n");
return;
}
if (pre == NULL) /* 前面无人, 表示要删除的是第1项 */
{
pList->next = p->next;
}
else
{
pre->next = p->next;
}
}
void SortList(struct list *pList)
{
struct person *pre;
struct person *next;
char *tmp_name;
int tmp_age;
pre = pList->next;
if (pre == NULL)
return;
while (pre)
{
next = pre->next;
while (next)
{
if (pre->age > next->age)
{
/* 交换值 */
tmp_name = pre->name;
pre->name = next->name;
next->name = tmp_name;
tmp_age = pre->age;
pre->age = next->age;
next->age = tmp_age;
}
next = next->next;
}
pre = pre->next;
}
}
void PrintList(struct list *pList)
{
int i = 0;
struct person *p = pList->next;
while (p != NULL)
{
printf("person %d: %s is %d\r\n", i++, p->name, p->age);
/* 后面还有人, 移动到下一个 */
p = p->next;
}
}
int main(int argc, char **arg)
{
struct list a_list;
int i;
struct person p[] = {
{"p1", 10, NULL},
{"p2", 20, NULL},
{"p3", 13, NULL},
{"p4", 41, NULL},
{"p5", 56, NULL},
{"p6", 12, NULL},
{"p7", 9, NULL},
{"p8", 21, NULL},
{NULL, 0, NULL},
};
HAL_Init();
MX_USART1_UART_Init();
InitList(&a_list, "A_class");
i = 0;
while (p[i].name != NULL)
{
AddItemToList(&a_list, &p[i]);
i++;
}
printf("add all person:\r\n");
PrintList(&a_list);
DelItemFromList(&a_list, &p[3]);
printf("del person %s:\r\n", p[3].name);
PrintList(&a_list);
DelItemFromList(&a_list, &p[0]);
printf("del person %s:\r\n", p[0].name);
PrintList(&a_list);
SortList(&a_list);
printf("sort list, all person:\r\n");
PrintList(&a_list);
while(1)
{
}
}
void Error_Handler(void)
{
printf("Error\r\n");
while(1)
{
}
}
/*
add all person:
person 0: p1 is 10
person 1: p2 is 20
person 2: p3 is 13
person 3: p4 is 41
person 4: p5 is 56
person 5: p6 is 12
person 6: p7 is 9
person 7: p8 is 21
del person p4:
person 0: p1 is 10
person 1: p2 is 20
person 2: p3 is 13
person 3: p5 is 56
person 4: p6 is 12
person 5: p7 is 9
person 6: p8 is 21
del person p1:
person 0: p2 is 20
person 1: p3 is 13
person 2: p5 is 56
person 3: p6 is 12
person 4: p7 is 9
person 5: p8 is 21
sort list, all person:
person 0: p7 is 9
person 1: p6 is 12
person 2: p3 is 13
person 3: p2 is 20
person 4: p8 is 21
person 5: p5 is 56
*/
1.5普通链表的改进
#include "usart.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct person {
char *name;
int age;
struct person *next;
};
struct list {
char *name; /* A班 */
struct person head;
};
void InitList(struct list *pList, char *name)
{
pList->name = name;
pList->head.next = NULL;
}
void AddItemToList(struct list *pList, struct person *new_person)
{
struct person *last = &pList->head;
while (last->next)
{
last = last->next;
}
/* last->next == NULL */
last->next = new_person;
new_person->next =NULL;
}
void AddItemAfter(struct person *pre, struct person *new_person)
{
new_person->next = pre->next;
pre->next = new_person;
}
void DelItemFromList(struct list *pList, struct person *person)
{
struct person *pre = &pList->head;
/* 找到person */
while (pre != NULL && pre->next != person)
{
pre = pre->next;
}
/* 没找到 */
if (pre == NULL)
return;
else
pre->next = person->next;
}
void SortList(struct list *pList)
{
struct person *pre1 = &pList->head;
struct person *pre2;
struct person *cur = pre1->next;
struct person *next;
struct person *tmp;
while (cur)
{
pre2 = cur;
next = cur->next;
while (next)
{
if (cur->age > next->age)
{
/* 交换节点 */
/* 1. del cur */
DelItemFromList(pList, cur);
/* 2. del next */
DelItemFromList(pList, next);
/* 3. 在pre1之后插入next */
AddItemAfter(pre1, next);
/* 4. 在pre2之后插入cur */
if (pre2 == cur)
AddItemAfter(next, cur);
else
AddItemAfter(pre2, cur);
/* 5. cur/next指针互换 */
tmp = cur;
cur = next;
next = tmp;
}
pre2 = next;
next = next->next;
}
pre1 = cur;
cur = cur->next;
}
}
void PrintList(struct list *pList)
{
int i = 0;
struct person *p = pList->head.next;
while (p != NULL)
{
printf("person %d: %s is %d\r\n", i++, p->name, p->age);
/* 后面还有人, 移动到下一个 */
p = p->next;
}
}
int main(int argc, char **arg)
{
struct list a_list;
int i;
struct person p[] = {
{"p1", 10, NULL},
{"p2", 20, NULL},
{"p3", 13, NULL},
{"p4", 41, NULL},
{"p5", 56, NULL},
{"p6", 12, NULL},
{"p7", 9, NULL},
{"p8", 21, NULL},
{NULL, 0, NULL},
};
HAL_Init();
MX_USART1_UART_Init();
InitList(&a_list, "A_class");
i = 0;
while (p[i].name != NULL)
{
AddItemToList(&a_list, &p[i]);
i++;
}
printf("add all person:\r\n");
PrintList(&a_list);
DelItemFromList(&a_list, &p[3]);
printf("del person %s:\r\n", p[3].name);
PrintList(&a_list);
DelItemFromList(&a_list, &p[0]);
printf("del person %s:\r\n", p[0].name);
PrintList(&a_list);
SortList(&a_list);
printf("sort list, all person:\r\n");
PrintList(&a_list);
while(1)
{
}
}
void Error_Handler(void)
{
printf("Error\r\n");
while(1)
{
}
}
/*
add all person:
person 0: p1 is 10
person 1: p2 is 20
person 2: p3 is 13
person 3: p4 is 41
person 4: p5 is 56
person 5: p6 is 12
person 6: p7 is 9
person 7: p8 is 21
del person p4:
person 0: p1 is 10
person 1: p2 is 20
person 2: p3 is 13
person 3: p5 is 56
person 4: p6 is 12
person 5: p7 is 9
person 6: p8 is 21
del person p1:
person 0: p2 is 20
person 1: p3 is 13
person 2: p5 is 56
person 3: p6 is 12
person 4: p7 is 9
person 5: p8 is 21
sort list, all person:
person 0: p7 is 9
person 1: p6 is 12
person 2: p3 is 13
person 3: p2 is 20
person 4: p8 is 21
person 5: p5 is 56
*/
1.5.1普通链表为什么要改进 ?
没改之前,pre的头是list,p1的头是person,两个头不一样。
改进之后, pre的头是person,p1的头也是person,两个头是一致的,方便后期统一操作。
看代码,找区别!
没改之前
/*没改之前,主要区别是struct list结构体中的*next指针*/
/*InitList函数,pList->head = NULL; pList的头是list结构体*/
struct person {
char *name;
int age;
struct person *next;
};
struct list {
char *name; /* A班 */
struct person *next;
};
void InitList(struct list *pList, char *name)
{
pList->name = name;
pList->next = NULL;
}
改进之后
/*改进之后,主要区别是struct list结构体中的next指针*/
/*InitList函数,pList->head.next = NULL; pList的头是person结构体*/
struct person {
char *name;
int age;
struct person *next;
};
struct list {
char *name; /* A班 */
struct person head;
};
void InitList(struct list *pList, char *name)
{
pList->name = name;
pList->head.next = NULL;
}
1.6通用链表
#include "usart.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node_t {
struct node_t *next;
};
struct person {
char *name;
int age;
struct node_t node;
};
struct list {
char *name; /* A班 */
struct node_t head;
};
void InitList(struct list *pList, char *name)
{
pList->name = name;
pList->head.next = NULL;
}
void AddItemToList(struct list *pList, struct node_t *new_node)
{
struct node_t *last = &pList->head;
while (last->next)
{
last = last->next;
}
/* last->next == NULL */
last->next = new_node;
new_node->next =NULL;
}
void AddItemAfter(struct node_t *pre, struct node_t *new_node)
{
new_node->next = pre->next;
pre->next = new_node;
}
void DelItemFromList(struct list *pList, struct node_t *node)
{
struct node_t *pre = &pList->head;
/* 找到node */
while (pre != NULL && pre->next != node)
{
pre = pre->next;
}
/* 没找到 */
if (pre == NULL)
return;
else
pre->next = node->next;
}
int CmpPersonAge(struct node_t *pre, struct node_t *next)
{
struct person *p;
struct person *n;
p = (struct person *)((char *)pre - (unsigned int)&((struct person *)0)->node);
n = (struct person *)((char *)next - (unsigned int)&((struct person *)0)->node);
if (p->age < n->age)
return -1;
else
return 0;
}
void SortList(struct list *pList)
{
struct node_t *pre1 = &pList->head;
struct node_t *pre2;
struct node_t *cur = pre1->next;
struct node_t *next;
struct node_t *tmp;
while (cur)
{
pre2 = cur;
next = cur->next;
while (next)
{
if (CmpPersonAge(cur, next) == 0)
{
/* 交换节点 */
/* 1. del cur */
DelItemFromList(pList, cur);
/* 2. del next */
DelItemFromList(pList, next);
/* 3. 在pre1之后插入next */
AddItemAfter(pre1, next);
/* 4. 在pre2之后插入cur */
if (pre2 == cur)
AddItemAfter(next, cur);
else
AddItemAfter(pre2, cur);
/* 5. cur/next指针互换 */
tmp = cur;
cur = next;
next = tmp;
}
pre2 = next;
next = next->next;
}
pre1 = cur;
cur = cur->next;
}
}
void PrintList(struct list *pList)
{
int i = 0;
struct node_t *node = pList->head.next;
struct person *p;
while (node != NULL)
{
p = (struct person *)((char *)node - (unsigned int)&((struct person *)0)->node);;
printf("person %d: %s is %d\r\n", i++, p->name, p->age);
/* 后面还有人, 移动到下一个 */
node = node->next;
}
}
int main(int argc, char **arg)
{
struct list a_list;
int i;
struct person p[] = {
// {"p1", 10, {NULL}},
// {"p2", 20, {NULL}},
// {"p3", 13, {NULL}},
// {"p4", 41, {NULL}},
// {"p5", 56, {NULL}},
// {"p6", 12, {NULL}},
// {"p7", 9, {NULL}},
// {"p8", 21, {NULL}},
// {"p9", 22, {NULL}},
// {"p10", 21, {NULL}},
// {"p11", 20, {NULL}},
// {NULL, 0, {NULL}},
{"p1", 10, NULL},
{"p2", 20, NULL},
{"p3", 13, NULL},
{"p4", 41, NULL},
{"p5", 56, NULL},
{"p6", 12, NULL},
{"p7", 9, NULL},
{"p8", 21, NULL},
{"p9", 22, NULL},
{"p10", 21, NULL},
{"p11", 20, NULL},
{NULL, 0, NULL},
};
HAL_Init();
MX_USART1_UART_Init();
InitList(&a_list, "A_class");
i = 0;
while (p[i].name != NULL)
{
AddItemToList(&a_list, &p[i].node);
i++;
}
printf("add all person:\r\n");
PrintList(&a_list);
DelItemFromList(&a_list, &p[3].node);
printf("del person %s:\r\n", p[3].name);
PrintList(&a_list);
DelItemFromList(&a_list, &p[0].node);
printf("del person %s:\r\n", p[0].name);
PrintList(&a_list);
SortList(&a_list);
printf("sort list, all person:\r\n");
PrintList(&a_list);
while(1)
{
}
}
void Error_Handler(void)
{
printf("Error\r\n");
while(1)
{
}
}
/*
add all person:
person 0: p1 is 10
person 1: p2 is 20
person 2: p3 is 13
person 3: p4 is 41
person 4: p5 is 56
person 5: p6 is 12
person 6: p7 is 9
person 7: p8 is 21
person 8: p9 is 22
person 9: p10 is 21
person 10: p11 is 20
del person p4:
person 0: p1 is 10
person 1: p2 is 20
person 2: p3 is 13
person 3: p5 is 56
person 4: p6 is 12
person 5: p7 is 9
person 6: p8 is 21
person 7: p9 is 22
person 8: p10 is 21
person 9: p11 is 20
del person p1:
person 0: p2 is 20
person 1: p3 is 13
person 2: p5 is 56
person 3: p6 is 12
person 4: p7 is 9
person 5: p8 is 21
person 6: p9 is 22
person 7: p10 is 21
person 8: p11 is 20
sort list, all person:
person 0: p7 is 9
person 1: p6 is 12
person 2: p3 is 13
person 3: p11 is 20
person 4: p2 is 20
person 5: p10 is 21
person 6: p8 is 21
person 7: p9 is 22
person 8: p5 is 56
*/
1.6.1普通链表与通用链表的比较
普通链表
普通链表的缺点
AddItemToList函数的第二个参数是person结构体,如果后面要加入Dog结构体,或者加入Bird结构体,AddItemToList函数就不够通用,此时需要对Dog,Bird重写加入链表的函数,所以需要修改AddItemToList函数,使其更加通用。
通用链表
此时在链表头里面加入struct node_t head;让head存放next指向p1的node,p1的node存放next指向p2......依次类推。
这样做的好处就是:后面有Dog、Bird结构体时,链表头不需要改动,链表添加函数也不需要改动,只需要定义出Dog结构体就可以了,后面的添加链表函数通用。
struct Dog {
char *name;
int age;
struct node_t node;
}
使用结构体的0地址偏移,找到结构体的首地址。
1.7通用链表的三种实现方式
1. 引入概念container
struct person {
struct node_t node;
char *name;
int age;
};
struct dog {
struct node_t node;
char *name;
int age;
char *class;
};
person里含有node,person就是node的"容器"、"container"。
dog里含有node,dog就是node的"容器"、"container"。
核心在于:怎么根据node找到container。
方法1
结构体中,node一定放在container中最前面:
struct person {
struct node_t node;
char *name;
int age;
};
struct dog {
struct node_t node;
char *name;
int age;
char *class;
};
方法2
结构体中,根据node反算出container位置:适用于Linux,RT-Threah
struct person {
char *name;
int age;
struct node_t node;
char *address;
};
struct dog {
char *name;
int age;
char *class;
struct node_t node;
};
方法3
node中,保存container地址:适用于FreeRTOS
struct node_t {
void *container;
struct node_t *next;
};
1.8双向链表
1.结构图
2.判断尾部
上如中,person3是链表中最后一个链表项,它的下一个person是head:
person3.node.next == &list.head
3. 怎么插入新项
new_node->pre = left_node;
new_node->next = right_node;
left_node->next = new_node;
right_node->pre = new_node;
4. 怎么删除项
left_node = del_node->pre;
right_node = del_node->next;
left_node->next = right_node;
right_node->pre = left_node;
5. 初始化
6. 添加person节点
7. 在链表后面添加节点
#include "usart.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define container_of(ptr, type, member) \
(type *)((char *)ptr - (unsigned int)&((type *)0)->member)
struct node_t {
struct node_t *pre;
struct node_t *next;
};
struct person {
char *name;
int age;
struct node_t node;
};
struct list {
char *name; /* A班 */
struct node_t head;
};
void InitList(struct list *pList, char *name)
{
pList->name = name;
pList->head.next = &pList->head;
pList->head.pre = &pList->head;
}
void AddItemToList(struct list *pList, struct node_t *new_node)
{
struct node_t *last = pList->head.pre;
new_node->next = &pList->head;
last->next = new_node;
new_node->pre = last;
pList->head.pre = new_node;
}
void AddItemAfter(struct node_t *pre, struct node_t *new_node)
{
struct node_t *right = pre->next;
pre->next = new_node;
new_node->next = right;
right->pre = new_node;
new_node->pre = pre;
}
void DelItemFromList(struct list *pList, struct node_t *node)
{
struct node_t *left = node->pre;
struct node_t *right = node->next;
left->next = right;
right->pre = left;
}
int CmpPersonAge(struct node_t *pre, struct node_t *next)
{
struct person *p;
struct person *n;
p = container_of(pre, struct person, node);
n = container_of(next, struct person, node);
if (p->age < n->age)
return -1;
else
return 0;
}
void SortList(struct list *pList)
{
struct node_t *pre1 = &pList->head;
struct node_t *pre2;
struct node_t *cur = pre1->next;
struct node_t *next;
struct node_t *tmp;
while (cur != &pList->head)
{
pre2 = cur;
next = cur->next;
while (next != &pList->head)
{
if (CmpPersonAge(cur, next) == 0)
{
/* 交换节点 */
/* 1. del cur */
DelItemFromList(pList, cur);
/* 2. del next */
DelItemFromList(pList, next);
/* 3. 在pre1之后插入next */
AddItemAfter(pre1, next);
/* 4. 在pre2之后插入cur */
if (pre2 == cur)
AddItemAfter(next, cur);
else
AddItemAfter(pre2, cur);
/* 5. cur/next指针互换 */
tmp = cur;
cur = next;
next = tmp;
}
pre2 = next;
next = next->next;
}
pre1 = cur;
cur = cur->next;
}
}
void PrintList(struct list *pList)
{
int i = 0;
struct node_t *node = pList->head.next;
struct person *p;
while (node != &pList->head)
{
p = container_of(node, struct person, node);
printf("person %d: %s is %d\r\n", i++, p->name, p->age);
/* 后面还有人, 移动到下一个 */
node = node->next;
}
}
int main(int argc, char **arg)
{
struct list a_list;
int i;
struct person p[] = {
{"p1", 10, {NULL}},
{"p2", 20, {NULL}},
{"p3", 13, {NULL}},
{"p4", 41, {NULL}},
{"p5", 56, {NULL}},
{"p6", 12, {NULL}},
{"p7", 9, {NULL}},
{"p8", 21, {NULL}},
{"p9", 22, {NULL}},
{"p10", 21, {NULL}},
{"p11", 20, {NULL}},
{NULL, 0, {NULL}},
};
HAL_Init();
MX_USART1_UART_Init();
InitList(&a_list, "A_class");
i = 0;
while (p[i].name != NULL)
{
AddItemToList(&a_list, &p[i].node);
i++;
}
printf("add all person:\r\n");
PrintList(&a_list);
DelItemFromList(&a_list, &p[3].node);
printf("del person %s:\r\n", p[3].name);
PrintList(&a_list);
DelItemFromList(&a_list, &p[0].node);
printf("del person %s:\r\n", p[0].name);
PrintList(&a_list);
SortList(&a_list);
printf("sort list, all person:\r\n");
PrintList(&a_list);
while(1)
{
}
}
void Error_Handler(void)
{
printf("Error\r\n");
while(1)
{
}
}
/*
add all person:
person 0: p1 is 10
person 1: p2 is 20
person 2: p3 is 13
person 3: p4 is 41
person 4: p5 is 56
person 5: p6 is 12
person 6: p7 is 9
person 7: p8 is 21
person 8: p9 is 22
person 9: p10 is 21
person 10: p11 is 20
del person p4:
person 0: p1 is 10
person 1: p2 is 20
person 2: p3 is 13
person 3: p5 is 56
person 4: p6 is 12
person 5: p7 is 9
person 6: p8 is 21
person 7: p9 is 22
person 8: p10 is 21
person 9: p11 is 20
del person p1:
person 0: p2 is 20
person 1: p3 is 13
person 2: p5 is 56
person 3: p6 is 12
person 4: p7 is 9
person 5: p8 is 21
person 6: p9 is 22
person 7: p10 is 21
person 8: p11 is 20
sort list, all person:
person 0: p7 is 9
person 1: p6 is 12
person 2: p3 is 13
person 3: p11 is 20
person 4: p2 is 20
person 5: p10 is 21
person 6: p8 is 21
person 7: p9 is 22
person 8: p5 is 56
*/