数据结构--C++代码实现
树结构
1.二叉搜索树
typedef int DataType;
struct TreeNode {
DataType data;
std::shared_ptr<TreeNode> left_node;
std::shared_ptr<TreeNode> right_node;
TreeNode() : data(0), left_node(nullptr), right_node(nullptr) {};
TreeNode(DataType value) : data(value), left_node(nullptr), right_node(nullptr) {};
};
class BinarySearchTree {
public:
BinarySearchTree() {
root_tree_node_ = std::make_shared<TreeNode>();
}
// 搜索 target 是否属于该树
bool Find(DataType target) {
return Find(target, root_tree_node_);
}
bool Find(DataType target, std::weak_ptr<TreeNode> tree_node) {
if(tree_node.expired()) {
return false;
}
auto node_ptr = tree_node.lock();
if(node_ptr->data == target) {
return true;
}
else if(node_ptr->data > target){
return Find(target, node_ptr->left_node);
}
else {
return Find(target, node_ptr->right_node);
}
}
//插入一个元素
void InsertData(DataType target) {
auto insert_node = std::make_shared<TreeNode>(target);
auto temp_node = root_tree_node_.get();
while(temp_node) {
if(target < temp_node->data) {
if(!temp_node->left_node) {
temp_node->left_node = insert_node;
num++;
return;
}
else {
temp_node = temp_node->left_node.get();
}
}
//对于相等的情况,按大于当前节点处理
else {
if(!temp_node->right_node) {
temp_node->right_node = insert_node;
num++;
return;
}
else {
temp_node = temp_node->right_node.get();
}
}
}
}
//删除一个元素
bool DeleteData(DataType target) {
if(!root_tree_node_) {
return false;
}
auto tree_node = root_tree_node_;
std::shared_ptr<TreeNode> node_base = nullptr;
//找到待删除元素对应的节点
while(tree_node != nullptr && tree_node->data != target) {
node_base = tree_node;
if(tree_node->data < target) {
tree_node = tree_node->right_node;
}
else {
tree_node = tree_node->left_node;
}
}
if(!tree_node) {
return false;
}
//删除节点有两个子节点
if(tree_node -> left_node && tree_node->right_node) {
std::shared_ptr<TreeNode> min_node = tree_node->right_node;
std::shared_ptr<TreeNode> min_node_base = tree_node;
//寻找右子树的最小节点,将它赋给当前待删除节点
while(min_node->left_node) {
min_node_base = min_node;
min_node = min_node->left_node;
}
tree_node->data = min_node->data;
tree_node = min_node;
node_base = min_node_base;
}
//删除节点是叶节点或仅有1个节点
std::shared_ptr<TreeNode> child_node;
if(!tree_node -> left_node) {
child_node = tree_node->left_node;
}
else if(!tree_node->right_node){
child_node = tree_node->right_node;
}
else {
child_node = nullptr;
}
if(!node_base) {
root_tree_node_ = child_node;
}
else if(tree_node == node_base->left_node) {
node_base->left_node = child_node;
}
else
node_base->right_node = child_node;
return true;
}
private:
int num = 1;
std::shared_ptr<TreeNode> root_tree_node_;
};
2.前缀树(字典树)
Trie树的核心思想是空间换时间,利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。
它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。
#include <vector>
#include <memory>
#include <string>
const static int children_size = 26;
struct TrieNode {
std::vector<std::shared_ptr<TrieNode> > children_node; //字典树的孩子节点
bool is_completion; // 该节点是否是某条单词的末尾节点
TrieNode() : is_completion(false) {
children_node.resize(children_size);
}
};
class Trie{
public:
Trie() {
trie_tree_ = std::make_shared<TrieNode>();
}
std::shared_ptr<TrieNode> SearchPrefix(const std::string& prefix_str); // 根据前缀信息,找到最后一个节点。
void Insert (const std::string& word); //插入新的单词
bool SearchWord(const std::string& word); //查询该单词是否出现过
std::shared_ptr<TrieNode> trie_tree_;
};
std::shared_ptr<TrieNode> Trie::SearchPrefix(const std::string& prefix_str) {
auto sentinel_node = trie_tree_;
for(const auto char_single : prefix_str) {
int index = char_single - 'a';
if(sentinel_node->children_node[index] == nullptr) {
return nullptr;
}
sentinel_node = sentinel_node->children_node[index];
}
return sentinel_node;
}
void Trie::Insert(const std::string &word) {
auto sentinel_node = trie_tree_;
for(const auto char_single : word) {
int index = char_single - 'a';
if(sentinel_node->children_node[index] == nullptr) {
sentinel_node->children_node[index] = std::make_shared<TrieNode>();
}
sentinel_node = sentinel_node->children_node[index];
}
sentinel_node->is_completion = true; //最后的末尾字符,需要将 completion 赋值
}
bool Trie::SearchWord(const std::string &word) {
auto search_node = SearchPrefix(word);
return search_node != nullptr;
}
Trie 树的改进: AC 自动机算法
AC 自动机算法,全称是 Aho-Corasick 算法。其实,Trie 树跟 AC 自动机之间的关系,就像单串匹配中朴素的串匹配算法,跟 KMP 算法之间的关系一样,只不过前者针对的是多模式串而已。
AC 自动机实际上就是在 Trie 树之上,加了类似 KMP 的 next 数组,只不过此处的 next 数组是构建在树上罢了。