链表
类型:
单向链表:
双向链表:
- 双向链表的前向指针指向前一个结点的首地址,后向指针指向下一个节点的首地址,并且指针类型相同,且只能指向与自己类型相同的结构体。
循环链表:
通用链表:
- 通用链表的前向指针指向前一个结点的指针域的首地址,后向指针指向下一个节点的指针域的首地址,所以在不同的结构体中定义相同的指针域就可以了,也就是说,单独定义一个结构体类型,其成员只有指针域,并且在其他结构体中定义这种结构体类型的变量。
单向链表
- 单向单指针操作
/*
* 3_stu_input.c
现有学生结构体(id,name,score),写代码实现
(1)从键盘初始化学员
(2)使用链表
(3)遍历打印所有学员
*/
#include <stdio.h>
#include <stdlib.h>
#define SIZE 3
struct student
{
char name[20];
int id;
int score;
struct student* next;
};
typedef struct student stud;
void output(void);
void insert(void);
stud* creat(stud* p);
stud* head=NULL;
int main(void)
{
head=creat(head);
char n='\0';
while(n!='q'){
insert();
printf("按任意键继续,或者按'q'退出:\n");
while(getchar()!='\n');
scanf("%c",&n);
}
printf("输入的学生信息为:\n");
output();
return 0;
}
stud* creat(stud* p){
p=(stud*)malloc(sizeof(stud));
p->next=NULL;
return p;
}
void insert(void){
stud* p=(stud*)malloc(sizeof(stud));
printf("请输入学生的学号,名字和成绩:");
scanf("%d %s %d",&p->id,p->name, &p->score);
p->next=NULL;
stud* current = head;
while(current->next!=NULL) current=current->next;
current->next=p;
}
void output(void){
for(stud* current=head;
current->next!=NULL; current=current->next)
printf("%d %s %d\n",current->next->id,current->next->name, current->next->score);
}//此处判断到结点指向NULL就会退出,无法输出最终项,所以使用current=head,current->next->name来输出。
双向链表
- 链表结点数据结构定义
struct xLIST_ITEM
{
TickType_t xItemValue; //辅助值,用于帮助节点进行排序
struct xLIST_ITEM* pxNext; //指向链表下一个节点
struct xLIST_ITEM* pxPrevious; //指向链表上一个节点
void* pvOwner; //指向拥有该节点的对象
void* pvContainer; //指向该节点所在的链表
};
typedef struct xLIST_ITEM ListItem_t;
- 链表节点初始化
void vListInitializeItem(ListItem_t* const pxItem)
{
//初始化该节点所在链表为空,表示节点还未插入任何链表
pxItem->pvContainer = NULL;
}
- 链表根节点数据结构定义
typedef struct xList
{
UBaseType_t uxNumberOfItems; //链表节点计数器
ListItem_t* pxIndex; //链表节点索引指针
MiniListItem_t xListEnd; //链表最后一个节点
}List_t;
- 链表精简节点结构体定义
struct xMINI_LIST_ITEM
{
TickType_t xItemValue; //辅助值,用于帮助节点进行排序
struct xLIST_ITEM* pxNext; //指向链表下一个节点
struct xLIST_ITEM* pxPrevious; //指向链表上一个节点
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;
- 链表根节点的初始化
void vListInitialize(List_t* const pxList)
{
//将链表索引指针指向最后一个节点
pxList->pxIndex = (ListItem_t*) &(pxList->xListEnd);
//将链表最后一个节点的辅助排序值设置最大
pxList->xListEnd.xItemValue = portMAX_DELAY;
//将最后一个节点的next 和 previous指针均指向节点本身,表示链表为空
pxList->xListEnd.pxNext = (ListItem_t*) &(pxList->xListEnd);
pxList->xListEnd.pxPrevious = (ListItem_t*) &(pxList->xListEnd);
//初始化链表计数器值为0,表示链表为空
pxList->uxNumberOfItems = (UBaseType_t) 0U;
}
双向循环链表操作
/*双循环通用链表*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct Link link_t;
struct Link
{
void *data;
link_t *pre;
link_t *next;
};
link_t* creathead(void);
link_t* creatnode(void);
link_t* insertnode(link_t *head, void *data, int size);
void display_link(link_t *head);
void destroy_allnode(link_t *head);
void sort_link(link_t *start, link_t *end, int (*cp)(const void *, const void *));
int compare(const void* p1, const void *p2);
int main(void)
{
int data = 0;
link_t *head = creathead();
for (int i = 0; i < 10; i++){
data = rand() % 100;
insertnode(head, &data, sizeof(data));
}
display_link(head);
sort_link(head->next, head->pre, compare);
display_link(head);
destroy_allnode(head);
return 0;
}
link_t* creathead(void)
{
link_t *head = NULL;
head = (link_t*)malloc(sizeof(link_t));
if (NULL == head){
perror("malloc failed!");
return NULL;
}
memset(head, 0, sizeof(link_t));
head->pre = head;
head->next = head;
return head;
}
link_t* creatnode(void)
{
link_t *p = NULL;
p = (link_t*)malloc(sizeof(link_t));
if (NULL == p){
perror("malloc failed!");
return NULL;
}
memset(p, 0, sizeof(link_t));
return p;
}
//尾插
link_t* insertnode(link_t *head, void *data, int size)
{
link_t *node = NULL;
if (NULL == head || NULL == data){
return NULL;
}
node = creatnode(); //创建节点
if (NULL == node){
printf("node is null!");
return NULL;
}
node->data = malloc(size); //扩展一个data数据长度的空间
if (NULL == node->data){ //创建失败则返回
free(node);
return NULL;
}
memcpy(node->data, data, size); //将数据内存拷贝给节点数据指针
head->pre->next = node; //最后一个节点为head->pre
node->pre = head->pre;
node->next = head;
head->pre = node;
return node;
}
link_t *findnode(link_t *head, void *data, int (*cp)(const void *, const void *))
{
link_t *p = NULL;
if (NULL == head){
return NULL;
}
p = head->next;
while (p != head){
if (cp(p->data, data) == 0){
return p;
}
p = p->next;
}
return NULL;
}
link_t* deletenode(link_t *head, void *data, int (*cp)(const void *, const void *))
{
link_t *p = NULL;
if (NULL == head){
return NULL;
}
p = findnode(head, data, cp);
if (NULL == p){
return p;
}
p->pre->next = p->next;
p->next->pre = p->pre;
free(p->data);
free(p);
p = NULL;
return head;
}
link_t* updatenode(link_t *head, void *alter, void *data, int size, int (*cp)(const void *, const void *))
{
link_t *p = NULL;
if (NULL == head){
return NULL;
}
p = findnode(head, alter, cp);
if (NULL == p){
return p;
}
memcpy(p->data, data, size);
return p;
}
void sort_link(link_t *start, link_t *end, int (*cp)(const void *, const void *))
{
link_t *l = NULL, *r = NULL;
void *key = NULL;
if (NULL == start || NULL == end || start == end || end->next == start || start->pre == end)
{
return;
}
l = start, r = end;
key = l->data;
while (l != r){
while(l != r && cp(key, r->data) > 0){
r = r->pre;
}
l->data = r->data;
while(l != r && cp(l->data, key) > 0){
l = l->next;
}
r->data = l->data;
}
l->data = key;
sort_link(start, l->pre, cp);
sort_link(l->next, end, cp);
}
void display_link(link_t *head)
{
link_t *p = NULL;
if (NULL == head){
return;
}
p = head->next;
while (p != head){
printf("%d ", *(int*)p->data);
p = p->next;
}
putchar('\n');
}
void destroy_allnode(link_t *head)
{
link_t *p = NULL;
if (NULL == head){
return;
}
while (head->pre != head){
p = head->pre;
head->pre = p->pre;
free(p->data);
free(p);
}
free(head);
}
int compare(const void* p1, const void *p2)
{
return *(int*)p1 >= *(int*)p2;
}
通用链表
- 声明和宏定义:
#ifndef __LIST_HEAD_H__
#define __LIST_HEAD_H__
//通用链表节点类型 双向链表
struct list_head{
struct list_head *prev; //前级指针
struct list_head *next;//后级指针
};
void INIT_LIST_HEAD(struct list_head *list);//初始化通用链表
void list_add(struct list_head *node,struct list_head *head);//插入节点
void list_add_tail(struct list_head *node,struct list_head *head);//尾插
void list_del(struct list_head *node);//删除节点
/*遍历链表 依次为:从头节点的下一个节点开始遍历
* 从头节点的上一个节点开始遍历
*(以list_for_next_each为例理解:首先节点指针pos指向头节点的下一个节点,判断 pos是否指向头节点,不是的话就向后继续遍历)
*/
#define list_for_next_each(pos,head)\for(pos=(head)->next;pos!=(head);pos=pos->next)#define list_for_prev_each(pos,head)\for(pos=(head)->prev;pos!=(head);pos=pos->prev)
//提取数据结构 ptr 是链接因子的指针 type是包含了链接因子的数据类型 member是链接因子成员名
#define container_of(ptr,type,member)\
(type *)( (int)ptr - (int)(&((type *)0)->member) )
#endif
- 链表操作函数:
#include "list_head.h"
void INIT_LIST_HEAD(struct list_head *list)//初始化通用链表
{
//前后级指针都指向本身
list->next=list;
list->prev=list;
}
void list_add(struct list_head *node,struct list_head *head)//插入节点
{
node->next=head->next;
node->prev=head;
head->next->prev=node;
head->next=node;
}
void list_add_tail(struct list_head *node,struct list_head *head)//尾插
{
node->next=head->prev;
node->prev=head;
head->prev->next=node;
head->prev=node;
}
void list_del(struct list_head *node)//删除节点
{
node->prev->next=node->next;
node->next->prev=node->prev;
}
- 数据定义:
#ifndef __STU_H__
#define __STU_H__
#define N 32
#include "list_head.h"
struct STU{
int id;
char name[N];
char pwd[N];
float score;
struct list_head list;//链接因子
};
#endif
- 测试文件:
#include <stdio.h>
#include <stdlib.h>
#include "list_head.h"
#include "stu.h"
int main(int argc, const char *argv[])
{
int i;
struct STU *stu;
struct STU *stup;
struct list_head *pos;
struct list_head stu_list;//学生表的首节点
stu=(struct STU *)malloc(sizeof(struct STU)*5); //分配节点空间
if(!stu)
{
perror("fail to malloc");
return -1;
}
//初始化通用链表
INIT_LIST_HEAD(&stu_list);
for(i=0;i<5;i++) //赋值学生信息
{
stu[i].id=i;
sprintf(stu[i].name,"stu%d",i);
sprintf(stu[i].pwd,"160%d",i);
stu[i].score=10*i;
list_add(&stu[i].list,&stu_list);//插入链表
}
//遍历学生信息
list_for_next_each(pos,&stu_list)
{
stup=container_of(pos,struct STU,list);
printf("stu:id=%d,name=%s,pwd=%s,score=%f\n",\
stup->id,stup->name,stup->pwd,stup->score);
}
puts("--------------------------------");
list_for_prev_each(pos,&stu_list)
{
stup=container_of(pos,struct STU,list);
printf("stu:id=%d,name=%s,pwd=%s,score=%f\n",\
stup->id,stup->name,stup->pwd,stup->score);
}
return 0;
}