链表-可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;
}
欢迎关注我的公众号