欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

一种高效查找树-radix的实现

程序员文章站 2022-07-14 20:11:37
...

1.引言

我们知道,unoredered_map是一种查找时间复杂度o(1)的数据结构,经常用在数据查找相关的地方,但是在使用unordered_map进行数据查找时,hash冲突是一件令人很头疼的事情,因为hash冲突导致unordered_map的查找效率降低。radix就是一种适用于基于二进制表示的键值的查找树,在数据量增大的时候不会影响其查找效率。由于我在一个项目中发现使用unordered_map在处理大量数据的时候效率并不高,因此来学习radix,本文将介绍radix的原理,并将我所实现并用于项目的代码分享出来。

2.介绍

radix是一种基于前缀树的思想的适用于基于二进制表示的键值的查找树。用图来解释直观明了。
一种高效查找树-radix的实现

3.实现

在使用radix这种数据结构的时候,会涉及到多次申请空间的过程,unordered_map使用的时STL自己的allocator。我使用的是boost中pool的一个对象池,因为每次申请的对象都是一样大的。

如何插入数据

radix是一种很巧妙的数据结构(感觉想出来的人是个天才),并且很简单,难的地方可能就是这个插入数据部分。难点在于每次如何获取Key值的二进制位上的一位、两位或多位。这个视具体情况,为了不让整个树层数过深,我采用每次获取两二进制的方法来实现的。
话不多说,上代码

#define CHECK_BITS(key,pos) ((((unsigned int)(key))<<sizeof(int)*8-((pos)+1)*BITS)>>(sizeof(int)*8-BITS))

这行代码负责每次获取两位二进制的值。

#pragma once
#include<stdlib.h>
#include<stdio.h>
#include<iostream>
#include<boost\pool\pool.hpp>
#include<stddef.h>
using namespace std;

#define RADIX_INSERT_VALUE_OCCUPY -1	//该节点已被占用
#define RADIX_INSERT_VALUE_SAME -2		//插入了相同的值
#define RADIX_DELETE_ERROR -3			//删除错误

typedef int k_type;
typedef char* v_type;

#define BITS 2
const int radix_tree_height = sizeof(k_type) * 8 / BITS;//树的高度
//返回key中由pos指定的位的值,位数由BITS指定,每次获取两位二进制的值
#define CHECK_BITS(key,pos) ((((unsigned int)(key))<<sizeof(int)*8-((pos)+1)*BITS)>>(sizeof(int)*8-BITS))
//基数树节点
struct radix_node_t {
	radix_node_t* child[4];//四个指向下层节点的指针数组,分别指向节点储存值为00 01 10 11的节点。
	radix_node_t* parent;//记录夫结点
	v_type value;//节点储存的值
};
//基数树头节点
struct radix_head {
	//根节点
	radix_node_t* root;
	//储存已分配但不在树中的节点(双向链表,这里储存其中的一个节点)
	size_t number;//存储目前有多少个存进来的节点。
};

class radix
{
public:
	radix()
		:_pool(sizeof(radix_node_t))
	{
		t = (radix_head*)malloc(sizeof(radix_head));
		t->number = 0;
		t->root = (radix_node_t*)_pool.malloc();
		for (int i = 0; i < 4; i++)
			t->root->child[i] = nullptr;
		t->root->value = nullptr;
	}
	int insert(k_type key, v_type value)
	{
		int i, temp;
		radix_node_t* node, *child;
		node=t->root;
		for (i = 0; i < radix_tree_height; i++) {
			//从低位开始获取每两位的值
			temp = CHECK_BITS(key, i);

			if (node->child[temp] == nullptr) {
				child = (radix_node_t*)_pool.malloc();
				if (!child)return NULL;

				//显示构造
				for (int i = 0; i < 4; i++)
					child->child[i] = nullptr;
				child->value = nullptr;

				child->parent = node;
				node->child[temp] = child;
				node = node->child[temp];
			}
			else {
				node = node->child[temp];
			}
		}
		//已经插入返回-2
		if (node->value == value)return RADIX_INSERT_VALUE_SAME;
		//插入节点有其他值返回-3
		if (node->value != nullptr)return RADIX_INSERT_VALUE_OCCUPY;
		node->value = value;
		//计数加1
		++t->number;
		return 0;
	}
	int Delete(k_type key)
	{
		radix_node_t* tar = find(key);
		if (tar == nullptr)
		{
			cout << "删除失败" << endl;
			return RADIX_DELETE_ERROR;//返回-3,删除失败,没有该数据
		}
		else
		{
			radix_node_t* par = tar->parent;
			//printf("真正删除%d\n", tar->value->_pageid);
			tar->value = nullptr;
			_pool.free(tar);
			--t->number;
			for (int i = 0; i < 4; i++)
			{
				if (par->child[i] == tar)
				{
					par->child[i] = nullptr;
					break;
				}
			}
			//printf("减少到%d个\n", t->number);
		}
		return 0;
	}
	void print()
	{
		radix_node_t* node = t->root;
		_radix_print(node);
	}
	radix_node_t* find(k_type key)
	{
		int i = 0, temp;
		radix_node_t* node;
		node = t->root;
		while (node && i < radix_tree_height) {
			temp = CHECK_BITS(key, i++);
			node = node->child[temp];
		}
		if (node == nullptr||node->value==nullptr)
			return nullptr;
		return node;
	}
private:
	void _radix_print(radix_node_t* node)
	{
		if (node == nullptr)return;
		if (node->value != nullptr)
			printf("%s\n", node->value);
		_radix_print(node->child[0]);
		_radix_print(node->child[1]);
		_radix_print(node->child[2]);
		_radix_print(node->child[3]);
	}
private:
	boost::pool<> _pool;
	radix_head* t;
};
相关标签: 数据结构 radix