6、双向链表
双向链表的头文件
#ifndef LLIST_H_
#define LLIST_H_
/*百搭的数据结构*/
typedef void LLIST;
/*首部插入*/
#define LLIST_FORWARD 1
/*尾部插入*/
#define LLIST_BACKWARD 2
/*抽象出来的函数,函数类型为llist_op*/
typedef void llist_op(const void *);
/*抽象出来的函数,函数类型为llist_cmp*/
typedef int llist_cmp(const void *,const void *);
struct llist_node_st
{
struct llist_node_st *prev;
struct llist_node_st *next;
/*变长结构体的实现,做一个占位符,使用结构体类型的变量来引用*/
char data[1];
};
typedef struct llist_head
{
int size;
struct llist_node_st head;
int (*insert)(struct llist_head *,const void *,int);
void *(*find)(struct llist_head *,const void *,llist_cmp *);
int (*delete)(struct llist_head *,const void *,llist_cmp *);
int (*fetch)(struct llist_head *,const void *,llist_cmp *,void *);
void (*travel)(struct llist_head *,llist_op *);
}LLIST;
/*双向链表的创建*/
LLIST* llist_create(int initsize);
/*双向链表的插入*/
int llist_insert(LLIST *,const void *data,int mode);
/*双向链表的查找*/
void *llist_find(LLIST *,const void *key,llist_cmp *);
/*双向链表的删除*/
int llist_delete(LLIST *,const void *key,llist_cmp *);
/*双向链表的元素获取*/
int llist_fetch(LLIST *,const void *key,llist_cmp *,void *data);
/*双向链表的遍历*/
void llist_travel(LLIST *,llist_op *);
/*双向链表的销毁*/
void llist_destory(LLIST *);
#endif // !LLIST_H_
双向链表的C文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "llist.h"
/**
* @brief 双向链表的创建
* @param 创建大小
* @retval 创建的双向链表的首地址
*/
LLIST* llist_create(int initsize)
{
/*双向链表头结点*/
LLIST *new;
new = malloc(sizeof(*new));
if (new == NULL)
return NULL;
/*双向链表的大小*/
new->size = initsize;
/*初始化双向链表的前驱结点*/
new->head.prev = &new->head;
/*初始化双向链表的后继结点*/
new->head.next = &new->head;
/*使用函数指针操作,函数名传递的是函数的首地址*/
/*给当前指针做一个赋值*/
new->insert = llist_insert;
new->delete = llist_delete;
new->find = llist_find;
new->fetch = llist_fetch;
new->travel = llist_travel;
return new;
}
/**
* @brief 双向链表的插入
* @param 链表名,插入数据,插入模式
* @retval 双向链表的插入状态
*/
int llist_insert(LLIST *p,const void *data,int mode)
{
struct llist_node_st *newnode;
struct llist_node_st *ptr = p;
/*结构体大小再加上ptr->size*/
newnode = malloc(sizeof(*newnode)+ptr->size);
if (newnode == NULL)
return -1;
/*往newnode->data位置拷贝ptr->size字节的data数据*/
memcpy(newnode->data,data,ptr->size);
if(newnode->data == NULL)
return -2;
/*首部插入模式*/
if (mode == LLIST_FORWARD)
{
/*新前驱结点的前驱结点为头结点*/
newnode->prev = &ptr->head;
/*新结点的后继结点为头结点的next*/
newnode->next = ptr->head.next;
}
/*尾部插入模式*/
else if(mode == LLIST_BACKWARD)
{
/*新结点的前驱结点为头结点的前驱结点*/
newnode->prev = ptr->head.prev;
/*新结点的next指向头结点*/
newnode->next = &ptr->head;
}
/*错误*/
else
{
return -3;
}
/*当前结点的前驱后继等于结点本身*/
newnode->prev->next = newnode;
/*当前结点的后继前驱等于结点本身*/
newnode->next->prev = newnode;
return 0;
}
/**
* @brief 双向链表的查找子函数
* @param 链表起始位置,关键字,比较函数
* @retval 无(数据类型不统一,使用万能的void,使得函数具有通用性)
*/
static struct llist_node_st *find_(struct llist_node_st *ptr,const void *key,llist_cmp*cmp)
{
struct llist_node_st *cur;
for (cur = ptr->head.next;cur!= &ptr->head;cur=cur->next)
{
/*比较数值是否相同*/
if(cmp(key,cur->data)==0)
break;
}
return cur;
}
/**
* @brief 双向链表的查找
* @param 链表名
* @retval 无(数据类型不统一,使用万能的void,使得函数具有通用性)
*/
void *llist_find(LLIST *p,const void *key,llist_cmp *cmp)
{
/**/
struct llist_node_st *node;
struct llist_node_st *ptr = p;
node = find_(ptr,key,cmp);
/*如果是当前的头结点*/
if (node == &ptr->head)
return NULL;
return node->data;
}
/**
* @brief 双向链表的销毁
* @param 链表名,删除元素名,比较函数
* @retval 删除状态
*/
int llist_delete(LLIST *p,const void *key,llist_cmp *cmp)
{
struct llist_node_st *node;
struct llist_node_st *ptr = p;
/*根据key查找,使用node接收*/
node = find_(ptr,key,cmp);
if (node == &ptr->head)
return -1;
node->prev->next = node->next;
node->next->prev = node->prev;
/*释放node*/
free(node);
return 0;
}
/**
* @brief 双向链表的内容的删除并且拿回
* @param 链表名
* @retval 操作状态
*/
int llist_fetch(LLIST *p,const void *key,llist_cmp *cmp,void *data)
{
struct llist_node_st *node;
struct llist_node_st *ptr = p;
node = find_(ptr,key,cmp);
/*拿到的是头结点,返回失败*/
if (node == &ptr->head)
return -1;
/*脱链的过程*/
node->prev->next = node->next;
node->next->prev = node->prev;
if (node != NULL)
{
/*给data的ptr->size填充node->data*/
memcpy(data,node->data,ptr->size);
}
free(node);
return 0;
}
/**
* @brief 双向链表的遍历
* @param 链表名
* @retval 无
*/
void llist_travel(LLIST *p,llist_op *op)
{
struct llist_node_st *cur;
struct llist_node_st *ptr = p;
/*cur等于头结点的next,跳过头结点*/
for (cur = ptr->head.next;cur!=&ptr->head;cur=cur->next)
{
/*用户回调函数,程序具有通用性,用户自行编写*/
op(cur->data);
}
}
/**
* @brief 双向链表的销毁
* @param 链表名
* @retval 无
*/
void llist_destory(LLIST *p)
{
struct llist_node_st *cur,*next;
struct llist_node_st *ptr = p;
/*cur指向第一个有效结点,cur不能等于&ptr->head,如果等于说明转过了一圈*/
for (cur = ptr->head.next;cur != &ptr->head;cur=cur->next)
{
/*next保存当前结点的下一个结点*/
next = cur->next;
free(cur);
}
/*释放头结点*/
free(ptr);
}
P93 C语言实现C++的面向对象
双向链表的主函数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "llist.h"
#define NAMESIZE 32
struct score_st
{
int id;
char name[NAMESIZE];
int math;
int chinese;
};
/*用户自定义的回调函数*/
void printf_s(const void *record)
{
/*类型转换*/
const struct score_st *r = record;
printf("""%d %s %d %d \n",r->id,r->name,r->math,r->chinese);
};
/*用户自定义的比较回调函数*/
static int id_cmp(const void *key,const void *record)
{
/*数据类型转换*/
const int *k = key;
/*数据类型转换*/
const struct score_st *r = record;
/*返回值是一个状态*/
return (*k-r->id);
}
/*用户自定义的回调函数,设置为字符串比较函数*/
static int name_cmp(const void *key,const void *record)
{
/*参数类型的转换*/
const char*k = key;
/*参数类型的转换*/
const struct score_st *r = record;
/*字符串比较函数*/
return strcmp(k,r->name);
}
int main()
{
struct score_st tmp;
int ret;
LLIST *handler;
handler = llist_create(sizeof(struct score_st));
if (handler == NULL)
exit(1);
for (int i = 0; i < 7; i++)
{
tmp.id = i;
snprintf(tmp.name,NAMESIZE,"std%d",i);
tmp.math = rand()%100;
tmp.chinese = rand()%100;
/*调用函数并且给函数传参*/
ret = handler->insert(handler,&tmp,LLIST_BACKWARD);
if (ret)
exit(1);
}
/*使用面向对象方式调用*/
handler->travel(handler,printf_s);
printf("\n\n");
/*测试删除函数*/
int id = 3;
char *del_name = "std6";
ret = llist_delete(handler,del_name,name_cmp);
if (ret)
printf("llist_delete failed\n");
llist_travel(handler,printf_s);
/*测试find函数*/
struct score *data;
data = llist_find(handler,&id,id_cmp);
if (data == NULL)
printf("can't find !\n");
else
printf_s(data);
llist_destory(handler);
exit(0);
}
7、内核源码实现双向链表
双向链表的头文件
#ifndef LINUX_LIST_H__
#define LINUX_LIST_H__
struct list_head
{
struct list_head *prev;
struct list_head *next;
};
#define LIST_HEAD_INIT(name) {&(name),&(name)}
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
static inline void list_add(struct list_head *new,struct list_head *head)
{
__list_add(new,head,head->next);
}
#define __list_for_each(pos,head)\
for (pos = (head)->next;pos!= (head);pos = pos->next)
/*
* ptr->cur;
* type->struct score_st;
* member->node
*/
#define offsetof(TYPE,MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
#define container_of(ptr,type,member)\
({ (type *)((char *)ptr - offsetof(type,member));})
#define list_entry(ptr,type,member)\
container_of(ptr,type,member)
#endif
双向链表的主函数
#include <stdlib.h>
#include <stdio.h>
#include "list.h"
#define NAMESIZE 32
struct score_st
{
int id;
char name[NAMESIZE];
struct list_head node;
int math;
int chinese;
};
static void printf_s(struct score_st *d)
{
printf("%d %s %d %d\n",d->id,d->name,d->math,d->chinese);
}
int main()
{
struct score_st *datap;
struct list_head *cur;
LIST_HEAD(head);
for (int i = 0; i < 7; i++)
{
datap = malloc(sizeof(*datap));
if (datap == NULL)
exit(1);
datap->id = i;
snprintf(datap->name,NAMESIZE,"stu%d",i);
datap->math = rand()%100;
datap->chinese = rand()%100;
list_add(&datap->node,&head);
}
__list_for_each(cur,&head)
{
datap = list_entry(cur,struct score_st,node);
printf_s(datap);
}
__list_for_each(cur,&head)
{
datap = list_entry(cur,struct score_st,node);
if (datap->id == 5)
{
break;
}
}
if (cur == &head)
printf("can't find");
else
printf_s(datap);
exit(0);
}
8、栈的实现(线性表)
栈实现的头文件
#ifndef SQSTACK_H__
#define SQSTACK_H__
#define MAXSIZE 5
typedef int datatype;
typedef struct node_st
{
datatype data[MAXSIZE];
/*记录栈顶的位置*/
int top;
}sqstack;
/*栈的创建*/
sqstack *st_create(void);
/*判断栈是否为空*/
int st_isempty(sqstack*);
/*入栈*/
int st_push(sqstack*,datatype *);
/*出栈*/
int st_pop(sqstack*,datatype *);
/*获取栈顶元素*/
int st_top(sqstack*,datatype *);//fetch top element;
/*栈的遍历*/
void st_travel(sqstack*);
/*栈的销毁*/
void st_destory(sqstack *);
#endif // !SQSTACK_H__
栈实现的C文件
#include <stdlib.h>
#include <stdio.h>
#include "sqstack.h"
/**
* @brief 栈的创建
* @param None
* @retval 栈的起始位置
*/
sqstack *st_create(void)
{
sqstack *st;
st = malloc(sizeof(*st));
if (st == NULL)
return NULL;
/*配置栈顶元素为-1*/
st->top = -1;
return st;
}
/**
* @brief 判断栈是否为空
* @param 栈的起始位置
* @retval 1表示为空,0表示非空
*/
int st_isempty(sqstack* st)
{
return (st->top == -1);
}
/**
* @brief 入栈
* @param 栈的起始位置,入栈元素
* @retval -1表示失败,0表示成功
*/
int st_push(sqstack* st ,datatype *data)
{
/*栈已满*/
if (st->top == MAXSIZE - 1)
{
return -1;
}
/*栈的下一个元素存放data*/
st->data[++st->top] = *data;
return 0;
}
/**
* @brief 出栈
* @param 栈的起始位置,出栈元素
* @retval 1表示为空,0表示非空
*/
int st_pop(sqstack*st,datatype *data)
{
/*判断栈是否为空*/
if (st_isempty(st))
return -1;
/*指向栈顶的下一个元素*/
*data = st->data[st->top --];
return 0;
}
/**
* @brief 取栈顶元素
* @param 栈的起始位置,出栈元素
* @retval -1表示失败,0表示成功
*/
int st_top(sqstack*st,datatype *data)//fetch top element;
{
/*判断栈是否为空*/
if (st_isempty(st))
{
return -1;
}
*data = st->data[st->top];
return 0;
}
/**
* @brief 栈的遍历
* @param 栈的起始位置
* @retval None
*/
void st_travel(sqstack* st)
{
/*判断栈是否为空*/
if (st_isempty(st))
return ;
/*循环遍历栈内元素*/
for (int i = 0; i <= st->top; i++)
{
printf("%d \n",st->data[i]);
}
printf("\n");
}
/**
* @brief 栈的销毁
* @param 栈的起始位置
* @retval None
*/
void st_destory(sqstack * st)
{
free(st);
}
栈实现的主函数
#include <stdlib.h>
#include <stdio.h>
#include "sqstack.h"
int main()
{
datatype arr[] = {19,23,45,67};
sqstack *st;
st = st_create();
if (st == NULL)
exit(1);
/*栈的初始化*/
for (int i = 0; i < sizeof(arr)/sizeof(*arr); i++)
{
st_push(st,&arr[i]);
}
/*栈的遍历*/
st_travel(st);
datatype tmp;
while (st_pop(st,&tmp) == 0)
{
printf("POP: %d\n",tmp);
}
/*出栈测试*/
datatype tmp = 1;
int ret;
ret = st_push(st,&tmp);
if (ret != 0)
printf("st_push failed.\n");
else
st_travel(st);
st_destory(st);
}
9、栈的实现(链表)
栈实现的头文件
#ifndef STACK_H__
#define STACK_H__
#include "llist.h"
typedef LLIST STACK;
/*栈的创建*/
STACK *stack_create(int initsize);
/*入栈*/
int stack_push(STACK * ,const void*);
/*出栈*/
int stack_pop(STACK * ,void *);
/*销毁栈*/
void stack_destory(STACK *);
#endif // !STACK_H__
栈实现的C文件
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
/**
* @brief 栈的创建
* @param 栈的大小
* @retval 栈的起始地址
*/
STACK* stack_create(int initsize)
{
/*通过链表创建栈*/
return llist_create(initsize);
}
/**
* @brief 入栈
* @param 栈名,入栈内容
* @retval 入栈的状态
*/
int stack_push(STACK *ptr ,const void*data)
{
return llist_insert(ptr,data,LLIST_FORWARD);
}
/**
* @brief 静态定义完全匹配函数
* @param 任意匹配的参数1,任意匹配的参数2
* @retval None
*/
static int always_match(const void *p1,const void *p2)
{
return 0;
}
/**
* @brief 出栈
* @param 栈的起始位置,出栈元素
* @retval 出栈状态
*/
int stack_pop(STACK *ptr ,void *data)
{
return llist_fetch(ptr,(void *)0,always_match,data);
}
/**
* @brief 栈的销毁
* @param 栈的首地址
* @retval None
*/
void stack_destory(STACK *ptr)
{
llist_destory(ptr);
}
栈实现的主函数
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
#define NAMESIZE 32
int ret;
struct score_st
{
int id;
char name[NAMESIZE];
int math;
int chinese;
};
/*打印函数,打印出栈的元素*/
static void printf_s(void *record)
{
struct score_st *r = record;
printf("%d %s %d %d \n",r->id,r->name,r->math,r->chinese);
}
int main()
{
STACK *st;
struct score_st tmp;
st = stack_create(sizeof(struct score_st));
if (st == NULL)
exit(1);
for (int i = 0; i < 7; i++)
{
tmp.id = i;
snprintf(tmp.name,NAMESIZE,"std%d",i);
tmp.math = rand()%100;
tmp.chinese = rand()%100;
/*如果入栈异常*/
if(stack_push(st,&tmp))
exit(1);
}
while (1)
{
ret = stack_pop(st,&tmp);
/*如果出栈异常,跳出*/
if (ret == -1)
break;
printf_s(&tmp);
}
stack_destory(st);
exit(0);
}
10、队列的实现(线性表)
队列实现的头文件
#ifndef QUEUE__H_
#define QUEUE__H_
#define MAXSIZE 5
typedef int datatype;
typedef struct node_st
{
datatype data[MAXSIZE];
int head,tail;
}queue;
/*队列的创建*/
queue *qu_create();
/*判断队列是否为空*/
int qu_isempty(queue *);
/*队列的入队*/
int qu_enqueue(queue*,datatype *);
/*队列的出队*/
int qu_dequeue(queue*,datatype *);
/*队列的遍历*/
void qu_travel(queue*);
/*队列的清除*/
void qu_clear(queue*);
/*队列的销毁*/
void qu_destory(queue *);
#endif // !QUEUE__H_
队列实现的C文件
#include <stdlib.h>
#include <stdio.h>
#include "queue.h"
/**
* @brief 队列的创建
* @param None
* @retval 队列的首地址
*/
queue *qu_create()
{
queue*sq;
sq = malloc(sizeof(*sq));
if (sq == NULL)
{
return NULL;
}
sq->head = 0;
sq->tail = 0;
return sq;
}
/**
* @brief 判断队列是否为空
* @param 队列的首地址
* @retval 1表示为空,0表示非空
*/
int qu_isempty(queue *sq)
{
return (sq->head == sq->tail);
}
/**
* @brief 队列的入队
* @param 队列的首地址,入队元素
* @retval 入队状态
*/
int qu_enqueue(queue*sq,datatype *x)
{
if ((sq->tail+1)%MAXSIZE == sq->head)//如果尾巴取余+1等于头,那么不可以加入。
return -1;
/*队列的尾巴等于队列的尾巴+1 和 队列最大值取余*/
sq->tail = (sq->tail +1) % MAXSIZE;
/*入队元素就是待入队的元素*/
sq->data[sq->tail] = *x;
return 0;
}
/**
* @brief 队列的出队
* @param 队列的首地址,出队元素
* @retval 出队状态
*/
int qu_dequeue(queue*sq,datatype *x)
{
/*判断队列是否为空*/
if(qu_isempty(sq))
return -1;
/*队列的头等于队列的头+1 和 队列最大值取余表示队列的起始位置*/
sq->head = (sq->head+1)%MAXSIZE;
/*出队元素就是队列的头*/
*x = sq->data[sq->head];
return 0;
}
/**
* @brief 队列的遍历
* @param 队列的首地址
* @retval None
*/
void qu_travel(queue*sq)
{
/*判断队列是否合法*/
if (sq->head == sq->tail)
return ;
/*队列的起始位置*/
int i = (sq->head + 1)%MAXSIZE;
/*头部结点不等于尾部结点时*/
while (i!=sq->tail)
{
/*打印每一个结点*/
printf("%d ",sq->data[i]);
/*队列位置递增*/
i = (i+1)%MAXSIZE;
}
/*打印最后一个结点*/
printf("%d \n",sq->data[i]);
}
/**
* @brief 队列的清空
* @param 队列的首地址
* @retval None
*/
void qu_clear(queue*sq)
{
/*让队列的头部指向队列的尾巴*/
sq->head = sq->tail;
}
/**
* @brief 队列的销毁
* @param 队列的首地址
* @retval None
*/
void qu_destory(queue *sq)
{
free(sq);
}
队列实现的主函数
#include <stdlib.h>
#include <stdio.h>
#include "queue.h"
int main()
{
queue *sq;
datatype arr[] = {2,3,98,12};
int i,ret;
/*队列的创建*/
sq = qu_create();
if (sq == NULL)
exit(1);
/*队列的初始化*/
for (int i = 0; i < sizeof(arr)/sizeof(*arr); i++)
{
qu_enqueue(sq,&arr[i]);
}
/*队列的遍历*/
qu_travel(sq);
/*队列入队的测试*/
datatype tmp = 100;
ret = qu_enqueue(sq,&tmp);
if (ret == -1)
printf("queue is full!\n");
else
qu_travel(sq);
/*队列的出队测试*/
datatype tmp;
qu_dequeue(sq,&tmp);
printf("DEQUEUE: %d \n",tmp);
/*队列的遍历*/
qu_travel(sq);
/*队列的销毁*/
qu_destory(sq);
exit(0);
}
11、队列的实现(链表)
链表实现的头文件
#ifndef QUEUE__H_
#define QUEUE__H_
#include "llist.h"
typedef LLIST QUEUE;
/*队列的创建*/
QUEUE *queue_create(int);
/*队列入队*/
int queue_en(QUEUE *,const void * );
/*队列出队*/
int queue_de(QUEUE *,void *);
/*队列销毁*/
void queue_destory(QUEUE *);
#endif // QUEUE__H_
链表实现的C文件
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
/**
* @brief 队列创建
* @param 队列的大小
* @retval 队列的首地址
*/
QUEUE * queue_create(int size)
{
return llist_create(size);
}
/**
* @brief 队列的入队
* @param 队列的首地址,入队元素
* @retval 入队状态
*/
int queue_en(QUEUE *ptr,const void * data)
{
return llist_insert(ptr,data,LLIST_BACKWARD);
}
/**
* @brief 完全匹配函数
* @param 通用类型 p1,p2
* @retval 0
*/
static int alwaws_match(const void *p1 ,const void *p2)
{
return 0;
}
/**
* @brief 队列的出队
* @param 队列的首地址,出队数据
* @retval None
*/
int queue_de(QUEUE *ptr,void *data)
{
return llist_fetch(ptr,(void*)0,alwaws_match,data);
}
/**
* @brief 队列的销毁
* @param 队列的首地址
* @retval None
*/
void queue_destory(QUEUE *ptr)
{
llist_destory(ptr);
}
链表实现的主函数
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
#define MAXSIZE 32
struct score_st
{
int id;
char name[MAXSIZE];
int math;
int chinese;
};
/*自定义打印函数,参数为通用void*类型*/
static void printf_s(void *record)
{
struct score_st *r = record;
printf("%d %s %d %d \n",r->id,r->name,r->math,r->chinese);
}
int main()
{
QUEUE *qu;
int ret;
struct score_st tmp;
/*队列的创建*/
qu = queue_create(sizeof(struct score_st));
if (qu == NULL)
exit(1);
for (int i = 0; i < 7; i++)
{
tmp.id = i;
snprintf(tmp.name,MAXSIZE,"stu%d",i);
tmp.math = rand()%100;
tmp.chinese = rand()%100;
/*判断队列入队是否发生错误*/
if(queue_en(qu,&tmp)!=0)
break;
}
/*队列执行出队操作*/
while (1)
{
ret = queue_de(qu,&tmp);
if (ret == -1)
break;
printf_s(&tmp);
}
/*队列的销毁*/
queue_destory(qu);
exit(0);
}