字典树算法

字典树

本文将包括以下内容:

  • 字典树的基本概念

  • 字典树的结构

  • 字典树的初始化

  • 字典树的插入

  • 根据单词前缀来遍历全部结果

1.字典树的基本概念

Trie字典树主要用于存储字符串,Trie 的每个 Node 保存一个字符。用链表来描述的话,就是一个字符串就是一个链表。每个Node都保存了它的所有子节点。字典树顾名思义是一个树形结构,它的创建和二叉树类似。它可以实现前缀搜索。
Trie 树利用字符串的公共前缀,逐层建立起一棵多叉树。在检索时类似于在字典中查单词,从第一个字符开始遍历,在 Trie 树中一层一层往下查找,查找效率可以达到 O(n),n 为查找字符串的长度。

Trie 树有以下特点:

1.Trie 树的根结点上不存储字符,其余结点上存且只存一个字符。
2.从根结点出发,到某一结点上经过的字符,即是该结点对应的前缀。每个结点的孩子结点存储的字符各不相同。
3.Trie 树牺牲空间来换取时间,当数据量很大时,会占用很大空间。如果字符串均由小写字母组成,则每个结点最多会有 2626 个孩子结点,则最多会有 26n26n 个用于存储的结点,nn 为字符串的最大长度。(实际上这个可以优化)
4.Trie 树常用于字符串的快速检索,字符串的快速排序与去重,文本的词频统计等。

下图是一棵以词:a、to、tea、ted、ten、i、in、inn构成的字典树,其中带下划线的结点为 终端结点(从根结点到终端结点的遍历过程就是 Trie 中存储的一个字符串)。注意$表示的根节点,是空的

在这里插入图片描述

2.字典树的结构

因为我们要查找公共前缀的所有单词,因此在这里加入isStr数据域用于判断是否构成完整单词
//字典树 
typedef struct tire_node {
	int count;		       //记录该节点代表的单词个数
	char word[MAXSIZE];
	bool isStr;		       //标记该节点是否构成完整单词
	struct tire_node *children[MAXSIZE];	//各个子节点
} tire;

3.字典树的初始化

//相当于建立带头节点的树 
tire *initTire() {	//初始化
	tire *root;
	root = (tire *)malloc(sizeof(tire));
	root->count = 0;
	root->isStr = false;
	int i;
	for (i = 0; i < MAXSIZE; i++)
	{
		root->children[i] = NULL;
	}
	return root;
}

4.字典树的插入

void tireInsert(tire **root, char *word) {
	tire *node = *root;
	int i = 0;
	int j;
	int id;
	while (word[i])
	{
		id = word[i] - 'a';
		if (!node->children[id])		//如果没找到相应的字符 
		{
			node->children[id] = new tire();	//开辟空间
			for (j = 0; j < MAXSIZE; j++)
			{
				node->children[id]->children[j] = NULL;
			}
			node->children[id]->count = 0;
			node->children[id]->isStr = false;
		}
		node = node->children[id];
		node->count++;
		i++;
	}
	node->isStr = true;
	strcpy(node->word,word);
}

注意:

插入的时候咱们这里默认按照字符从小到大的顺序插入,因此所建立的树如果按照层次遍历的话是一个递增序列

5.根据单词前缀来遍历全部结果

//根据单词前缀查找前缀所在的节点位置 
tire * tireSearch(tire *root, char *word) {
	tire *node = root;
	int i = 0;
	while (word[i])
	{
		int id = word[i] - 'a';
		if (node->children[id])
		{
			node = node->children[id];
			i++;
		}
		//如果没找到,返回空节点 
		else	 
		{
			return NULL;
		}
	}
	return node;
}
在这里用到了BFS的思想
//BFS遍历打印出满足前缀的图书信息
void printTire(tire *root,char *front) {
	int count = 1;
	tire *node = tireSearch(root, front);
	int i;
	if (!node)
	{
		cout << "未匹配到您需要的信息,请重新输入" << endl;
	}
	else
	{
		tire *queue[MAXSIZE];
		int left = 0, right = 0;
		queue[right++] = node;
		//如果队列不为空 
		while (left < right)
		{
			tire *p = queue[left++];
			//如果当前节点表示的是完整的单词就输出 
			if (p->count != 0 && p->isStr)
			{
				cout << p->word<< endl;
			}
			//将当前节点的孩子都加入队列 
			for (i = 0; i < MAXSIZE; i++)
			{
				if (p->children[i])
				{
					queue[right++] = p->children[i];
				}
			}
		}
	}
}

完整代码:

#include<bits/stdc++.h>
#define MAXSIZE 50 
using namespace std;
//字典树 
typedef struct tire_node {
	int count;		//记录该节点代表的单词个数
	char word[MAXSIZE];
	bool isStr;		//标记该节点是否构成完整单词
	struct tire_node *children[MAXSIZE];	//各个子节点
} tire;
//相当于建立带头节点的树 
tire *initTire() {	//初始化
	tire *root;
	root = (tire *)malloc(sizeof(tire));
	root->count = 0;
	root->isStr = false;
	int i;
	for (i = 0; i < MAXSIZE; i++)
	{
		root->children[i] = NULL;
	}
	return root;
}
void tireInsert(tire **root, char *word) {
	tire *node = *root;
	int i = 0;
	int j;
	int id;
	while (word[i])
	{
		id = word[i] - 'a';
		if (!node->children[id])		//如果没找到相应的字符 
		{
			node->children[id] = new tire();	//开辟空间
			for (j = 0; j < MAXSIZE; j++)
			{
				node->children[id]->children[j] = NULL;
			}
			node->children[id]->count = 0;
			node->children[id]->isStr = false;
		}
		node = node->children[id];
		node->count++;
		i++;
	}
	node->isStr = true;
	strcpy(node->word,word);
}
//根据单词前缀查找前缀所在的节点位置 
tire * tireSearch(tire *root, char *word) {
	tire *node = root;
	int i = 0;
	while (word[i])
	{
		int id = word[i] - 'a';
		if (node->children[id])
		{
			node = node->children[id];
			i++;
		}
		//如果没找到,返回空节点 
		else	 
		{
			return NULL;
		}
	}
	return node;
}
//BFS遍历打印出满足前缀的图书信息
void printTire(tire *root,char *front) {
	int count = 1;
	tire *node = tireSearch(root, front);
	int i;
	if (!node)
	{
		cout << "未匹配到您需要的信息,请重新输入" << endl;
	}
	else
	{
		tire *queue[MAXSIZE];
		int left = 0, right = 0;
		queue[right++] = node;
		//如果队列不为空 
		while (left < right)
		{
			tire *p = queue[left++];
			//如果当前节点表示的是完整的单词就输出 
			if (p->count != 0 && p->isStr)
			{
				cout << p->word<< endl;
			}
			//将当前节点的孩子都加入队列 
			for (i = 0; i < MAXSIZE; i++)
			{
				if (p->children[i])
				{
					queue[right++] = p->children[i];
				}
			}
		}
	}
}
int main(){
	tire *node;
	node = initTire();
	tireInsert(&node,"wangjiahao");
	tireInsert(&node,"wangli");
	tireInsert(&node,"wanggayhao");
	tireInsert(&node,"wangnima");
	tireInsert(&node,"zhangwanlin");
	tireInsert(&node,"zhangsan");
	char x[MAXSIZE];
	cout<<"请输入您查询的名字"<<endl;
	cin>>x;
	printTire(node,x);
	return 0;
} 

本人菜鸟,如果有不对的地方大佬们请留言,在下一定吸取教训及时改正,谢谢!!!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
决策是一种常用的分类和回归方法。下面是一个使用Python实现的决策算法案例: def createTree(dataSet, r, usedX=[]): if len(dataSet) == 0: return {} tree = {} numEachClass = CountEachClass(dataSet) c = numEachClass.index(max(numEachClass)) tree['class'] = c mx, mg = getMaxGain(dataSet, usedX) print("max gain:", mg) if len(usedX) == len(X) or numEachClass[c] == len(dataSet) or mg < r: tree['factureX'] = -1 return tree else: tree['factureX'] = mx subDataSet = splitData(dataSet, mx) for xiv in range(len(X[mx])): xivDataSet = subDataSet[xiv] newusedX = usedX.copy() newusedX.append(mx) tree[xiv] = createTree(xivDataSet, r, newusedX) return tree 这个案例定义了一个递归构建决策的函数createTree。函数根据给定的数据集、阈值r和已使用的特征列表usedX,构建一个决策的字典结构。函数首先检查数据集是否为空,如果为空则返回一个空。然后计算数据集中每个类别的数量,并找出数量最多的类别作为当前根节点的类别。接下来,函数计算当前数据集中每个特征的信息增益,并选择信息增益最大的特征作为划分子集的依据。如果已经使用了所有特征、当前数据集中只有一种类别或者信息增益小于阈值r,则当前节点为叶节点,不再继续分支。否则,函数根据选择的特征将数据集划分为不同的子集,并递归调用自身构建。最后,函数返回构建好的决策。 这个案例是一个简化的决策算法实现,具体的数据处理和计算函数CountEachClass、getMaxGain和splitData在代码中未给出,你可以根据具体的需求自行实现或使用其他库进行实现。此外,你也可以参考《统计学习方法》一书中关于决策的相关内容了解更多细节。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值