trie-字典树及实现

trie树

又称为字典树、单词查找树。是一种树形结构,哈希树的变种。典型应用是用于统计、排序和保存大量的字符串(不仅仅限于字符串),经常被搜索引擎系统用于文本词频统计。trie树是用空间换取时间的典型数据结构。

性质

根节点不包含字符,除了根节点外,每个节点都只包含一个字符;

从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;

每个节点的所有子节点包含的字符都不相同。

基本操作

基本操作有:树的创建、删除;节点的插入、查找、删除(好像这种操作比较少见)。

优点

利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希表高

缺点

每个节点需要包含一些额外的字段来保存节点信息,浪费空间。

应用

串的快速检索、“串”排序、最长公共前缀

 

trie树实现

本文实现了trie树的创建、删除;字符串的插入、查找、删除。另外,本文限定单词仅仅由26个小写字母组成。具体实现将在本文最后给出完整代码。

结构体设计

typedef struct TrieNode
{
	int isStr; /*word flag*/
	int elemcount; /*word number*/
	int passcount; /*pass by number*/
	struct TrieNode *next[MAX];
}Trie;

其中,isStr 单词结束标记;elemcount是单词被插入的次数;passcount是所有单词经过该节点的次数;next是该节点的孩子节点。

trie树创建

创建trie树与trie树初始化,分开实现。

Trie * trie_malloc();
void trie_init(Trie *p);

trie树删除

删除整棵树,释放其拥有的所有资源

void trie_del(Trie *root);

字符串插入

将字符串s插入trie树root

void trie_insert(Trie *root,const char *s);

字符串查找

从trie树中查找字符串s,如果能找到则返回s在trie中出现的次数(即被插入的次数),否则返回0

int trie_search(Trie *root,const char *s);

字符串删除

trie树中删除字符串s(s是整个单词,并不会删除一个完整单词的一部分)

void trie_node_del(Trie *root, const char *s);

辅助函数

这些辅助函数相当于C++的private成员,仅仅用来辅助实现基本的用户功能。分别为:验证字符串的合法性、根据字符获取在孩子节点中的索引、递归删除trie树、递归删除字符串对应的节点

static int verify_str(const char *s);
static int get_index(char ch);
static void delete_subtrie(Trie **root);
static void delete_node(Trie **node, const char *chr);

具体的代码实现trie.h如下:

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

#define MAX 26
#define IDXERR -1
#define INVALID 0
#define VALID 1

#define true 1
#define false 0

typedef struct TrieNode
{
	int isStr; /*word flag*/
	int elemcount; /*word number*/
	int passcount; /*pass by number*/
	struct TrieNode *next[MAX];
}Trie;

Trie * trie_malloc();
void trie_init(Trie *p);

void trie_insert(Trie *root,const char *s);
int trie_search(Trie *root,const char *s);
void trie_del(Trie *root);
void trie_node_del(Trie *root, const char *s);

static int verify_str(const char *s);
static int get_index(char ch);
static void delete_subtrie(Trie **root);
static void delete_node(Trie **node, const char *chr);

void trie_init(Trie *p)
{
	int i=0;
	if(NULL == p)
		return;
	memset(p,0x0,sizeof(Trie));
	for(i=0;i<MAX;i++)
	{
		p->next[i] = NULL;
	}
	p->isStr = false;
	p->elemcount = 0;
	p->passcount = 0;
}

Trie * trie_malloc()
{
	Trie *temp=(Trie *)malloc(sizeof(Trie));
	return temp;
}

void trie_insert(Trie *root,const char *s)
{
	if(NULL == root || NULL == s || *s == '\0')
		return;
	if(INVALID == verify_str(s))
		return;
	Trie *p = root;
	int idx = 0;
	while(*s!='\0')
	{
		idx = get_index(*s);
		if(NULL == p->next[idx]) 
		{
			Trie *temp = trie_malloc();
			trie_init(temp);
			p->next[idx]=temp;
			p=p->next[idx];   
		}   
		else
		{
			p=p->next[idx];
		}
		s++;
		p->passcount++;
	}
	p->isStr=true;  
	p->elemcount++;
}

int trie_search(Trie *root,const char *s) 
{
	Trie *p=root;
	int idx = 0;
	if(NULL == root || NULL == s)
		return 0;
	while(p != NULL && *s != '\0')
	{
		idx = get_index(*s);
		if(IDXERR == idx)
			return 0;
		p=p->next[idx];
		s++;
	}
	if(p != NULL && true == p->isStr)
		return p->elemcount;
	else
		return 0;
}

void trie_del(Trie *root)
{
        if(NULL == root)
                return;
        delete_subtrie(&root);
}

static int verify_str(const char *s)
{
	if(NULL == s)
		return INVALID;
        while(*s!='\0')
        {
                if(IDXERR == get_index(*s))
                        return INVALID;
                s++;
        }
        return VALID;
}

static int get_index(char ch)
{
        int idx = ch-'a';
        if(idx < 0 || idx >= MAX)
        {
                idx = IDXERR;
        }
        return idx;
}

static void delete_subtrie(Trie **root)
{
	int i = 0;
	if(root != NULL && *root != NULL)
	{
		for(i = 0; i < MAX; i++)
		{
			if((*root)->next[i]!=NULL)
			{
				delete_subtrie(&((*root)->next[i]));
			}
		}
	}
	if(NULL != root)
	{
		free(*root);
		*root = NULL;
	}
}


static void delete_node(Trie **node, const char *chr)
{
	int idx = 0;
	if(NULL == node || NULL == *node || NULL == chr)
		return;
	if(*chr != '\0'&& *(chr+1) != '\0' && *node != NULL)
	{
		chr++;
		idx = get_index(*chr);
		delete_node(&((*node)->next[idx]), chr);           
	}
	if(*node != NULL)
	{
		free(*node);
		*node = NULL;
	}
	return;
} 

void trie_node_del(Trie *root, const char *s)
{
	if(NULL == root || NULL == s || *s == '\0')
		return;
	int elemcount=0;
	Trie *p = root;
        Trie *q = p;
        int remain=0;
        int idx = 0;
	if((elemcount=trie_search(root,s))<= 0)
		return;
	while(*s != '\0' && p != NULL)
	{
		idx = get_index(*s);
		q = p;
		p = p->next[idx];
		remain = p->passcount - elemcount;
		if(remain <= 0)
		{
			delete_node(&p, s);
			q->next[idx] = p; // important
			p = NULL;// can delete "p = NULL"
			break;
		}
		else
		{
			p->passcount = remain;
		}
		s++;
	}
	/*clear word flag*/
	if(p != NULL)
	{
		p->isStr = false;
	}
}


测试代码main.c

#include "trie.h"

#define STR1 "hello"
#define STR2 "hell"
#define STR3 "helloworld"
#define STR4 "world"
#define STARLINE "****"

int main(int argc, char *argv[])
{
	Trie *root= trie_malloc();
	if(NULL == root)
	{
		printf("malloc trie failed\n");
		exit(0);
	}
	trie_init(root);

	/*insert*/
	printf("\n %sinsert string%s\n",STARLINE,STARLINE);
	trie_insert(root,STR1);
	printf("%s\n",STR1);
	trie_insert(root,STR2);
	printf("%s\n",STR2);
	trie_insert(root,STR3);
	printf("%s\n",STR3);
	trie_insert(root,STR4);
	printf("%s\n",STR4);
	trie_insert(root,STR2);
	printf("%s\n",STR2);
	/*search*/
	printf("\n %ssearch string%s\n",STARLINE,STARLINE);
	printf("%s, %d times\n",STR1, trie_search(root,STR1));
	printf("%s, %d times\n",STR2, trie_search(root,STR2));
	printf("%s, %d times\n",STR3, trie_search(root,STR3));
	printf("%s, %d times\n",STR4, trie_search(root,STR4));
	/*delete*/
	printf("\n %sdelete string%s\n",STARLINE,STARLINE);
	trie_node_del(root, STR1);
	printf("%s\n", STR1);
	printf("search %s, %d times\n",STR1, trie_search(root,STR1));

	trie_node_del(root, STR2);
	printf("%s\n", STR2);
	printf("search %s, %d times\n",STR2, trie_search(root,STR2));

	trie_node_del(root, STR3);
	printf("%s\n", STR3);
	printf("search %s, %d times\n",STR3, trie_search(root,STR3));

	trie_node_del(root, STR4);
	printf("%s\n", STR4);
	printf("search %s, %d times\n",STR4, trie_search(root,STR4));

	/*free trie*/
	printf("\n %sfree trie%s\n",STARLINE,STARLINE);
	trie_del(root);
	root = NULL;

	return 0;
}


gcc -g -o test main,c

执行结果如下图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值