📌  相关文章
📜  使用Trie对字符串(或单词)进行排序(1)

📅  最后修改于: 2023-12-03 14:49:51.865000             🧑  作者: Mango

使用Trie对字符串(或单词)进行排序

Trie是一种树状数据结构,通常用于文本及字符串中的单词查找。它可以快速地在大量字符串 (或句子)中查找目标单词,即在O(m)的时间复杂度内完成查找(其中m是目标单词的长度)。在本篇文章中,我们将介绍使用Trie对字符串进行排序的方法,以及如何通过Trie彻底了解它的工作原理。

Trie树的基本介绍
Trie树的定义

Trie树,也叫字典树,是一种有序树,用于保存关联数组,其中键通常是字符串。Trie树的核心优势在于它能够快速地找到具有共同前缀的字符串,如同搜索引擎中自动提示某一个单词一样。

Trie树的数据结构

Trie树的节点具有以下属性:

  • 字符串中的字符
  • 该节点的终止状态: 表示这个字符是不是一个词的结束字符
  • 一个指向该节点父亲的指针
  • 一个数组存储所有子节点

例如,下面是一个Trie树的图示:

   root
    / \
   t   a
  /     \
 o       n
/ \      / \
e *     y   e *
     / \
    a   t
      / \
     e   d *

其中,每个节点都代表一个字符,带*的节点表示词的终止状态。

具体来说,我们可以使用下面的结构体来表示一个Trie节点:

struct TrieNode {
    char val;                       //该节点代表的字符
    bool is_end;                    //标记该节点是否代表一个字符串的结束
    vector<TrieNode *> children;    //全部的子节点
    TrieNode(char c) : val(c), is_end(false), children(26, nullptr) {}
};
对字符串排序
思路

使用Trie树对字符串排序的思路十分简单,具体来说,我们按顺序遍历每个字符,在Trie树上找到对应节点,如果该节点已经存在,则表示前缀已经被添加到Trie树中,否则我们需要新建该节点并插入到Trie树中。

当插入字符串时,我们需要保留它在数组中的下标值,以便最终输出排序后的字符串。因此,我们可以使用vector来存储Trie树中每个节点代表的单词的下标值,并在Trie的终止状态(is_end==true)处取出下标值。

代码实现

下面是使用C++语言实现的对字符串排序的代码:

class Trie {
public:
    void insert(string word, int index) {
        TrieNode *cur = root;

        for (char c : word) {
            if (!cur->children[c - 'a']) 
                cur->children[c - 'a'] = new TrieNode(c);
            cur = cur->children[c - 'a'];
        }

        cur->is_end = true;
        cur->indicies.push_back(index);
    }

    vector<string> sort(vector<string> &words) {
        for (int i = 0; i < words.size(); i++)
            insert(words[i], i);

        vector<string> res;
        dfs(root, words, res);
        return res;
    }

private:
    struct TrieNode {
        char val;
        bool is_end;
        vector<int> indicies; 
        vector<TrieNode *> children;
        TrieNode(char c) : val(c), is_end(false), children(26, nullptr) {}
    };

    void dfs(TrieNode *root, vector<string> &words, vector<string> &res) {
        if (!root) return;
        if (root->is_end) {
            for (int idx : root->indicies) {
                res.push_back(words[idx]);
            }
        }

        for (int i = 0; i < 26; i++) {
            if (root->children[i]) {
                dfs(root->children[i], words, res);
            }
        }
    }

    TrieNode *root = new TrieNode(' ');
};
总结

本篇文章介绍了如何使用Trie树对字符串进行排序。利用Trie树这种高效的数据结构,我们可以实现O(mn)的时间复杂度来对n个长度为m的字符串进行排序。同时,通过对Trie树的讲解,我们好像了解了这种树状结构的工作原理,从而更好地掌握其应用。