• trie树前缀匹配


    题目:搜索功能一般都有根据你的输入快速显示对应关键字的功能,比如你输入”刘”, 搜索框的下拉列表会显示“刘德华”,”刘若英”,”刘欢”等,你继续输入‘德’,将查询关键字变成”刘德”,显示的候选字列表会显示”刘德华”,”刘德华专辑”,”刘德华演唱会”等。如果让你用算法和数据结构实现这个功能(用户每次多输入一个字母都可以得到最佳的查询结果,每次返回最多不超过10条),你会如何设计。能否用程序实现。

    一、算法设计
    1) 采用trie树来实现前缀匹配,如果匹配成功,返回所有前缀相同的字符串,否则返回空;
    2) 如果匹配上的字符串超过10条,用堆排找出搜索热度前10的字符串(这部分没有写代码);

    二、代码与运行结果

    代码参考了网络上他人的代码成果,针对题目进行了修改,特此声明。
    完整代码。

      1 #include <iostream>
      2 #include <vector>
      3 using namespace std;
      4 
      5 const int sonNums = 26;
      6 
      7 struct node
      8 {
      9     bool endFlag;
     10     node* sons[sonNums];
     11 
     12     node() 
     13     { 
     14         endFlag = false; 
     15         for ( int i = 0; i < sonNums; i++ )
     16             sons[i] = NULL;
     17     }
     18 };
     19 
     20 class Trie
     21 {
     22 public:
     23     void insert(const char* str);
     24     bool query(const char* str);
     25     void getStr(node *tree, vector<char*>& ret, vector<char> prefix);
     26     Trie() { root = new node();}
     27 
     28 private:
     29     node *root;
     30 };
     31 
     32 void Trie::insert(const char* str)
     33 {
     34     cout << "insert: " << str << endl;
     35 
     36     node *p = root;
     37     while( *str != '\0')
     38     {
     39         int index = *str - 'a';
     40         if ( p->sons[index] == NULL )
     41         {
     42             p->sons[index] = new node();
     43         }
     44         p = p->sons[index];
     45         str++;
     46     }
     47     p->endFlag = true;
     48 }
     49 
     50 bool Trie::query(const char* str)
     51 {
     52     node *p = root;
     53     const char *tmp = str;
     54     vector<char*> ret;
     55     vector<char> prefix;
     56 
     57     int index = *str - 'a';
     58     if ( !p->sons[index])
     59     {
     60         cout << "\nprefix query for \"" << tmp << "\" failed" << endl;
     61         return false;
     62     }
     63 
     64     while( *str != '\0' && p )
     65     {
     66         int index = *str - 'a';
     67         if ( p->sons[index] )
     68         {
     69             prefix.push_back(*str);
     70         }
     71 
     72         p = p->sons[index];
     73         str++;
     74     }
     75 
     76     if ( p != NULL )
     77     {
     78         getStr( p, ret, prefix );
     79 
     80         vector<char*>::iterator iter;
     81         cout << "\nprefix query for \""<< tmp << "\", results:" << endl;
     82         for ( iter = ret.begin(); iter != ret.end(); iter++ )
     83             cout << *iter << endl;
     84 
     85         return true;
     86     }
     87     else
     88     {
     89         cout << "\nprefix query for \"" << tmp << "\" failed" << endl;
     90         return false;
     91     }
     92 }
     93 
     94 void Trie::getStr(node *tree, vector<char*>& ret, vector<char> prefix)
     95 {
     96     if ( tree->endFlag )
     97     {    
     98         char *str = new char[prefix.size()+1];
     99         int i;
    100         for ( i=0; i<prefix.size(); i++ )
    101             str[i] = prefix[i];
    102         str[i] = '\0';
    103         ret.push_back(str);
    104     }
    105 
    106     node *p = tree;
    107     for (int i = 0; i < 26; i++)
    108     {
    109         if ( p->sons[i] != NULL )
    110         {
    111             prefix.push_back('a'+i);
    112             getStr( p->sons[i], ret, prefix);
    113         }
    114     }
    115 }
    116 
    117 int main()
    118 {
    119     Trie t;
    120     t.insert("a");
    121     t.insert("abandon");
    122     t.insert("abandoned");
    123     t.insert("abashed");
    124 
    125     t.query("a");
    126     t.query("aba");
    127     t.query("aban");
    128     t.query("ban");
    129     
    130     return 0;
    131 }
    View Code

    运行结果:

     1 insert: a
     2 insert: abandon
     3 insert: abandoned
     4 insert: abashed
     5 
     6 prefix query for "a", results:
     7 a
     8 abandon
     9 abandoned
    10 abanshed
    11 
    12 prefix query for "aba", results:
    13 abandon
    14 abandoned
    15 abanshed
    16  
    View Code

    三、存在的问题

    1) 中文处理比较麻烦,只实现了英文字母的匹配;
    2) 对每个节点开辟了26个分支,用分支下标表示字母,这种方式节省了时间浪费了空间,如果要节省空间应采用链表;
    3) 为了挑选最热的10个字符串,我把所有的匹配结果都找出来然后用堆排找出最热的10个字符串,我没想到更好的方法;
    4)未考虑查询扩展,比如汉字拼音扩展。

  • 相关阅读:
    Redis Cluster笔记
    http协议之 COOKIE
    lor框架代码分析
    PHP--SPL扩展学习笔记
    lua协程----ngx-lua线程学习笔记
    设计模式
    eclipse中使用maven创建springMVC项目
    一般处理程序里使用session对象
    .Dot NET Cored简介
    Spring 依赖注入(基本注入和自动适配注入)
  • 原文地址:https://www.cnblogs.com/simonote/p/3086958.html
Copyright © 2020-2023  润新知