键树算法的实现

转载 2007年10月15日 20:36:00
原贴:http://www.jsbulo.com/htmldata/cxkf/c/2007417/6994.html

键树算法的实现
  2007-4-17  来源:CSDN  编辑:Jsbulo  热度:

键树算法在计费系统中非常普遍,用来在共享内存中查找用户资料的时候,非常快,查找代价始终是常数级别。

下面是源码广泛应用在国内的计费系统之中,其中alloctor,dealloctor函数是用来在共享内存中分配和释放内存的。

另外重复键值的算法采用的是线性链表的算法,比较简单,所以就没有列出源码。

h_trie.h

#ifndef H_TRIE_H_
#define H_TRIE_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "error.h"
#include "list.h"

#define TRIE_FANOUT 10

/* - - - 键树节点结构 - - - */
typedef struct trie_s
{   
 int  subchanged[TRIE_FANOUT]; /* 记录子节点发生变化的情况 */
 int  listchanged; /* 记录所属链表的变化情况 */
 list_t  *list;
 struct trie_s *subtrie[TRIE_FANOUT];
}trie_t;

void InitHTrie (trie_t **trie);

int InsertHTrie (trie_t **trie, const char str[], const int level,
  void *data, size_t n, int changed);

void * SearchHTrie (trie_t *trie, const char str[], const int level, void *data,
 int (*cmp) (const void *data1, const void *data2));

int TouchHTrie (trie_t **trie, const char str[], const int level, list_t ***list);

list_t *GetListofHTrie (trie_t *trie, const char str[], const int level);

void PrintHTrie (trie_t *trie, const int level, const int key,
 void (*print) (const void *data));
/*
void OperateTrie (trie_t *trie, void (* op_list) (void *data));
*/
void RefreshHTrie (trie_t *trie, void (* op_data) (void *data));

void FreeHTrie (trie_t *trie);

int NeedRefresh (trie_t *trie);

/*
 * 最大可能匹配树查找
 */
list_t *MatchHTrie (trie_t *trie, const char str[], const int level);

/*
 * 功能: TRIE树遍历操作函数
 *
 * 注意 节点操作可中断
 *
 * 返回 0 未执行完毕 1 执行完毕
 */ 
int DealHTrie (trie_t *trie, int (* op_data) (void *data));

#endif

h_trie.c

#include "stdafx.h"
#include <stdio.h>
#include <ctype.h>

#include "h_trie.h"
#include "alloc.h"
static char keyarray[256];

/*-------------------------------
 * usage: 初始化键值数组
 * comment:将char映射成0-9的数值
 *-------------------------------*/
void InitHTrie (trie_t **trie)
{
 int c;

 for (c = 0; c < 256; c++)
 {
  if (isdigit (c))
   keyarray[c] = c - ’0’;
  else
   keyarray[c] = c%10;
 }
 
 *trie = NULL;
}

static trie_t * NewNode ()
{
 int i;
 trie_t *node = (trie_t *)allocate (sizeof (trie_t));

 if (node)
 {
  node->list = NULL;
  for (i = 0; i < TRIE_FANOUT; i++)
  {
   node->subchanged[i] = 0;
   node->listchanged = 0;
   node->subtrie[i] = NULL;
  }
 }

        if (node == NULL)
  pr_error("errorcode:%d,msg:NewNode: allocate() return NULL/n");       
              
 return node;
}

/*--------------------------------
 * usage: 向键树中插入一个新的数据
 * arguments: *trie -- 键树头指针
 *   str   -- 键值字符串
 *   level -- 键值长度
 *   data  -- 要插入的数据
 *   n     -- 要插入的数据的大小
 *   changed - 记录当前节点的子节点的内容是否发生了变化
 *     1 -- 有变化 0 -- 无变化
 * return: -1 -- 出错 0 -- 正常
 * comment:键树的叶节点是链表,出入数据时,先根据键值找到叶节点,再向
 *   叶节点所指的链表中插入数据。
 *---------------------------------*/
int InsertHTrie (trie_t **trie, const char str[], const int level,
  void *data, size_t n, int changed)
{
 int i;
 int key;
 trie_t *curnode;

 if (*trie == NULL)
 {
  *trie = NewNode ();
  if (*trie == NULL) {
   return -1;
  }
 }

 curnode = *trie;
 for (i = 0; i < level ; i++)
 {
  key = (int) keyarray[(int)str[i]];
  if (curnode->subtrie[key] == NULL)
  {
   if ((curnode->subtrie[key] = NewNode ()) == NULL)
    return -1;
  }
  curnode->subchanged[key] = changed;
  
  curnode = curnode->subtrie[key];
 }
 
 curnode->listchanged = changed;
 
 return (InsertList (&(curnode->list), data, n));
}

/*--------------------------------
 * usage: 在键树中查找数据
 * arguments: trie  -- 键树头指针
 *   str   -- 键值字符串
 *   level -- 键值长度
 *   data  -- 要查找的数据
 *   cmp   -- 比较函数指针
 * return: 找到 -- 返回指向该数据的指针 没找到 -- NULL
 * comment:查找规则由cmp函数指定
 *---------------------------------*/
void * SearchHTrie (trie_t *trie, const char str[], const int level, void *data,
  int (*cmp) (const void *data1, const void *data2))
{
 int i;
 int key;
 trie_t *curnode;

 if (trie == NULL)
  return NULL;

 curnode = trie;
 for (i = 0; i < level ; i++)
 {
  key = (int) keyarray[ (int)str[i] ];
  if (curnode->subtrie[key] == NULL)
   return NULL;
  
  curnode = curnode->subtrie[key];
 }

 return (SearchList (curnode->list, data, cmp));
}

/*--------------------------------
 * usage: 在键树中查找键值指向的链头。并将经过的节点的changed字段置1
 *  表示该节点的子节点要发生变化。如节点不存在,则生成该节点
 * arguments: trie  -- 键树头指针
 *   str   -- 键值字符串
 *   level -- 键值长度
 *   list  -- 保存指向链头list指针的指针,由于要保存指针的指针,
 *     使用3层指针
 * return: 找到 -- 返回指向该链表头的指针 没找到 -- NULL
 * comment:
 *---------------------------------*/
int TouchHTrie (trie_t **trie, const char str[], const int level, list_t ***list)
{
 int i;
 int key;
 trie_t *curnode;

 if (*trie == NULL)
 {
  *trie = NewNode ();
  if (*trie == NULL) {
   pr_error("errorcode:%d,msg:TouchHTrie:NewNode () return NULL/n");
                 
   return -1;
  }
 }

 curnode = *trie;
 for (i = 0; i < level ; i++)
 {
  key = (int) keyarray[ (int)str[i]];
  if (curnode->subtrie[key] == NULL)
  {
   if ((curnode->subtrie[key] = NewNode ()) == NULL) {
    pr_error("errorcode:%d,msg:NewNode () error/n");
    return -1;
   }
  }
  curnode->subchanged[key] = 1;
  
  curnode = curnode->subtrie[key];
 }
 
 curnode->listchanged = 1;
 
 *list = &(curnode->list);
 
 return 0;
}

/*-------------------------------------------
 *
 *-------------------------------------------*/
list_t *GetListofHTrie (trie_t *trie, const char str[], const int level)
{
 int i;
 int key;
 trie_t *curnode;
 
 if (trie == NULL)
  return NULL;
 
 curnode = trie;
 for (i = 0; i < level ; i++)
 {
  key = (int) keyarray[(int)str[i]];
  if (curnode->subtrie[key] == NULL)
   return NULL;
   
  curnode = curnode->subtrie[key];
 }
 
 return curnode->list;
}


list_t *MatchHTrie (trie_t *trie, const char str[], const int level)
{
 int i;
 int key;
 trie_t *curnode;
 
 if (trie == NULL)
  return NULL;
 
 curnode = trie;
 
 for (i = 0; i < level ; i++)
 {
  key = (int) keyarray[(int)str[i]];
  if (curnode->subtrie[key] == NULL)
   return curnode->list;
   
  curnode = curnode->subtrie[key];
 }
 
 return curnode->list;
}

/*-------------------------------
 * usage: 释放键树
 * arguments: trie -- the head of trie
 *-------------------------------*/
void FreeHTrie (trie_t *trie)
{
 int i;

 if (trie)
 {
  for (i = 0; i < TRIE_FANOUT; i++)
   FreeHTrie (trie->subtrie[i]);
  FreeList (trie->list);
  free (trie);
 }
}

/*----------------------------------
 * usage: print the data of the trie
 *----------------------------------*/
void PrintHTrie (trie_t *trie, const int level, const int key, void (*print) (const void *data))
{
 int i;
 
 if (trie)
 {
  fprintf (stderr, "enter subtrie -- level:%d,key:%d/n", level, key);
  for (i = 0; i < TRIE_FANOUT; i++)
  {
   PrintHTrie (trie->subtrie[i], level + 1, i, print);
  }
  PrintList (trie->list, print);
 }
}
/*
void OperateHTrie (trie_t *trie, void (* op_list) (void *data))
{
  
}
*/

/*------------------------------------------
 * usage: 刷新TRIE,对changed为1的节点的子节点的链表做op_list指定的操作
 * parameters: trie   -- trie head pointer
 *   op_list-- 对list的操作
 *------------------------------------------*/
void RefreshHTrie (trie_t *trie, void (* op_data) (void *data))
{
 int i;
 
 if (trie)
 {
  for (i = 0; i < TRIE_FANOUT; i++)
  {
   if (trie->subchanged[i]) /* 子节点发生过变化 */
   {
    RefreshHTrie (trie->subtrie[i], op_data);
    trie->subchanged[i] = 0;
   }
  }
  if (trie->listchanged) 
  {
   OperateList (trie->list, op_data);
   trie->listchanged = 0;
  }
 }
}

int NeedRefresh (trie_t *trie)
{
 int i;
 
 if (trie)
 {
  for (i = 0; i < TRIE_FANOUT; i++)
  {
   if (trie->subchanged[i]) /* 子节点发生过变化 */
   {
    return 1;
   }
  }
  if (trie->listchanged)
  {
   return 1;
  }
 }
 
 return 0;
}

/*
 * 功能: TRIE树遍历操作函数
 *
 * 注意 节点操作可中断
 *
 * 返回 0 未执行完毕 1 执行完毕
 */ 
int DealHTrie (trie_t *trie, int (* op_data) (void *data))
{
 int i;
 
 if (trie)
 {
  for (i = 0; i < TRIE_FANOUT; i++)
  {
   if (trie->subchanged[i]) /* 子节点发生过变化 */
   {
    /* 字节点操作中断, 返回 0 */
    if (DealHTrie (trie->subtrie[i], op_data) == 0)
     return 0;
     
    trie->subchanged[i] = 0;
   }
  }
  if (trie->listchanged) 
  {
   if (DealList (trie->list, op_data) == 0)
    return 0;
   trie->listchanged = 0;
  }
 }
 
 return 1;
}

 测试主程序在vs2005中编译通过

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>

#include "alloc.h"
#include "list.h"
#include "h_trie.h"

static trie_t *pTrie;
struct testdata
{
 int key;
 char data[20];
};


int _tmain(int argc, _TCHAR* argv[])
{
 struct testdata *pData;
    int i;
    char key[10];

 InitShm(sizeof(trie_t)*100+sizeof(list_t)*20);

 PrintFreelistAndCookie();

 InitHTrie(&pTrie);

 for(i = 0 ;i<10; i++)
 {
  printf("main:i=%d/n",i);
  pData = (struct testdata*)malloc(sizeof(struct testdata));
  if (pData == NULL)
  {
   pr_error("allocate fail/n");
  }

  pData->key = i;
  sprintf(pData->data ,"%d", i*9999);
        sprintf(key, "%d", pData->key);

  if ( - 1 == InsertHTrie(&pTrie, key, sizeof(int), pData,
   sizeof(struct testdata), 0) )
  {
   pr_error("errorcode:%d,msg:insert tree error/n");
  }

  PrintFreelistAndCookie();
 }


 free(getShm());
 return 0;
};

Java 键树---字典树(小词典)的实现

键树的基本概念 键树又称数字查找树(Digital Search Tree)。   它是一棵度大于等于2的树,树中的每个结点中不是包含一个或几个关键字,而是只含有组成关键字的符号。   例如,若...
  • Sun_Ru
  • Sun_Ru
  • 2016年07月23日 14:45
  • 815

Trie树(字典树,前缀树,键树)分析详解

Trie树概述   Trie树,又称字典树、前缀树、单词查找树、键树,是一种多叉树形结构,是一种哈希树的变种。Trie这个术语来自于retrieval,发音为/tri:/ “tree”,也有人读为/t...
  • u010599509
  • u010599509
  • 2017年01月13日 17:32
  • 937

经典查找算法 --- R树

R树:处理空间存储问题 -->是引用别人的文章 相信经过上面第一节的介绍,你已经对B树或者B+树有所了解。这种树可以非常好的处理一维空间存储的问题。B树是一棵平衡树,它是把一维直线分为若干段线段,当...
  • sjyttkl
  • sjyttkl
  • 2017年04月18日 11:18
  • 1129

【模式匹配】之——多模匹配 下篇(AC算法之前缀树实现)

前言 本文章对应代码下载地址: http://download.csdn.net/detail/sun2043430/5286986 AC算法之前缀树实现步骤 步骤一 ...
  • sun2043430
  • sun2043430
  • 2013年04月21日 23:00
  • 2931

基于kd树的KNN算法的实现

记得大三初期,刚从大连理工大学回来,眼巴巴的望着同学各自都有着落了,就我一副“初出茅庐,不谙世事”的样子,于是不得不觍着脸厚着皮去找老师,恳求他让我去海洋所实习。他给我的第一份差事便是将几个G的图片里...
  • fujianfei99
  • fujianfei99
  • 2017年07月30日 17:16
  • 348

TreeMap 红黑树算法实现

TreeMap 的实现就是红黑树数据结构,也就说是一棵自平衡的排序二叉树,这样就可以保证当需要快速检索指定节点。 TreeSet 和 TreeMap 的关系 为了让大家了解 TreeMap...
  • u014421556
  • u014421556
  • 2016年08月31日 16:09
  • 764

哈夫曼树及其算法实现

概念:哈夫曼(Huffman)树又称最优二叉树或最优搜索树,是一种带权路径长度最短的二叉树。在许多应用中,常常赋给树中结点一个有某种意义的实数,称此实数为该结点的权。从树根结点到该结点之间的路径长度与...
  • luoluozlb
  • luoluozlb
  • 2016年08月04日 22:10
  • 5479

看数据结构写代码(59) 键树的双链表示法

杂谈; 打败自己的 往往不是敌人,而是自己。坚持不易,且行且珍惜。 键树 是一种 把  把  非叶子节点 当成索引,叶子节点保存具体信息的一种树。 例如:   它的 键树形式如下: 键树 有...
  • fuming0210sc
  • fuming0210sc
  • 2015年04月28日 21:59
  • 558

图的最小生成树 Prim算法 C++实现

/* * File name : graph_cmst_prim.cpp * Function : 图的最小生成树 Prim算法 C++实现 * Created on : 2016年6月8日 ...
  • beijiwei
  • beijiwei
  • 2016年06月08日 16:22
  • 421

场景管理:BSP算法C++实现

简单的实现了下BSP树 代码结构: face.hpp 被管理的模型面片类bsp_tree.hpp BSP树类main.cpp程序入口 face.hpp #pragma once...
  • u012234115
  • u012234115
  • 2015年07月30日 21:13
  • 1341
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:键树算法的实现
举报原因:
原因补充:

(最多只允许输入30个字)