Trie树

Trie树也称字典树,因为其效率很高,所以在在字符串查找、前缀匹配等中应用很广泛,下来就跟着我来建一棵自己的Trie树(以要存储的数据为字符串)。

                                             

(1)分析.

如上图,是一个简单的Trie树,我们可以看到以下特征:

1.多个子节点共用一个"根节点".

2.根节点为root里面没有存有任何数据.

3.对每个节点来说,由两部分构成,数据和一系列"指向"(可理解为与其子节点的联系).

4.它是一棵树,因此对树的操作,实际就是对节点的操作.

(2)构架

由此,我们和容易就可以构造一个节点,

class TrieNode {

char data;

list<TrieNode*> child;

};

那么一棵Trie树也就更简单了,

class Trie {

TrieNode* root;

};

由此我们已经大体上建好了一棵Trie数,只不过是差一些操作函数而已。

看过一些其他博客里面的定义,有些会定义一个定常的数组在节点立,我认为还是链表好一点,首先它可以节省空间,其次在STL中list已经被封装好,使用起来很方便。

(2)功能构想.

Trie树的操作主要有插入,删除,查找和销毁等。

想一下所有的功能,不难发现我们会频繁在一个节点的字孩子中查找,所以为了方便,我们直接在节点里面就定义一个查找函数TrieNode* find(char key)在当前节点的子孩子中寻找能与key匹配的节点,没有找到返回NULL.

还有插入操作就是在一个节点的孩子联表中插入一个新的指针,于是我们在节点里面在定义一个插入函数void insert(TrieNode* &newchild)王当前节点孩子中插入一个新的孩子newchild.

查找value[]:从根节点开始扎找value[0],找到的话继续向下查找,直至每个元素都找完,否则返回false。

插入value[]:先从根节点开始在还在查找value[0],找到的话,向下继续;没有找到,就建立一个新的节点,然后插入上一个节点中,继续向下查找,直到把value整个插入完成。

删除value[]:用一个栈来保存访问路径。从根节点开始找value[0],找到的话继续向下查找,直至找完,否则返回false,然后,开始压栈,如果第一次压栈发现栈顶有子孩子,说明value[strlen(value)-]为树中中间节点不能删除,返回false;如果栈顶没有孩子则将其删除,继续压栈直至栈中只有root,否则返回true;

销毁:


函数的功能实现方法很多,上面只供参考。

(3)实现.

/////////////////main.cpp

#include <iostream>
#include "Tree.h"
#include <cstring>

using namespace std;
//测试函数
void test() {
    Trie t;
    char a[20];
    int i = 0;
    while (i == 0) {
        if (i < 5)
            cout << "Input the data you want to insert: " << endl;
        while (i++ < 1) {
            cin >> a;
            t.insert(a, strlen(a));
        }
        cout << "prin: " << endl;
        t.prin();
        cout << endl << "Input the data you want to find: ";
        i = 3;
        while (i++ < 7) {
            cin >> a;
            if (t.find(a, strlen(a)) == NULL)
                cout << "No find " << a << "!!" << endl;
            else
                cout << "Yes find " << a << endl;
        }
        cout << "Input the data you want to delete: ";
        cin >> a;
        t.del(a, strlen(a));
        t.prin();
        cout << endl;
    }
}


int main() {
    test();
    return 0;
}

////////////Trie.h

#ifndef TREE_H_INCLUDED
#define TREE_H_INCLUDED

#include <vector>
#include <list>

using namespace std;

class Node {
public:
    char data;
    list<Node*> p;


public:
    Node() {}
    Node(char value):data(value) {}
    Node* find(char value);
    void insert(Node*&);
};

class Trie {
    Node* root;


public:
    Trie();
    ~Trie() {remove();}
    Node* find(char*, int size); //查找
    bool insert(char*, int size); //插入
    bool del(char*, int size); //删除
    bool remove(); //销毁

    void prin(); //测试打印函数
};

#endif
/////////////Trie.cpp
#include "Tree.h"
#include <cstring>
#include <iostream>
#include <stdlib.h>
#include <stack>


Node* Node::find(char value) {
   list<Node*>::iterator t;
   for (t=p.begin(); t!=p.end(); t++)
        if (value == (*t)->data)
            return *t;
   return NULL;
}


void Node::insert(Node* &newnode) {
    p.push_back(newnode);
}

Node* Trie::find(char* value, int size) {
    int j =-1;
    Node* p = root;
    while (++j != size) {
        p = p->find(value[j]);
        if (p == NULL)
            return NULL;
    }
    return p;
}


Trie::Trie() {
    root = new Node();
    root->data = '#';
}


bool Trie::insert(char* value, int size) {
    int i = 0, j =0;
    bool sign;
    Node* p, *temp = root;
    p = root->find(value[j]);
    while (j < size) {
        sign = false;
        if (p == NULL) {
            p = new Node(value[j++]);
            temp->insert(p);
            sign = true;
        }
        temp = p;
        if (sign)
            p = p->find(value[j]);
        else
            p = p->find(value[++j]);
    }
    return (sign && (size == j));
}


bool Trie::del(char* value, int size) {
    int j =-1;
    stack<Node*> s;
    Node* p = root, *pointer;
    while (++j != size) {
        s.push(p);
        p = p->find(value[j]);
        if (p == NULL)
            return false;
    }
    s.push(p);
    j = 0;
    while (s.size() > 1) {
        p = s.top();
        s.pop();
        int len = p->p.size();
        if (j == 0) {
            if (len != 0)
                return false;
            pointer = p;
            delete p;
            p = s.top();
            p->p.remove(pointer);
            continue;
        }
        if (len == 0) {
            pointer = p;
            delete p;
            p = s.top();
            p->p.remove(pointer);
        } else
            return true;
    }
}

bool Trie::remove() {
    stack<Node*> s;
    list<Node*>::iterator t;
    Node* temp = root;
    s.push(root);
    bool sign = false;
    while (!s.empty()) {
        s.pop();
        for (t=temp->p.begin(); t!=temp->p.end(); t++)
            s.push(*t);
        delete temp;
        if (s.empty())
            break;
        temp = s.top();
    }
    root = NULL;
    return true;
}


void Trie::prin() {
    stack<Node*> s;
    list<Node*>::iterator t;
    Node* temp = root;
    if (root == NULL) {
        std::cout << "empty tree" << std::endl;
        return;
    }
    s.push(root);
    bool sign = false;
    while (!s.empty()) {
        s.pop();
        for (t=temp->p.begin(); t!=temp->p.end(); t++)
            s.push(*t);
        if (s.empty())
            break;
        temp = s.top();
        std::cout << temp->data << "  ";
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值