10.算法之复杂数据结构

Trie树(字典树)概述

  • trie树,又称字典树或前缀树,是一种有序的、用于统计、排序和存储字符串的数据结构,它与二叉查找树不同,关键字不是直接保存在结点中,而是由结点在书中的位置决定。
  • 一个结点的所有子孙都有相同的前缀,也就是这个结点对应的字符串,而根结点对应空字符串。一般情况下,不是所有的结点都有对应的值,只有叶子结点和部分内部结点所对应的键才有相关的值。
  • trie树的最大优点是利用字符串的公共前缀来减少存储空间与查询时间,从而最大限度地减少无谓的字符串比较,是非常高效的字符串查找数据结构。
    在这里插入图片描述
#define TRIE_MAX_CHAR_NUM 26

struct TrieNode{
   
	TrieNode *child[TRIE_MAX_CHAR_NUM];
	bool is_end;
	TrieNode():is_end(false){
   
		for(int i=0;i<TRIE_MAX_CHAR_NUM;i++){
   
			child[i]=0;
		}
	}
};
//前序遍历
void preorder_trie(TrieNode *node,int layer){
   
	for(int i=0;i<TRIE_MAX_CHAR_NUM;i++){
   
		if(node->child[i]!=0){
   
			for(int j=0;j<layer;j++){
   
				printf("---");
			}
			printf("%c",i+'a');
			if(node->child[i].is_end==true){
   
				printf((end));
			}
			printf("\n");
			 preorder_trie(node->child[i],layer+1);
		}
	}
}

Trie树获取全部单词

深度搜索trie树,对于正在搜索的结点node:
遍历该结点26个孩子指针child[i](‘a’-‘z’),如果指针不空:
将该child[i]对应的字符(i+‘a’),push进入栈中,如果该孩子指针标记的is_end为真(说明这个位置是一个单词):
从栈底到栈顶对栈进行遍历,生成字符串,将它保存到结果数组中
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

void get_all_word_from_trie(TrieNode *node,string &word,vector<string>&word_list){
   
	for(int i=0;i<TRIE_MAX_CHAR_NUM;i++){
   
		if(node->child[i]!=0){
   
			word.push_back(i-'a');
			if(node->child[i]->is_end){
   
				word_list.push_back(word);
			}
			get_all_word_from_trie(node->child[i],word,word_list);
			word.erase(word.length()-1,1);
		}
	}
}

Trie树的单词插入

使用ptr指针指向root
逐个遍历待插入的字符串中的各个字符:
计算下标pos=正在遍历字符-‘a’
如果ptr指向的结点的第pos个孩子为假:
创建该结点的第pos个孩子
ptr指向该结点的第pos个孩子
标记ptr指向的结点is_end为true
在这里插入图片描述

class TrieTree{
   
public:
TrieTree(){
   }
~TrieTree(){
   
	for(int i=0;i<_node_vec.size();i++){
   
		delete _node_vec[i];
	}
}
void insert(const char *word){
   
	TrieNode *ptr=&_root;
	while(*word){
   
		int pos=*word-'a';
		if(ptr->child[pos]==0){
   
			ptr->child[pos]=new_node();
		}
		ptr=ptr->child[pos];
		word++;
	}
	ptr->is_end=true;
}

private:
TrieNode *new_node(){
   
	TrieNode *node=new TrieNode();
	_node_vec.push_back(node);
	return node;
}

	vector<TrieNode *> _node_vec;
	/*便于析构比较复杂的数据结构,比如树、图,析构时需要前序还是后序析构?相当复杂*/
	TrieNode _root;
};

Trie树的单词搜索

使用ptr指针指向root
逐个遍历待插入的字符串中的各个字符:
计算下标pos=正在遍历字符-‘a’
如果ptr指向的结点的第pos个孩子为假:
返回假
ptr指向该结点的第pos个孩子
标记ptr指向的结点is_end
在这里插入图片描述

bool search(const char* word){
   
	TrieNode *ptr= &_root;

	while(*word){
   
		int pos=*word-'a';
		if(!ptr->child[pos]){
   
			return false;
		}
		ptr=ptr->child[pos];
		word++;;
	}
	return ptr->is_end;
}

Trie树的前缀查询

通常以该前缀开始有哪些单词。
该代码段只实现是否存在该前缀开始的单词。

bool startsWith(const char *prefix){
   
	TrieNode *ptr=&_root;
	while(*prefix){
   
		int pos=*prefix-'a'
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值