基數樹的簡單實現-二

對之前的基數樹做了修改,減少空間佔用。

頭文件:

#pragma once
#include<stdlib.h>
#include<stdio.h>

#define MEMPAGE 4096
#define INIT_POOL_SIZE (MEMPAGE*1)	//初始內存池大小
#define RADIX_INSERT_VALUE_OCCUPY -1		//該節點已被佔用
#define RADIX_INSERT_VALUE_SAME -2		//插入了相同的值
#define RADIX_DELETE_ERROR -3			//刪除錯誤
typedef unsigned int ptr_t;
typedef unsigned int uint32;

#define BITS 2
//返回key指定位的值,位數由BITS指定
#define CHECK_BITS(key,pos) ((((unsigned int)(key))<<sizeof(int)*8-(pos+1)*BITS)>>(sizeof(int)*8-BITS))
//基數樹節點
typedef struct radix_node_t radix_node_t;
struct radix_node_t {
	radix_node_t* child[4];
	radix_node_t* parent;
};
typedef struct radix_leafnode_t {
	struct radix_leafnode_t* next;
	uint32 key;//路徑
	ptr_t value;//值
}radix_leafnode_t;

//內存池結構,放在內存池的前段
typedef struct radix_pool {
	struct radix_pool* next;
	struct radix_pool* prev;
	char* start;
	size_t size;
}radix_pool, * pool_t;
//基數樹管理結構
typedef struct radix_tree_t {
	//指向根節點
	radix_node_t* root;
	//內存池指針,(一頁內存)
	pool_t pool;
	//儲存已分配但不在樹中的節點(雙向鏈表,這裏儲存其中的一個節點)
	radix_node_t* free;
	//葉節點內存池
	pool_t leafpool;
	//儲存已分配但不在樹中的葉節點
	radix_leafnode_t* lfree;
}radix_tree_t;

//內存池擴大函數,num:新內存池的大小,=-1使用默認值,單位:頁
pool_t get_new_pool(radix_tree_t* t, int num);

//創建一個節點,從內存池中取出可以使用的節點
radix_node_t* radix_node_alloc(radix_tree_t* t);

//創建管理結構
radix_tree_t* radix_tree_create();

//插入
int radix_tree_insert(radix_tree_t* t, uint32 key, ptr_t value);

//由於插入時會創建很多節點,爲了提高速度這裏只會刪除最底層的指定節點
int radix_tree_delete(radix_tree_t* t, uint32 key);

//打印函數,會打印出所有底層節點的長度
//void radix_print(radix_node_t* node);

//節點查找函數
ptr_t radix_tree_find(radix_tree_t * t, uint32 key);
pool_t get_new_leafpool(radix_tree_t* t, int num);
radix_leafnode_t* radix_leafnode_alloc(radix_tree_t* t);
//遍歷葉節點,返回葉節點數量
int radix_tree_traversal(radix_tree_t* t);
//遍歷葉節點,並指定操作
int radix_tree_traversal_fun(radix_tree_t* t, void(*fun)(uint32, uint32));

實現文件:

#include"radixTree.h"
static radix_leafnode_t* last_leafnode;
static int radix_tree_height = sizeof(ptr_t) * 8 / BITS;

//內存池擴大函數,num:新內存池的大小,=-1使用默認值,單位:頁
pool_t get_new_pool(radix_tree_t*t, int num)
{
	if (num <=0 )num = INIT_POOL_SIZE;
	else num *= MEMPAGE;
	pool_t pool = (pool_t)malloc(num);
	if (pool == NULL)return NULL;
	pool->next = t->pool->next;
	pool->prev = t->pool;
	t->pool->next->prev = pool;
	t->pool->next = pool;
	t->pool = pool;
	//格式化,將申請的內存全部設置爲節點
	radix_node_t * node=(radix_node_t*)((char*)pool + sizeof(radix_pool));
	int i;
	for (i = 0; i < (num - sizeof(radix_pool)-1) / sizeof(radix_node_t); ++i) {
		node[i].parent = &(node[i + 1]);
	}
	node[i++].parent = NULL;
	t->free = node;
	pool->start = (char*)((char*)node+sizeof(radix_node_t)*i);
	pool->size =  num-sizeof(radix_node_t)*i-sizeof(radix_pool);
	return pool;
}
//葉節點內存池擴大
pool_t get_new_leafpool(radix_tree_t* t, int num)
{
	if (num <=0)num = INIT_POOL_SIZE;
	else { num *= MEMPAGE; }
	pool_t leafpool = (pool_t)malloc(num);
	if (leafpool == NULL)return NULL;
	leafpool->next = t->leafpool->next;
	leafpool->prev = t->leafpool;
	t->leafpool->next->prev = leafpool;
	t->leafpool->next = leafpool;
	t->leafpool = leafpool;
	radix_leafnode_t* node = (radix_leafnode_t*)((char*)leafpool + sizeof(radix_pool));
	int i;
	for (i = 0; i < (num - sizeof(radix_pool) - 1) / sizeof(radix_leafnode_t); ++i) {
		node[i].next = &(node[i + 1]);
	}
	node[i++].next = NULL;
	t->lfree = node;
	leafpool->start = (char*)((char*)node + sizeof(radix_leafnode_t) * i);
	leafpool->size = num - sizeof(radix_leafnode_t) * i - sizeof(radix_pool);
	return leafpool;
}
//葉節點獲取
radix_leafnode_t* radix_leafnode_alloc(radix_tree_t* t)
{
	radix_leafnode_t* node;
	if (t->free != NULL) {
		node = t->lfree;
		t->lfree = node->next;
	}
	else {
		if (t->leafpool->size < sizeof(radix_leafnode_t)) {
			get_new_leafpool(t, -1);
		}
		if (t->lfree != NULL) {
			node = t->lfree;
			t->lfree = node->next;
		}
		else {
			node = (radix_leafnode_t*)t->leafpool->start;
			t->leafpool->start += sizeof(radix_leafnode_t);
			t->leafpool->size -= sizeof(radix_leafnode_t);
		}
	}
	node->next = (radix_leafnode_t*)NULL;
	node->key = (uint32)NULL;
	node->value = (ptr_t)NULL;
	return node;
}

//創建一個節點,從內存池中取出可以使用的節點
radix_node_t* radix_node_alloc(radix_tree_t* t)
{
	radix_node_t* node;
	if (t->free != NULL) {//從free中提取節點
		node = t->free;
		t->free = node->parent;
	}
	else {//在內存池中尋找可以使用的內存
		if (t->pool->size < sizeof(radix_node_t)) {//如果剩餘空間不夠分配,則重新分配
			get_new_pool(t, -1);
		}
		if (t->free != NULL) {//從free中提取節點
			node = t->free;
			t->free = node->parent;
		}
		else {
			node = (radix_node_t*)t->pool->start;
			t->pool->start += sizeof(radix_node_t);
			t->pool->size -= sizeof(radix_node_t);
		}
	}
	node->child[0] = NULL;
	node->child[1] = NULL;
	node->child[2] = NULL;
	node->child[3] = NULL;
	node->parent = NULL;
	return node;
}
//創建管理結構
radix_tree_t* radix_tree_create()
{
	int i;
	radix_tree_t* tree = (radix_tree_t*)malloc(sizeof(radix_tree_t));
	if (tree == NULL)return NULL;
	tree->pool = (pool_t)malloc(INIT_POOL_SIZE);
	if (tree->pool == NULL) { free(tree); return NULL; }
	tree->leafpool = (pool_t)malloc(INIT_POOL_SIZE);
	if (tree->leafpool == NULL) { free(tree->pool); free(tree); return NULL; }

	radix_node_t* node = (radix_node_t*)((char*)tree->pool + sizeof(radix_pool));
	tree->pool->next = tree->pool;
	tree->pool->prev = tree->pool;
	for (i = 1; i < (INIT_POOL_SIZE - sizeof(radix_pool) - 1) / sizeof(radix_node_t); ++i) {
		node[i].parent = &node[i + 1];
	}
	node[i++].parent = NULL;
	node[0].child[0] = NULL;
	node[0].child[1] = NULL;
	node[0].child[2] = NULL;
	node[0].child[3] = NULL;
	node[0].parent = NULL;
	i *= sizeof(radix_node_t);
	tree->pool->start = ((char*)node +i);
	tree->pool->size = INIT_POOL_SIZE - sizeof(radix_pool) - i;
	//葉節點
	radix_leafnode_t* lnode= (radix_leafnode_t*)((char*)tree->leafpool + sizeof(radix_pool));
	tree->leafpool->next = tree->leafpool;
	tree->leafpool->prev = tree->leafpool;
	for (i = 1; i < (INIT_POOL_SIZE - sizeof(radix_pool) - 1) / sizeof(radix_leafnode_t); ++i) {
		lnode[i].next = &(lnode[i + 1]);
	}
	lnode[i++].next = NULL;
	lnode[0].key = (uint32)NULL;
	lnode[0].next = lnode;
	lnode[0].value = (ptr_t)NULL;
	last_leafnode = lnode;
	i *= sizeof(radix_leafnode_t);
	tree->leafpool->start = ((char*)lnode + i);
	tree->leafpool->size = INIT_POOL_SIZE - sizeof(radix_pool) - i;
	tree->free = &node[1];
	tree->lfree = &lnode[1];
	tree->root = node;
	return tree;
}

//插入
int radix_tree_insert(radix_tree_t* t, uint32 key, ptr_t value)
{
	int i, temp;
	radix_node_t* node, * child;
	radix_leafnode_t* lnode;
	node = t->root;
	for (i = 0; i < radix_tree_height-1; i++) {
		temp = CHECK_BITS(key, i);
		if (!node->child[temp]) {
			child = radix_node_alloc(t);
			if (child==NULL)return -1;
			child->parent = node;
			node->child[temp] = child;
			node = node->child[temp];
		}
		else {
			node = node->child[temp];
		}
	}
	temp = CHECK_BITS(key, i);
	lnode = (radix_leafnode_t*)node->child[temp];
	if (lnode != NULL)return -1;
	lnode = radix_leafnode_alloc(t);
	if (lnode == NULL)return -1;

	lnode->next = last_leafnode->next;
	last_leafnode->next = lnode;
	last_leafnode = lnode;
	node->child[temp] =(radix_node_t*) lnode;
	if (lnode->value == value)return RADIX_INSERT_VALUE_SAME;
	if (lnode->value != (ptr_t)NULL)return RADIX_INSERT_VALUE_OCCUPY;
	lnode->value = value;
	lnode->key = key;
	return 0;
}

//由於插入時會創建很多節點,爲了提高速度這裏只會刪除最底層的指定節點
int radix_tree_delete(radix_tree_t* t, uint32 key)
{
	radix_node_t* node = t->root, * par;
	int i = 0, temp = 0;
	for (i = 0; i < radix_tree_height - 1; ++i) {
		temp = CHECK_BITS(key, i);
		node = node->child[temp];
		if (node == NULL) return RADIX_DELETE_ERROR;
	}
	temp = CHECK_BITS(key, i);
	radix_leafnode_t* lnode;
	lnode = (radix_leafnode_t*)node->child[temp];
	if (lnode == NULL)return RADIX_DELETE_ERROR;
	node->child[temp] = NULL;
	//將lnode迴歸內存池
	lnode->next = t->lfree->next;
	t->lfree->next = lnode;
	return 0;
}

//節點查找函數
//key爲索引,返回葉節點被查找到的值
ptr_t radix_tree_find(radix_tree_t* t, uint32 key)
{
	int i = 0, temp;
	radix_node_t* node;
	node = t->root;
	for (i; i < radix_tree_height - 1; ++i) {
		temp = CHECK_BITS(key, i);
		node = node->child[temp];
		if (node == NULL)return 0;
	}
	temp = CHECK_BITS(key, i);
	radix_leafnode_t* lnode;
	lnode = (radix_leafnode_t*)node->child[temp];
	if (lnode == NULL)return 0;
	return lnode->value;
}

//遍歷葉節點,打印節點內容,返回葉節點數量
int radix_tree_traversal(radix_tree_t* t)
{
	int i = 0;
	radix_leafnode_t* temp = last_leafnode,*node=last_leafnode;
	do {
		printf("key:%x, value:%x\n", node->key, node->value);
		node = node->next;
		i++;
	} while (node != temp);
	return i;
}

//遍歷葉節點,可以傳入一個函數進行處理
int radix_tree_traversal_fun(radix_tree_t* t, void(*fun)(uint32,uint32))
{
	int i = 0;
	radix_leafnode_t* temp = last_leafnode, * node = last_leafnode;
	do {
		printf("key:%x, value:%x\n", node->key, node->value);
		fun(node->key,node->value);
		node = node->next;
		i++;
	} while (node != temp);
	return i;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章