链表-可pop任意字节的队列

链表-可pop任意字节的队列

前言

在一般的链表中,数据是存储在node节点中的,每次pop出来的数据是以node为单位的。这篇文章,我们对一般的链表进行改进,可以pop任意字节的数据,也就是说,每次pop的数据数据是以任意字节为单位的,可以pop 10Byte,也可以500Byte,这种方法比较灵活。

原理

针对一般的链表,我们做的改进主要是在每个node中加了一个字段pos,用来标记这个node的data的下标。比如说这个node打data数据大小为10,它的pos就为0,这时候就表示这10个字节都可以用。然后可以pop 2个字节,这时候pos就成了2,表示还有8个字节可以用。

实现的话,我们可以定义这样的结构体:

typedef struct Node
{
    int id;				//每个link的标识符
    int pos;			//记录node数据的下标
    int size;			//记录node数据的总大小
    int num; 			//记录link的node个数,仅头结点使用
    char *addr;			//数据data
    struct Node *next;	//next node
} Node;

对于具体的原理实现,我们可以用一张图片来清楚地说明一下:
在这里插入图片描述

例子

下面是一个完整的的代码例子供参考,可以直接运行:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <queue>

class PkgLink
{
public:
    PkgLink() {m_link_header.clear();}
    ~PkgLink() {}

    typedef struct Node
    {
        int id;
        int pos;
        int size;
        int num; //for head;
        char *addr;
        struct Node *next;
    } Node;

    std::vector<Node *> m_link_header;

    Node *mk_node(int id, char *data, int len)
    {
        Node *node = new Node;
        if (node == NULL) {
            perror("new Node failed\n");
            return NULL;
        }
        if (data != NULL) {
            node->addr = new char[len]();
            if (node->addr == NULL) {
                perror("node->addr = new failed");
                return NULL;
            }
            memcpy(node->addr, data, len);
        }
        else node->addr = NULL;

        node->id = id;
        node->pos = 0;
        node->size = len;
        node->num = 0;
        node->next = NULL;
        return node;
    }

    int free_node(Node *node)
    {
        if (node->addr != NULL)
            delete[] node->addr;
        node->addr = NULL;
        if (node)
            delete node;
        node = NULL;
        return 0;
    }

    int create_head(int id)
    {
        int i = 0;
        for (i = 0; i < (int)m_link_header.size(); i++) {
            if (id == m_link_header[i]->id) {
                break;
            }
        }
        if (i == (int)m_link_header.size()) {
            printf("head[%d] not exist, create it\n", i);
            Node *node = mk_node(id, NULL, 0);
            if (node == NULL) {
                printf("mk_node failed!\n");
            }
            m_link_header.push_back(node);
        }
        else {
            printf("head[%d] exist, can't create it\n", i);
        }

        return 0;
    }

    int push(Node *phead, Node *node)
    {
        Node *p = phead;
        while (p->next != NULL) {
            p = p->next;
        }

        node->next = p->next;
        p->next = node;

        phead->size += node->size;
        phead->num++;
        return 0;
    }

    int push_data(int id, char *data, int len)
    {
        int i = 0;
        for (i = 0; i < (int)m_link_header.size(); i++) {
            if (id == m_link_header[i]->id) {
                break;
            }
        }
        if (i == (int)m_link_header.size()) {
            printf("head[%d] not exist, push_data failed\n", i);
            return -1;
        }

        Node *phead = m_link_header[i];
        Node *node = mk_node(id, data, len);
        if (node == NULL) {
            printf("mk_node failed!\n");
        }
        push(phead, node);
    }

    Node *pop(Node *phead)
    {
        Node *p = phead->next;
        if (p != NULL) {
            phead->size -= p->size - p->pos;
            phead->next = p->next;
            phead->num--;
            p->next = NULL;
            return p;
        }
        return NULL;
    }

    int read_data(Node *phead, char *data, int len)
    {
        if (len > phead->size) {
            printf("pop data len > link size, read data failed\n");
            return -1;
        }

        int i_read = 0;
        Node *p = phead->next;
        while (1) {
            if (p == NULL) {
                printf("p == NULL\n");
                break;
            }

            if (i_read + p->size - p->pos > len) {
                printf(" < len\n");
                memcpy(&data[i_read], &p->addr[p->pos], len - i_read);
                break;
            }

            if (i_read + p->size - p->pos == len) {
                printf(" = len\n");
                memcpy(&data[i_read], &p->addr[p->pos], p->size - p->pos);
                break;
            }

            if (i_read + p->size - p->pos < len) {
                printf(" > len\n");
                memcpy(&data[i_read], &p->addr[p->pos], p->size - p->pos);
                i_read += p->size - p->pos;
                p = p->next;
            }
        }
        return 0;
    }

    int pop_data(Node *phead, char *data, int len)
    {
        if (len > phead->size) {
            printf("pop data len > link size, read data failed\n");
            return -1;
        }

        Node *phead_tmp = phead;
        int i_read = 0;
        while (1) {
            Node *p = phead_tmp->next;
            if (p == NULL) {
                // printf("p == NULL\n");
                break;
            }

            if (i_read + p->size - p->pos > len) {
                // printf(" > len\n");
                memcpy(&data[i_read], &p->addr[p->pos], len - i_read);

                p->pos += len - i_read;
                phead->size -= len - i_read;

                break;
            }

            if (i_read + p->size - p->pos == len) {
                // printf(" = len\n");
                memcpy(&data[i_read], &p->addr[p->pos], p->size - p->pos);

                phead->size -= p->size - p->pos;
                phead_tmp->next = p->next;
                phead->num--;
                free_node(p);
                p = NULL;
                break;
            }

            if (i_read + p->size - p->pos < len) {
                // printf(" < len\n");
                memcpy(&data[i_read], &p->addr[p->pos], p->size - p->pos);
                i_read += p->size - p->pos;

                //p = p->next;
                phead->size -= p->size - p->pos;
                phead_tmp->next = p->next;
                phead->num--;
                free_node(p);
                p = NULL;
            }
        }
        return 0;
    }

    Node *get_head_desc(int i)
    {
        return m_link_header[i];
    }

    int get_memlink_num()
    {
        return m_link_header.size();
    }

    void printf_memlink_status()
    {
        int i = 0;
        for (i = 0; i < (int)m_link_header.size(); i++) {
            Node *phead = m_link_header[i];
            printf(">head: id: %d, pos: %d, num: %d, size: %d, addr: %s\n", phead->id,
                                phead->pos, phead->num, phead->size, phead->addr);
        }
    }

    void printf_link(Node *phead)
    {
        printf(">head: id: %d, pos: %d, num: %d, size: %d, addr: %s\n", phead->id,
                            phead->pos, phead->num, phead->size, phead->addr);
        Node *p = phead->next;
        while (p) {
            printf("node:  id: %d, pos: %d, size: %d\n", p->id, p->pos, p->size);
            p = p->next;
        }
    }

    void delete_link(Node *phead)
    {
        Node *p = phead->next;
        while (phead->next) {
            p = phead->next;
            phead->next = p->next;
            free_node(p);
        }
        free_node(phead);
        printf("delete head\n");
    }

    void delete_memlink()
    {
        int i = 0;
        for (i = 0; i < (int)m_link_header.size(); i++) {
            Node *phead = m_link_header[i];
            delete_link(phead);
        }
        m_link_header.clear();
    }

    void link_test()
    {
        int id = 10;
        create_head(id);

        // push
        char tmp[10] = {0};
        strcpy(tmp, "111222333");
        push_data(id, tmp, strlen(tmp));
        strcpy(tmp, "444555666");
        push_data(id, tmp, strlen(tmp));
        strcpy(tmp, "777888999");
        push_data(id, tmp, strlen(tmp));

        push_data(id, "1", strlen("1"));
        push_data(id, "2", strlen("2"));
        push_data(id, "3", strlen("3"));
        push_data(id, "4", strlen("4"));
        push_data(id, "5", strlen("5"));
        push_data(id, "6", strlen("6"));
        push_data(id, "7", strlen("7"));

        id = 20;
        create_head(id);
        push_data(id, "8", strlen("8"));
        push_data(id, "9", strlen("9"));
        push_data(id, "10", strlen("10"));

        id = 30;
        create_head(id);
        push_data(id, "11", strlen("11"));
        push_data(id, "12", strlen("12"));
        push_data(id, "13", strlen("13"));


        printf_memlink_status();
        int memlink_num = get_memlink_num();
        printf("\nmemlink_num = %d\n", memlink_num);
        for (int i = 0; i < memlink_num; i++) {
            Node *head = get_head_desc(i);
            printf_link(head);
            if (head->id == 10) {
                //pop
                Node *p4 = pop(head);
                printf("pop size = %d\n", p4->size);
                free_node(p4);

                char read_tmp[11 + 1] = {0};
                pop_data(head, read_tmp, 11);
                printf("read_data = %s\n", read_tmp);

                char read_tmp2[8 + 1] = {0};
                pop_data(head, read_tmp2, 8);
                printf("read_data = %s\n", read_tmp2);
                printf_link(head);
            }
        }

        delete_memlink();
    }
};

int main()
{
    PkgLink pl;
    pl.link_test();

    return 0;
}

欢迎关注我的公众号
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chasentech

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值