ptree数据结构分析

2023-11-22 20:58
文章标签 分析 数据结构 ptree

本文主要是介绍ptree数据结构分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!



1.位置

使用时包含头文件ptree.h   还要编译ptree.c文件。


2.数据结构

2.1struct ptree

/* Patricia tree top structure. */
struct ptree
{/* Top node. */struct ptree_node *top;/* Maximum key size allowed (in bits). */u_int32_t max_key_len;/* Identifier of the FIB the tree is for - default is 0 */u_int32_t id;
};

/* Patricia tree node structure. */
struct ptree_node
{struct ptree_node *link[2];
#define  p_left      link[0]
#define  p_right     link[1]/* Tree link. */struct ptree *tree;struct ptree_node *parent;/* Lock of this radix. */u_int32_t lock;/* Each node of route. */void *info;/* Key len (in bits). */u_int32_t key_len;/* Key begins here. */u_int8_t key [1];
};



2.2struct ptree_node

3.1. PAT tree介绍

3.1.1. 应用
  1. PAT tree是目前信息检索领域应用十分成功的索引方法。主要在字符串子串匹配上有着非常优异的表现,采用半无限长字串作为字符串的查找结构。当有了一个文档的所有半无限长字串的集合,该文档的任何子串都可以定位为某一半无限长字串的前缀。
  2. 半无限长字串:就是一串字符的顺序子串(从一给定点到串的结尾)。
    比如一个字符串CUHK,它的半无限长字串:CUHK、UHK、HK和K。
3.1.2. 基本定义
  1. PAT tree是由所有可能的无限长字串所构成的一棵树。在PAT tree中通过逐个鉴别半无限长字串的二进制位来判断树中的分支,如果二进制位是0则产生左分支,是1则产生右分支,因此PAT tree是一棵二叉树,树的结点分为外部结点和内部结点。
  2. 外部结点:也就是树的叶子结点,用来记录半无限长字串的首字符在完整半无限长字串中的开始位置(字符索引)和半无限长字串出现的频次。
  3. 内部结点:除了叶子结点的所有结点,这个结点是自动添加的,用来记录索引的路径,它有三个基本的数据项:左指针、右指针、比较位。
  4. 左指针:指向该结点的左子树。
  5. 右指针:指向该结点的右子树。
  6. 比较位:记录的是从根结点到达该结点的所有位串最后一个不相同位的位置。用来指示下一步搜索的方向:当位串的比较位为0 时,搜索转向左子树,当该比较位为1时,搜索转向右子树。
3.1.3. 原理说明
  1. 将所有半无限长字串,用二进制位来表示。它们之间的比较也是以bit位为单位来进行比较。
  2. 规定所有半无限长字串的长度要一致,结尾没有的空字符用0来填充。
3.1.4. 举例说明
  • CUHK     01000011   01010101   01001000   01001011                                       
  • UHK0      01010101   01001000   01001011   00000000
  • HK00      01001000   01001011   00000000   00000000
  • K000       01001011   00000000   00000000   00000000

图 1  PAT tree示例图

3.1.5. 检索过程
  1. 检索过程就是根据查询字串在PAT tree中从根结点寻找路径的过程。当比较完查询字串所有位置后,搜索路径达到PAT tree的某一结点。
  2. 若该结点为叶子结点,则判断查询字串是否为叶子结点所指的半无限长字串的前缀,如果判断为真,则查询字串出现的频次即为叶子结点中记录的频次;否则,该查询字串不存在。
  3. 若该结点为内部结点,则判断查询字串是否为该结点所辖子树中任一叶子结点所指的半无限长字串的前缀。如果判断为真,该子树中所有叶子结点记录的频次之和即为查询字串的出现频次。否则,查询字串不存在。
  4. 这样,通过PAT tree可以检索原文中任意长度的字串及其出现频次。 

3.2.ptree.c文件中PAT tree与一般意义上PAT tree的差异

  1. 数据结构不同。
  2. ptree.c文件中存储的关键信息长度可以不同。
  3. 对于ptree.c文件中的PAT tree内部结点有可能是我们手动添加的结点。
  4. 利用ptree.c文件中的代码CUHK、UHK、HK和K的存储效果为2图。


图2 ptree.c示例图 

3.3. ptree.c文件中PAT tree的介绍

3.3.1. 数据结构
  • PAT tree头:即struct ptree,用来管理PAT tree。
  • 数据结点:即struct ptree_node。分为通配虚结点和信息结点。
    1. 通配虚结点:为了使整棵树链接起来,自动添加的结点,结点中的关键字为它左、右子树关键字的公共部分。
    2. 信息结点:用户手动添加的结点。

图 3 ptree.h数据结构图 

3.3.2. 设计原理
  1. 查找最长匹配的结点:
    a. 从头结点开始依次向下比较,取两个key_len中较小值为关键字的比较长度;
    b. 如果,比较到某结点不匹配,那么它的父结点为最长匹配结点(父结点为NULL表示没有匹配到结点),直到把待匹配结点的key_len匹配完。
  2. 添加结点:
    a. 从头结点开始,查看是否有完全匹配的结点,如果有,不添加新结点。
    b. 如果没有,获取最长匹配的结点。
        如果该结点是第一个添加的结点,把该结点定义为头结点。
        如果最长匹配的结点为叶子结点,把待匹配结点添加为该叶子结点的孩子结点。
        如果最长匹配的结点的孩子结点为叶子结点,把待匹配的结点插入到最长匹配结点和它的孩子结点之间。
        否则,需要添加通配结点。
  3. 删除结点:
    待删除结点的lock属性应等于0,info为NULL且左、右子树不能都存在,才可进行删除操作。
  4. 结点的lock属性: 
    每个结点都包含一个lock成员,称为结点的访问计数。
    新创建的信息结点没有进行任何操作时,它的lock值等于1。
    自动添加的通配结点没有进行任何操作时,它的lock值等于0。
    添加新结点时,如果存在完全匹配的结点,不添加结点,但原结点的lock值会+1。
    每次访问(遍历、查找、添加)该结点时调用ptree_lock_node()函数使lock值+1,访问结束后调用ptree_unlock_node()函数lock值-1,使之恢复原值。 
3.3.3. 举例说明 
  1. 有三个结点,假设key_len都为3(bit),关键字的前三个bit位分别是:010、100和101,其中结点1和结点2均为通配结点。
    结点1:key_len == 0(bit);
    结点2:key_len == 1(bit)。
  • 向PAT tree中增加第一个结点010......,如右图4:

          图 4
  • 向PAT tree中增加第二个结点100......,如右图5:
  • 图 5
  • 说 明:当向PAT tree中增加结点100......时,由于和当前存在结点的第一个bit位就不匹配,所以在增加结点的同时,会自动产生一个key_len = 0(bit)的通配虚结点,逻辑图如上图所示,通配虚结点的p_left指针,指向不匹配的bit位为0的结点,p_right指针指向不匹配的bit位 为1的结点。
  • 向PAT tree中增加第三个结点101......,如右图6:

 图 6
说明:向PAT tree中增加结点101......时,当匹配到第二bit位时,没有结点可以继续匹配,在增加结点的同时,会自动产生一个key_len = 2(bit),key值为10(含有2个bit位)的通配虚结点,逻辑图如上图所示,通配结点的p_left指针,指向不匹配的bit位为0的结点100......,p_right指针指向不匹配的bit位为1的结点101......。

4. 接口

4.1 ptree_init

  • 原型
         struct ptree *ptree_init (u_int16_t max_key_len)
  • 功能
         初始化树结构
  • 参数
         max_key_len:树节点key的最大比特位长度
  • 返回值
         成功返回初始化好的树结构体指针,失败返回NULL

4.2 ptree_top

  • 原型
         struct ptree_node *ptree_top (struct ptree *tree)
  • 功能
         获得树的根节点并加锁
  • 说明
         主要用于遍历整个树的节点
  • 参数
         tree:树结构指针
  • 返回值
         成功返回加锁了的树根节点,失败返回NULL

4.3 ptree_next

  • 原型
         struct ptree_node *ptree_next (struct ptree_node *node)
  • 功能
         返回当前节点的下一个节点
  • 参数
         node:树节点指针
  • 返回值
         成功返回加锁了的当前节点的下一节点,失败返回NULL

4.4 ptree_next_until

  • 原型
        struct ptree_node *ptree_next_until (struct ptree_node *node1, struct ptree_node *node2)
  • 功能
        返回当前节点的下一个节点
  • 说明
        若找到下一节点前遇到node2,返回NULL
  • 参数
         node1:树节点指针1; node2:树节点指针2
  • 返回值
         成功返回加锁了的当前节点的下一节点,失败返回NULL

4.5 ptree_node_get

  • 原型
         struct ptree_node *ptree_node_get (struct ptree *tree, u_char *key, u_int16_t key_len)
  • 功能
         增加树节点到树
  • 说明
         若key被包含在已有树节点中,则返回相应节点
  • 参数
         tree:树结构指针; key:键值; key_len:key比特位长度
  • 返回值
         成功返回加了锁的树节点指针,失败返回NULL

4.6 ptree_node_lookup

  • 原型
         struct ptree_node *ptree_node_lookup (struct ptree *tree, u_char *key, u_int16_t key_len)
  • 功能
         查找节点
  • 说明
         根据key在树中查找相应节点,找到包含key值且info非空,key_len相等的则加锁并返回相应节点,找不到则返回NULL
  • 参数
         tree:树结构指针; key:键值; key_len:key比特位长度(key_len >= 树节点key长度)
  • 返回值
         成功返回加了锁的树节点指针,失败返回NULL

4.7 ptree_lock_node

  • 原型
         struct ptree_node *ptree_lock_node (struct ptree_node *node)
  • 功能
         对node加锁
  • 参数
         node:树节点指针
  • 返回值
         成功返回加了锁的树节点指针

4.8 ptree_node_match1

  • 原型
         struct ptree_node *ptree_node_match1 (struct ptree *tree, u_char *key, u_int16_t key_len)
  • 功能
         查找节点  
  • 说明
         根据key在树中查找相应节点,返回树节点中的key值匹配查找key值的树节点(不关心info),否则返回NULL
  • 参数
         tree:树结构指针; key:键值; key_len:key比特位长度
  • 返回值
         成功返回加了锁的匹配树节点指针(该节点key_len 不小于 搜索key_len),否则返回NULL

4.9 ptree_node_match

  • 原型
         struct ptree_node *ptree_node_match (struct ptree *tree, u_char *key, u_int16_t key_len)
  • 功能
         查找节点
     
  • 说明
         根据key在树中查找相应节点(查找key的值必须大于等于树节点的值,否则直接返回NULL),返回树节点中的key值匹配查找key值且数据节点(info指针)非空的树节点,否则返回NULL
  • 参数
          tree:树结构指针; key:键值; key_len:key比特位长度
  • 返回值
         成功返回加了锁的匹配树节点指针(该节点key_len 不大于 搜索key_len),否则返回NULL

4.10 ptree_node_free

  • 原型
         void ptree_node_free (struct ptree_node *node)
  • 功能
         释放树节点空间
  • 参数
         node:树节点指针
  • 返回值
         无

4.11 ptree_finish

  • 原型
         void ptree_finish (struct ptree *tree)
  • 功能
         释放树
  • 参数
         tree:树结构指针
  • 返回值
         无

4.11 ptree_unlock_node

  • 原型
         void ptree_unlock_node (struct ptree_node *node)
  • 功能
         释放树节点锁,如果锁值为0,删除此节点
  • 参数
         node:树节点指针
  • 返回值
         无

4.12 ptree_node_delete

  • 原型
         void ptree_node_delete (struct ptree_node *node)
  • 功能
         从树中删除节点
  • 参数
        node:树节点指针
  • 返回值
         无

4.13 ptree_node_delete_all

  • 原型
        void ptree_node_delete_all (struct ptree *tree)
  • 功能
         删除树中所有节点
  • 参数
         tree:树结构指针
  • 返回值
         无

4.14 ptree_has_info

  • 原型
    int ptree_has_info (struct ptree *tree)
  • 功能
         检查树中节点 info是否设置
  • 参数
         tree:树结构指针
  • 返回值
         1:info设置 0:树空或info未设置

4.15 ptree_key_copy

  • 原型
        void ptree_key_copy (struct ptree_node *node, u_char *key, u_int16_t key_len)
  • 功能
         为node设置key值
  • 参数
        node:树节点指针 key:键值 key_len:键值比特位长度
  • 返回值
         无

4.16 ptree_bit_to_octets

  • 原型
        int ptree_bit_to_octets (u_int16_t key_len)
  • 功能
         将比特位长度转换成字节长度
  • 参数
         key_len:比特位长度
  • 返回值
         字节长度

4.17 ptree_key_match

  • 原型
         int ptree_key_match (u_char *np, u_int16_t n_len, u_char *pp, u_int16_t p_len)
  • 功能
         key值匹配
  • 说明
        匹配key(n_len 不大于p_len),如果np的前n_len位与pp的前n_len位相等返回true,否则返回false
  • 参数
         np:key1 n_len; key1比特位长度 pp:key2; p_len:key2比特位长度
  • 返回值
         如果np包含pp返回true,否则返回false

4.18 ptree_check_bit

  • 原型
         int ptree_check_bit (struct ptree *tree, u_char *p, u_int16_t key_len)
  • 功能
         根据键值返回0或1
  • 说明
         根据key值返回0,1决定搜索或添加方向(左孩子或右孩子)
  • 参数
         tree:树结构指针; p:键值指针; ken_len:键值长度;
  • 返回值
         0, 1 (用于判断左孩子还是右孩子)

4.19 ptree_node_match_exclude

  • 原型
        struct ptree_node * ptree_node_match_exclude (struct ptree *pt, u_char *key1, u_int16_t key_len1, u_char *key2, u_int16_t key_len2)
  • 功能
         保留未用
  • 参数
         保留

使用说明

1.首先调用ptree_init初始化tree结构

2.然后调用ptree_node_get添加节点

3.通过调用ptree_node_lookup查找匹配key的节点

3调用ptree_node_delete删除指定节点

4.最后调用ptree_finish释放节点

备注:lock索引值在每次有返回节点时都会加一,在处理完该节点后记得ptree_unlock_node该节点!

示例

1.程序添加节点示意图如下:

2.运行结果

3.代码
#include <stdio.h>
#include "ptree.h"
#define BUF_SIZE 3
/*封装的信息打印函数*/
void my_printf(struct ptree_node *node);
/*封装的打印所有树节点信息函数*/
void show_all_node(struct ptree *tree);int main(void)
{struct ptree * tree;int i;char *str = "****str******";u_char buf[BUF_SIZE][3] = {{192, 168, 1},{20, 16, 5}, {10, 8, 26}} ;u_char buf_1[] = {10, 8};u_char buf_2[] = {16};struct ptree_node *node = NULL, *next = NULL;i= 0;/* 初始化树 */tree = ptree_init (32);if (NULL == tree)printf("tree is null \n");while(i < BUF_SIZE){	/* 将节点加入到树*/node = ptree_node_get (tree, buf[i], 24);if(NULL == node)goto finish;node->info = str;i++;show_all_node(tree);}/* 将节点加入到树*/ptree_node_get (tree, buf_1, 16);show_all_node(tree);/* 将节点加入到树*/ptree_node_get (tree, buf_2, 8);show_all_node(tree);/*查找节点 */node = ptree_node_lookup(tree, (u_char *)buf[1], 24);if (NULL != node){printf("-----------------del--------------\n");ptree_unlock_node(node);my_printf(node);		printf("-----------------del--------------\n");        }/* 从树中删除节点 */node->info = NULL;/*info为空才能删除*/ptree_unlock_node(node);/*遍历树节点*/show_all_node(tree);finish:/* 释放树 */ptree_finish (tree);return 0;	
}
void show_all_node(struct ptree *tree)
{/*遍历树节点*/int num;struct ptree_node *node = NULL, *next = NULL;num = 0;printf("-----------------traverse--------------\n");node = ptree_top (tree);while (NULL != node){   /* 获取下一个节点 */    next = ptree_next (node);my_printf(node);         node = next;num++;}printf("num = %d\n", num);
}void my_printf(struct ptree_node *node)
{int i, j;i = 0;j = ptree_bit_to_octets(node->key_len);while(i < j){printf("%d.", node->key[i]);i++;}printf("\tlock = %d\tkey_len = %d\n", node->lock, node->key_len);}






这篇关于ptree数据结构分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/412862

相关文章

Mysql的主从同步/复制的原理分析

《Mysql的主从同步/复制的原理分析》:本文主要介绍Mysql的主从同步/复制的原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录为什么要主从同步?mysql主从同步架构有哪些?Mysql主从复制的原理/整体流程级联复制架构为什么好?Mysql主从复制注意

java -jar命令运行 jar包时运行外部依赖jar包的场景分析

《java-jar命令运行jar包时运行外部依赖jar包的场景分析》:本文主要介绍java-jar命令运行jar包时运行外部依赖jar包的场景分析,本文给大家介绍的非常详细,对大家的学习或工作... 目录Java -jar命令运行 jar包时如何运行外部依赖jar包场景:解决:方法一、启动参数添加: -Xb

Apache 高级配置实战之从连接保持到日志分析的完整指南

《Apache高级配置实战之从连接保持到日志分析的完整指南》本文带你从连接保持优化开始,一路走到访问控制和日志管理,最后用AWStats来分析网站数据,对Apache配置日志分析相关知识感兴趣的朋友... 目录Apache 高级配置实战:从连接保持到日志分析的完整指南前言 一、Apache 连接保持 - 性

Linux中的more 和 less区别对比分析

《Linux中的more和less区别对比分析》在Linux/Unix系统中,more和less都是用于分页查看文本文件的命令,但less是more的增强版,功能更强大,:本文主要介绍Linu... 目录1. 基础功能对比2. 常用操作对比less 的操作3. 实际使用示例4. 为什么推荐 less?5.

spring-gateway filters添加自定义过滤器实现流程分析(可插拔)

《spring-gatewayfilters添加自定义过滤器实现流程分析(可插拔)》:本文主要介绍spring-gatewayfilters添加自定义过滤器实现流程分析(可插拔),本文通过实例图... 目录需求背景需求拆解设计流程及作用域逻辑处理代码逻辑需求背景公司要求,通过公司网络代理访问的请求需要做请

Java集成Onlyoffice的示例代码及场景分析

《Java集成Onlyoffice的示例代码及场景分析》:本文主要介绍Java集成Onlyoffice的示例代码及场景分析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 需求场景:实现文档的在线编辑,团队协作总结:两个接口 + 前端页面 + 配置项接口1:一个接口,将o

IDEA下"File is read-only"可能原因分析及"找不到或无法加载主类"的问题

《IDEA下Fileisread-only可能原因分析及找不到或无法加载主类的问题》:本文主要介绍IDEA下Fileisread-only可能原因分析及找不到或无法加载主类的问题,具有很好的参... 目录1.File is read-only”可能原因2.“找不到或无法加载主类”问题的解决总结1.File

Dubbo之SPI机制的实现原理和优势分析

《Dubbo之SPI机制的实现原理和优势分析》:本文主要介绍Dubbo之SPI机制的实现原理和优势,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Dubbo中SPI机制的实现原理和优势JDK 中的 SPI 机制解析Dubbo 中的 SPI 机制解析总结Dubbo中

C#继承之里氏替换原则分析

《C#继承之里氏替换原则分析》:本文主要介绍C#继承之里氏替换原则,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#里氏替换原则一.概念二.语法表现三.类型检查与转换总结C#里氏替换原则一.概念里氏替换原则是面向对象设计的基本原则之一:核心思想:所有引py

基于Go语言实现Base62编码的三种方式以及对比分析

《基于Go语言实现Base62编码的三种方式以及对比分析》Base62编码是一种在字符编码中使用62个字符的编码方式,在计算机科学中,,Go语言是一种静态类型、编译型语言,它由Google开发并开源,... 目录一、标准库现状与解决方案1. 标准库对比表2. 解决方案完整实现代码(含边界处理)二、关键实现细