基于双链表的队列和栈操作的实现
目录
1. 应用需求
1.1 背景
- 以往队列和栈的实现一般都限制了数据类型和长度,无法做到通用性,因此本文主要考虑通用性实现一套接口解决这个问题。
1.2 前提
- 动态分配函数,malloc和free。
1.3 功能
- 支持FIFO/LIFO的常规操作。
- 不限制每次入队/入栈的数据类型和长度。
- 采用面向对象的编程思维,便于移植,理论上移植后不需要进行修改源代码
2. 功能实现
2.1 源文件实现
- Buff.h
#ifndef __BUFF_H__
#define __BUFF_H__
typedef void* BuffHandle_t;
typedef void *(*mallocCb)(unsigned long size);
typedef void (*freeCb)(void *ptr);
typedef void (*printCb)(const char *format, ...);
BuffHandle_t BuffCreat(unsigned long maxNums, mallocCb mallocFun, freeCb freeFun, printCb printFun);
int BuffDelete(BuffHandle_t handle);
unsigned char BuffIsEmpty(BuffHandle_t handle);
unsigned char BuffIsFull(BuffHandle_t handle);
unsigned int BuffGetNums(BuffHandle_t handle);
unsigned int BuffGetFreeNums(BuffHandle_t handle);
int BuffPushTail(BuffHandle_t handle, void *data, unsigned long dataSize);
int BuffPopTail(BuffHandle_t handle, void *data, unsigned long dataSize);
int BuffPushHead(BuffHandle_t handle, void *data, unsigned long dataSize);
int BuffPopHead(BuffHandle_t handle, void *data, unsigned long dataSize);
int BuffRead(BuffHandle_t handle, void *data, unsigned long dataSize, unsigned long cnt);
void BuffPrint(BuffHandle_t handle);
#endif
- Buff.c
#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include "Buff.h"
#ifdef __BUFF_H__
//buff的存储内容对外不可见
typedef struct _BuffNode
{
unsigned long dataSize; //数据大小
void *data; //指向数据内容
struct _BuffNode *prev; //指向上一个数据地址
struct _BuffNode *next; //指向下一个数据地址
} BuffNode_t;
//buff的头信息
typedef struct
{
unsigned long curNums;
unsigned long maxNums;
BuffNode_t *addr;
mallocCb mallocFun;
freeCb freeFun;
printCb printFun;
} BuffHead_t;
//-----------------------------------------------------------------------------
// 名称:BuffCreatNode
// 功能:创建一个动态的节点数据
// 参数:
// 返回:
// 说明:
//-----------------------------------------------------------------------------
static BuffNode_t* BuffCreatNode(BuffHandle_t handle, void *data, unsigned long dataSize)
{
BuffHead_t *head = (BuffHead_t *)handle;
void *buff = NULL;
BuffNode_t *add = NULL;
//参数检查
if (handle == NULL || data == NULL || dataSize <= 0)
{
return NULL;
}
//创建内容缓存
buff = head->mallocFun(dataSize);
if (buff == NULL)
{
return NULL;
}
//非空队列中增加一个节点
add = (BuffNode_t *)head->mallocFun(sizeof(BuffNode_t));
if (add == NULL)
{
head->freeFun(buff);
return NULL;
}
memcpy(buff, data, dataSize);
add->dataSize = dataSize;
add->data = buff;
add->next = NULL;
add->next = NULL;
return add;
}
//-----------------------------------------------------------------------------
// 名称:BuffCreat
// 功能:创建一个Buff
// 参数:void
// 返回:Buff的句柄
// 说明:仅仅是创建一个句柄
//-----------------------------------------------------------------------------
BuffHandle_t BuffCreat(unsigned long maxNums, mallocCb mallocFun, freeCb freeFun, printCb printFun)
{
BuffHead_t *handle = NULL;
if (mallocFun == NULL || freeFun == NULL)
{
return NULL;
}
//创建一个头节点内存
handle = (BuffHead_t *)mallocFun(sizeof(BuffHead_t));
if (handle == NULL)
{
return NULL;
}
//初始化头信息
handle->curNums = 0;
handle->maxNums = maxNums;
handle->addr = NULL;
handle->mallocFun = mallocFun;
handle->freeFun = freeFun;
handle->printFun = printFun;
return handle;
}
//-----------------------------------------------------------------------------
// 名称:BuffDelete
// 功能:删除Buff
// 参数:Buff句柄
// 返回:成功返回0,否则返回<0
// 说明:
//-----------------------------------------------------------------------------
int BuffDelete(BuffHandle_t handle)
{
BuffHead_t *head = (BuffHead_t *)handle;
BuffNode_t *del = NULL;
unsigned long i = 0;
unsigned long buffNums = 0;
//参数异常
if (handle == NULL)
{
return -1;
}
buffNums = head->curNums;
//删除所有的节点
for (i = 0; i < buffNums; i++)
{
del = head->addr;
if (del->data != NULL)
{
head->freeFun(del->data);
}
head->addr = del->next;
head->freeFun(del);
}
//删除头信息
head->freeFun(head);
return 0;
}
//-----------------------------------------------------------------------------
// 名称:BuffIsEmpty
// 功能:Buff是否为空
// 参数:Buff句柄
// 返回:空Buff返回1,否则返回0
// 说明:
//-----------------------------------------------------------------------------
unsigned char BuffIsEmpty(BuffHandle_t handle)
{
BuffHead_t *head = (BuffHead_t *)handle;
//参数错误认为是空buff
if (handle == NULL)
{
return 1;
}
if (head->curNums <= 0)
{
return 1;
}
return 0;
}
//-----------------------------------------------------------------------------
// 名称:BuffIsFull
// 功能:Buff是否为满
// 参数:Buff句柄
// 返回:满Buff返回1,否则返回0
// 说明:
//-----------------------------------------------------------------------------
unsigned char BuffIsFull(BuffHandle_t handle)
{
BuffHead_t *head = (BuffHead_t *)handle;
//参数错误认为是空buff
if (handle == NULL)
{
return 0;
}
if (head->curNums < head->maxNums)
{
return 0;
}
return 1;
}
//-----------------------------------------------------------------------------
// 名称:BuffGetNums
// 功能:获取有效Buff数据条数
// 参数:句柄
// 返回:返回数据条数,失败返回0
// 说明:
//-----------------------------------------------------------------------------
unsigned int BuffGetNums(BuffHandle_t handle)
{
BuffHead_t *head = (BuffHead_t *)handle;
if (handle == NULL)
{
return 0;
}
return head->curNums;
}
//-----------------------------------------------------------------------------
// 名称:BuffGetFreeNums
// 功能:获取剩余可用有效数据条数
// 参数:队列句柄
// 返回:返回剩余数据条数,失败返回0
// 说明:
//-----------------------------------------------------------------------------
unsigned int BuffGetFreeNums(BuffHandle_t handle)
{
BuffHead_t *head = (BuffHead_t *)handle;
if (handle == NULL)
{
return 0;
}
return (head->maxNums - head->curNums);
}
//-----------------------------------------------------------------------------
// 名称:BuffPushTail
// 功能:往句柄中尾部添加一条数据
// 参数:handle,句柄
// data,写入的数据地址
// dataSize,数据字节数
// 返回:成功返回写入的字节数,否则返回<0
// 说明:
//-----------------------------------------------------------------------------
int BuffPushTail(BuffHandle_t handle, void *data, unsigned long dataSize)
{
BuffHead_t *head = (BuffHead_t *)handle;
BuffNode_t *add = NULL;
//参数检查
if (handle == NULL || data == NULL || dataSize <= 0)
{
return -1;
}
//超过最大限制
if (head->curNums >= head->maxNums)
{
BuffPopHead(handle, data, dataSize);
return -1;
}
//创建一个节点
add = BuffCreatNode(handle, data, dataSize);
if (add == NULL)
{
return -1;
}
//空
if (head->addr == NULL)
{
add->next = add;
add->prev = add;
head->addr = add;
}
//尾插
else
{
add->next = head->addr;
add->prev = head->addr->prev;
head->addr->prev->next = add;
head->addr->prev = add;
}
head->curNums++;
return dataSize;
}
//-----------------------------------------------------------------------------
// 名称:BuffPopTail
// 功能:在BUFF尾部弹出数据
// 参数:handle,Buff句柄
// data,接收的数据地址
// dataSize,接收区缓存大小
// 返回:成功返回弹出的字节数,否则返回<0
// 说明:
//-----------------------------------------------------------------------------
int BuffPopTail(BuffHandle_t handle, void *data, unsigned long dataSize)
{
BuffHead_t *head = (BuffHead_t *)handle;
BuffNode_t *del = NULL;
//参数检查
if (handle == NULL)
{
return -1;
}
//没有数据
if (head->curNums <= 0)
{
return -1;
}
del = head->addr->prev;
if (del->data != NULL)
{
if (data != NULL && dataSize > 0)
{
if (dataSize >= del->dataSize)
{
dataSize = del->dataSize;
}
memcpy(data, del->data, dataSize);
}
else
{
dataSize = 0;
}
head->freeFun(del->data);
}
else
{
dataSize = 0;
}
//有多个节点
if (head->curNums > 1)
{
head->addr->prev = del->prev;
head->addr->prev->next = head->addr;
}
else
{
head->addr = NULL;
}
head->freeFun(del);
head->curNums--;
return dataSize;
}
//-----------------------------------------------------------------------------
// 名称:BuffPushHead
// 功能:往句柄中头部添加一条数据
// 参数:handle,句柄
// data,写入的数据地址
// dataSize,数据字节数
// 返回:成功返回写入的字节数,否则返回<0
// 说明:
//-----------------------------------------------------------------------------
int BuffPushHead(BuffHandle_t handle, void *data, unsigned long dataSize)
{
BuffHead_t *head = (BuffHead_t *)handle;
BuffNode_t *add = NULL;
//参数检查
if (handle == NULL || data == NULL || dataSize <= 0)
{
return -1;
}
//超过最大限制
if (head->curNums >= head->maxNums)
{
return -1;
}
//创建一个节点
add = BuffCreatNode(handle, data, dataSize);
if (add == NULL)
{
return -1;
}
//没有节点
if (head->addr == NULL)
{
add->prev = add;
add->next = add;
head->addr = add;
}
else
{
//头插
add->next = head->addr;
add->prev = head->addr->prev;
head->addr->prev->next = add;
head->addr->prev = add;
head->addr = add;
}
head->curNums++;
return dataSize;
}
//-----------------------------------------------------------------------------
// 名称:BuffPopHead
// 功能:在BUFF头部弹出数据
// 参数:handle,Buff句柄
// data,接收的数据地址
// dataSize,接收区缓存大小
// 返回:成功返回弹出的字节数,否则返回<0
// 说明:
//-----------------------------------------------------------------------------
int BuffPopHead(BuffHandle_t handle, void *data, unsigned long dataSize)
{
BuffHead_t *head = (BuffHead_t *)handle;
BuffNode_t *del = NULL;
//参数检查
if (handle == NULL)
{
return -1;
}
//没有数据
if (head->curNums <= 0)
{
return -1;
}
del = head->addr;
if (del->data != NULL)
{
if (data != NULL && dataSize > 0)
{
if (dataSize >= del->dataSize)
{
dataSize = del->dataSize;
}
memcpy(data, del->data, dataSize);
}
else
{
dataSize = 0;
}
head->freeFun(del->data);
}
else
{
dataSize = 0;
}
//有多个节点
if (head->curNums > 1)
{
head->addr = del->next;
head->addr->prev = del->prev;
head->addr->prev->next = head->addr;
}
else
{
head->addr = NULL;
}
head->freeFun(del);
head->curNums--;
return dataSize;
}
//-----------------------------------------------------------------------------
// 名称:BuffRead
// 功能:在BUFF中读取数据
// 参数:handle,Buff句柄
// data,接收的数据地址
// dataSize,接收区缓存大小
// cnt,读取第几条数据,下标从0开始
// 返回:成功返回弹出的字节数,否则返回<0
// 说明:
//-----------------------------------------------------------------------------
int BuffRead(BuffHandle_t handle, void *data, unsigned long dataSize, unsigned long cnt)
{
BuffHead_t *head = (BuffHead_t *)handle;
BuffNode_t *cur = NULL;
unsigned long i = 0;
//检查参数
if (handle == NULL)
{
return -1;
}
//查看是否符合范围
if (cnt >= head->curNums)
{
return -1;
}
cur = head->addr;
if (cnt < head->curNums - cnt)
{
for (i = 0; i < cnt; i++)
{
cur = cur->next;
}
}
else
{
for (i = 0; i < head->curNums - cnt; i++)
{
cur = cur->prev;
}
}
if (cur->data != NULL)
{
if (data != NULL && dataSize > 0)
{
if (dataSize >= cur->dataSize)
{
dataSize = cur->dataSize;
}
memcpy(data, cur->data, dataSize);
}
else
{
dataSize = 0;
}
}
else
{
dataSize = 0;
}
return dataSize;
}
//-----------------------------------------------------------------------------
// 名称:BuffPrint
// 功能:打印Buff数据
// 参数:handle,Buff句柄
// printFun,打印接口回调
// 返回:
// 说明:
//-----------------------------------------------------------------------------
void BuffPrint(BuffHandle_t handle)
{
BuffHead_t *head = (BuffHead_t *)handle;
BuffNode_t *cur = NULL;
unsigned long i = 0;
//参数检查
if (handle == NULL)
{
return;
}
if (head->curNums <= 0 || head->printFun == NULL)
{
return;
}
cur = head->addr;
for (i = 0; i < head->curNums; i++)
{
head->printFun("BuffNode[%d]: prev = 0x%08X, addr = 0x%08X, next = 0x%08X\r\n", i, cur->prev, cur, cur->next);
cur = cur->next;
}
return;
}
#endif
2.2 句柄的定义
- 作为返回用户操作的地址,空类型表示已对使用者屏蔽内部实现,不需要关注具体实现。
typedef void* BuffHandle_t;
2.3 外部依赖
- 创建句柄时需要传入malloc和free用于动态创建才可正常返回可用的句柄。
- printf非必要传参,不需要调试则传入NULL即可。
typedef void *(*mallocCb)(unsigned long size);
typedef void (*freeCb)(void *ptr);
typedef void (*printCb)(const char *format, ...);
2.4 功能说明
- BuffCreat:创建一个支持队列/栈链,maxNums表示最大支持的链长,返回一个句柄
- BuffDelete:删除创建的句柄
- BuffIsEmpty/BuffIsFull:返回空或满,满状态由maxNums决定了个数
- BuffGetNums/BuffGetFreeNums:返回当前有效链个数/剩余可用链个数
- BuffPushHead/BuffPushTail:在头/尾增加数据,不限制数据类型,将数据大小传入即可,正常返回已增加的字节大小
- BuffPopHead/BuffPopTail:在头/尾移除数据,参数为接收的缓存和缓存大小,返回实际接收的长度
- BuffRead:cnt为查询的第几包数据,从0开始
- BuffPrint:打印当前链表的链式情况
BuffHandle_t BuffCreat(unsigned long maxNums, mallocCb mallocFun, freeCb freeFun, printCb printFun);
int BuffDelete(BuffHandle_t handle);
unsigned char BuffIsEmpty(BuffHandle_t handle);
unsigned char BuffIsFull(BuffHandle_t handle);
unsigned int BuffGetNums(BuffHandle_t handle);
unsigned int BuffGetFreeNums(BuffHandle_t handle);
int BuffPushTail(BuffHandle_t handle, void *data, unsigned long dataSize);
int BuffPopTail(BuffHandle_t handle, void *data, unsigned long dataSize);
int BuffPushHead(BuffHandle_t handle, void *data, unsigned long dataSize);
int BuffPopHead(BuffHandle_t handle, void *data, unsigned long dataSize);
int BuffRead(BuffHandle_t handle, void *data, unsigned long dataSize, unsigned long cnt);
void BuffPrint(BuffHandle_t handle);
3. 功能测试
3.1 测试函数
int main(void)
{
unsigned char step = 0;
BuffHandle_t handle = NULL;
int dataSize = 0;
int wrData = 0;
int rdData = 0;
int i = 0;
while (1)
{
switch (step)
{
case 0:
if (handle == NULL)
{
handle = BuffCreat(5, malloc, free, printf);
}
printf("BuffCreat handle = 0x%08X\r\n", handle);
step++;
break;
case 1:
dataSize = BuffPushHead(handle, &wrData, sizeof(wrData));
printf("BuffPushHead:%d, size = %d\r\n", wrData++, dataSize);
if (BuffIsFull(handle))
{
for (i = 0; i < BuffGetNums(handle); i++)
{
dataSize = BuffRead(handle, &rdData, sizeof(rdData), i);
printf("BuffRead[%d]:%d, size = %d\r\n", i, rdData, dataSize);
}
BuffPrint(handle);
step++;
}
break;
case 2:
dataSize = BuffPopHead(handle, &rdData, sizeof(rdData));
printf("BuffPopHead:%d, size = %d\r\n", rdData, dataSize);
if (BuffIsEmpty(handle))
{
step++;
}
break;
case 3:
dataSize = BuffPushTail(handle, &wrData, sizeof(wrData));
printf("BuffPushTail:%d, size = %d\r\n", wrData++, dataSize);
if (BuffIsFull(handle))
{
for (i = 0; i < BuffGetNums(handle); i++)
{
dataSize = BuffRead(handle, &rdData, sizeof(rdData), i);
printf("BuffRead[%d]:%d, size = %d\r\n", i, rdData, dataSize);
}
BuffPrint(handle);
step++;
}
break;
case 4:
dataSize = BuffPopTail(handle, &rdData, sizeof(rdData));
printf("BuffPopTail:%d, size = %d\r\n", rdData, dataSize);
if (BuffIsEmpty(handle))
{
step++;
}
break;
case 5:
if (wrData % 2)
{
dataSize = BuffPushHead(handle, &wrData, sizeof(wrData));
printf("BuffPushHead:%d, size = %d\r\n", wrData++, dataSize);
}
else
{
dataSize = BuffPushTail(handle, &wrData, sizeof(wrData));
printf("BuffPushTail:%d, size = %d\r\n", wrData++, dataSize);
}
if (BuffIsFull(handle))
{
for (i = 0; i < BuffGetNums(handle); i++)
{
dataSize = BuffRead(handle, &rdData, sizeof(rdData), i);
printf("BuffRead[%d]:%d, size = %d\r\n", i, rdData, dataSize);
}
BuffPrint(handle);
step++;
}
break;
case 6:
if (wrData % 2)
{
dataSize = BuffPopTail(handle, &rdData, sizeof(rdData));
printf("BuffPopTail:%d, size = %d\r\n", rdData, dataSize);
}
else
{
dataSize = BuffPopHead(handle, &rdData, sizeof(rdData));
printf("BuffPopHead:%d, size = %d\r\n", rdData, dataSize);
}
if (BuffIsEmpty(handle))
{
step++;
}
default:
printf("BuffDelete:0x%08X, ret = %d\r\n", handle, BuffDelete(handle));
handle = NULL;
break;
}
if (handle == NULL)
{
break;
}
}
return 0;
}
3.2 测试结果
BuffCreat handle = 0x006E13D0
BuffPushHead:0, size = 4
BuffPushHead:1, size = 4
BuffPushHead:2, size = 4
BuffPushHead:3, size = 4
BuffPushHead:4, size = 4
BuffRead[0]:4, size = 4
BuffRead[1]:3, size = 4
BuffRead[2]:2, size = 4
BuffRead[3]:1, size = 4
BuffRead[4]:0, size = 4
BuffNode[0]: prev = 0x006E6AB0, addr = 0x006E6BF0, next = 0x006E6BA0
BuffNode[1]: prev = 0x006E6BF0, addr = 0x006E6BA0, next = 0x006E6B50
BuffNode[2]: prev = 0x006E6BA0, addr = 0x006E6B50, next = 0x006E6B00
BuffNode[3]: prev = 0x006E6B50, addr = 0x006E6B00, next = 0x006E6AB0
BuffNode[4]: prev = 0x006E6B00, addr = 0x006E6AB0, next = 0x006E6BF0
BuffPopHead:4, size = 4
BuffPopHead:3, size = 4
BuffPopHead:2, size = 4
BuffPopHead:1, size = 4
BuffPopHead:0, size = 4
BuffPushTail:5, size = 4
BuffPushTail:6, size = 4
BuffPushTail:7, size = 4
BuffPushTail:8, size = 4
BuffPushTail:9, size = 4
BuffRead[0]:5, size = 4
BuffRead[1]:6, size = 4
BuffRead[2]:7, size = 4
BuffRead[3]:8, size = 4
BuffRead[4]:9, size = 4
BuffNode[0]: prev = 0x006E6BF0, addr = 0x006E6AB0, next = 0x006E6B00
BuffNode[1]: prev = 0x006E6AB0, addr = 0x006E6B00, next = 0x006E6B50
BuffNode[2]: prev = 0x006E6B00, addr = 0x006E6B50, next = 0x006E6BA0
BuffNode[3]: prev = 0x006E6B50, addr = 0x006E6BA0, next = 0x006E6BF0
BuffNode[4]: prev = 0x006E6BA0, addr = 0x006E6BF0, next = 0x006E6AB0
BuffPopTail:9, size = 4
BuffPopTail:8, size = 4
BuffPopTail:7, size = 4
BuffPopTail:6, size = 4
BuffPopTail:5, size = 4
BuffPushTail:10, size = 4
BuffPushHead:11, size = 4
BuffPushTail:12, size = 4
BuffPushHead:13, size = 4
BuffPushTail:14, size = 4
BuffRead[0]:13, size = 4
BuffRead[1]:11, size = 4
BuffRead[2]:10, size = 4
BuffRead[3]:12, size = 4
BuffRead[4]:14, size = 4
BuffNode[0]: prev = 0x006E6BF0, addr = 0x006E6BA0, next = 0x006E6B00
BuffNode[1]: prev = 0x006E6BA0, addr = 0x006E6B00, next = 0x006E6AB0
BuffNode[2]: prev = 0x006E6B00, addr = 0x006E6AB0, next = 0x006E6B50
BuffNode[3]: prev = 0x006E6AB0, addr = 0x006E6B50, next = 0x006E6BF0
BuffNode[4]: prev = 0x006E6B50, addr = 0x006E6BF0, next = 0x006E6BA0
BuffPopTail:14, size = 4
BuffDelete:0x006E13D0, ret = 0
2023-03-15 李不清的烦恼,总结篇。