基于双链表的队列和栈操作的实现

基于双链表的队列和栈操作的实现


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 李不清的烦恼,总结篇。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值