输入法核心数据结构及算法的设计

简介:

输入法只需要实现三个非常重要的函数即可:

 

[java]   view plain copy
  1. /** 
  2.      * 插入一个单词 
  3.      *  
  4.      * @param term 
  5.      *            要插入的单词 
  6.      */  
  7. public void insert(String term);  
  8.   
  9. /** 
  10.      * 删除一个单词 
  11.      *  
  12.      * @param term 
  13.      *            要删除的单词 
  14.      */  
  15. public void delete(String term);  
  16. /** 
  17.      * 获取提示的词条 
  18.      *  
  19.      * @param preTerm 
  20.      *            用户已输入的词条 
  21.      * @return 提示词条 
  22.      */  
  23. public List<String> promptsTerms(String preTerm);  

 

当然在考虑删除某个单词的时候,由于有很多单词共享相同的前缀,所以不能轻易删除,具体删除的情况可以分为三种:完全独立型、完全共享型、部分共享型。大家自己去思考吧,还是很简单的,我就不说了~

 

其中一种实现思路可以为每个单词节点设计一个计数器,delete的时候就把计数减1,当计数为0时就删除。但这种方法有个缺陷:即每个节点都要多设置一个计数的空间,节点当然不少,无形中对空间会造成比较大的浪费。而且对于输入法而言delete函数并不常用,为了一个极少使用的函数浪费这么多空间肯定是不合适的。特别是对于手机而言,本身内存就已经很少了,这样的设计肯定是bad smell。那么,我们采用另外一种方法去解决了这个问题~

 

废话我就不太多说了,我觉得用代码描述更为直观,大家有什么问题直接研究代码吧~

[java]   view plain copy
  1. package com.algorithm;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.HashMap;  
  5. import java.util.List;  
  6. import java.util.Map;  
  7. import java.util.Stack;  
  8.   
  9. /** 
  10.  * 共享前缀树PrefixTree 
  11.  *  
  12.  * E-mail:530025983@qq.com 2011-5-28 
  13.  *  
  14.  * @author MONKEY_D_MENG 
  15.  *  
  16.  */  
  17. public class PrefixTree  
  18. {  
  19.     /* 利用Hash表能够O(1)时间内找到下一个字符的位置 */  
  20.     private Map<Byte, PrefixTree> wordTable = new HashMap<Byte, PrefixTree>();  
  21.   
  22.     /* 到这个节点为止是否是一个完整的单词 */  
  23.     private boolean isWord = false;  
  24.   
  25.     /** 
  26.      * 插入一个单词 
  27.      *  
  28.      * @param term 
  29.      *            要插入的单词 
  30.      */  
  31.     public void insert(String term)  
  32.     {  
  33.         if (null == term)  
  34.         {  
  35.             return;  
  36.         }  
  37.   
  38.         /* 将单词转化为字符串处理 */  
  39.         byte[] termChars = term.getBytes();  
  40.         PrefixTree current = this;  
  41.         for (byte ch : termChars)  
  42.         {  
  43.             if (!current.wordTable.containsKey(ch))  
  44.             {  
  45.                 PrefixTree next = new PrefixTree();  
  46.                 current.wordTable.put(ch, next);  
  47.                 current = next;  
  48.             }  
  49.             else  
  50.             {  
  51.                 current = (PrefixTree) current.wordTable.get(ch);  
  52.             }  
  53.         }  
  54.   
  55.         /* 设置到该节点止为单词的标志 */  
  56.         current.isWord = true;  
  57.     }  
  58.   
  59.     /** 
  60.      * 删除一个单词 
  61.      *  
  62.      * @param term 
  63.      *            要删除的单词 
  64.      */  
  65.     public void delete(String term)  
  66.     {  
  67.         if (null == term)  
  68.         {  
  69.             return;  
  70.         }  
  71.   
  72.         /* 将单词转化为字符串处理 */  
  73.         byte[] termChars = term.getBytes();  
  74.         PrefixTree current = this;  
  75.         PrefixTree fromDelete = this;  
  76.         PrefixTree next = this;  
  77.         int indexDelete = 0;  
  78.         int index = 0;  
  79.   
  80.         for (index = 0; index < termChars.length; ++index)  
  81.         {  
  82.             if (!current.wordTable.containsKey(termChars[index]))  
  83.             {  
  84.                 return;  
  85.             }  
  86.             else  
  87.             {  
  88.                 current = (PrefixTree) current.wordTable.get(termChars[index]);  
  89.             }  
  90.             /* 记录要删除的节点位置,注意不能到最后才判断,因为要删除这个单词最后的节点的isWord肯定被转为了true */  
  91.             if (current.isWord && index != termChars.length - 1)  
  92.             {  
  93.                 fromDelete = current;  
  94.                 indexDelete = index + 1;  
  95.             }  
  96.         }  
  97.   
  98.         /* 有后缀节点,说明被其他单词共享了前缀 */  
  99.         if (current.wordTable.size() != 0)  
  100.         {  
  101.             current.isWord = false;  
  102.             return;  
  103.         }  
  104.   
  105.         /* 删除所有不共享的后缀节点 */  
  106.         for (current = fromDelete, index = indexDelete; index < termChars.length; ++index)  
  107.         {  
  108.             next = current.wordTable.get(termChars[index]);  
  109.             current.wordTable.remove(termChars[index]);  
  110.             current = next;  
  111.             current.isWord = false;  
  112.         }  
  113.     }  
  114.   
  115.     /** 
  116.      * 获取提示的词条 
  117.      *  
  118.      * @param preTerm 
  119.      *            用户已输入的词条 
  120.      * @return 提示词条 
  121.      */  
  122.     public List<String> promptsTerms(String preTerm)  
  123.     {  
  124.         if (null == preTerm)  
  125.         {  
  126.             return null;  
  127.         }  
  128.   
  129.         PrefixTree current = this;  
  130.         List<String> words = new ArrayList<String>();  
  131.         Stack<Byte> stack = new Stack<Byte>();  
  132.   
  133.         /* 将单词转化为字符串处理 */  
  134.         byte[] termChars = preTerm.getBytes();  
  135.         for (byte ch : termChars)  
  136.         {  
  137.             if (!current.wordTable.containsKey(ch))  
  138.             {  
  139.                 return null;  
  140.             }  
  141.             else  
  142.             {  
  143.                 current = (PrefixTree) current.wordTable.get(ch);  
  144.             }  
  145.         }  
  146.   
  147.         /* 如果本身输入的已经是一个单词了,需要先记录,由于后面处理时要加前缀,这个地方只给个空串即可 */  
  148.         if (current.isWord)  
  149.         {  
  150.             words.add("");  
  151.         }  
  152.   
  153.         /* 递归地遍历,寻找所有匹配的单词 */  
  154.         this.traversalTree(current, stack, words);  
  155.   
  156.         /* 将每个单词都加上前缀 */  
  157.         for (int index = 0; index < words.size(); ++index)  
  158.         {  
  159.             words.set(index, preTerm + words.get(index));  
  160.         }  
  161.   
  162.         return words;  
  163.     }  
  164.   
  165.     /** 
  166.      * 递归生成所有后缀的单词 
  167.      *  
  168.      * @param current 
  169.      *            当前的根节点 
  170.      * @param words 
  171.      *            单词列表 
  172.      */  
  173.     private void traversalTree(PrefixTree current, Stack<Byte> stack,  
  174.             List<String> words)  
  175.     {  
  176.         for (byte ch : current.wordTable.keySet())  
  177.         {  
  178.             stack.push(ch);  
  179.   
  180.             /* 遇到是单词的标志 */  
  181.             if (current.wordTable.get(ch).isWord)  
  182.             {  
  183.                 /* 记录单词 */  
  184.                 words.add(stackToWord(stack));  
  185.             }  
  186.   
  187.             /* 如果还有后续节点则递归 */  
  188.             if (current.wordTable.get(ch).wordTable.size() != 0)  
  189.             {  
  190.                 this.traversalTree(current.wordTable.get(ch), stack, words);  
  191.             }  
  192.             stack.pop();  
  193.         }  
  194.     }  
  195.   
  196.     /** 
  197.      * 输出从栈底到栈顶的一条路径,即为一个单词 
  198.      *  
  199.      * @param stack 
  200.      *            栈 
  201.      * @return 栈中所存储的单词 
  202.      */  
  203.     private String stackToWord(Stack<Byte> stack)  
  204.     {  
  205.         String word = "";  
  206.         for (byte ch : stack)  
  207.         {  
  208.             word += (char) ch;  
  209.         }  
  210.         return word;  
  211.     }  
  212. }  
  213. package com.algorithm;  
  214.   
  215. import java.util.List;  
  216.   
  217. /** 
  218.  * 测试代码 
  219.  *  
  220.  * E-mail:530025983@qq.com 2011-5-28 
  221.  *  
  222.  * @author MONKEY_D_MENG 
  223.  *  
  224.  */  
  225. public class Main  
  226. {  
  227.     public static void main(String[] args)  
  228.     {  
  229.         PrefixTree prefixTree = new PrefixTree();  
  230.         List<String> words;  
  231.   
  232.         prefixTree.insert("mon");  
  233.         prefixTree.insert("money");  
  234.         prefixTree.insert("monkey");  
  235.         prefixTree.insert("monkey1");  
  236.         prefixTree.insert("monkey2");  
  237.         prefixTree.insert("monkey3");  
  238.         prefixTree.insert("monkey4");  
  239.         prefixTree.insert("monkey5");  
  240.   
  241.         prefixTree.delete("money");  
  242.         words = prefixTree.promptsTerms("mon");  
  243.   
  244.         for (String word : words)  
  245.         {  
  246.             System.out.println(word);  
  247.         }  
  248.     }  
  249. }  

 

本文转自莫水千流博客园博客,原文链接:http://www.cnblogs.com/zhoug2020/p/3320221.html,如需转载请自行联系原作者
相关文章
|
3月前
|
机器学习/深度学习 算法 数据挖掘
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构。本文介绍了K-means算法的基本原理,包括初始化、数据点分配与簇中心更新等步骤,以及如何在Python中实现该算法,最后讨论了其优缺点及应用场景。
206 6
|
3月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
107 1
|
25天前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
83 29
|
25天前
|
存储 算法 C语言
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
92 25
|
25天前
|
存储 人工智能 算法
C 408—《数据结构》算法题基础篇—数组(通俗易懂)
408考研——《数据结构》算法题基础篇之数组。(408算法题的入门)
67 23
|
2月前
|
存储 运维 监控
探索局域网电脑监控软件:Python算法与数据结构的巧妙结合
在数字化时代,局域网电脑监控软件成为企业管理和IT运维的重要工具,确保数据安全和网络稳定。本文探讨其背后的关键技术——Python中的算法与数据结构,如字典用于高效存储设备信息,以及数据收集、异常检测和聚合算法提升监控效率。通过Python代码示例,展示了如何实现基本监控功能,帮助读者理解其工作原理并激发技术兴趣。
82 20
|
1月前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
54 2
|
3月前
|
存储 算法 搜索推荐
Python 中数据结构和算法的关系
数据结构是算法的载体,算法是对数据结构的操作和运用。它们共同构成了计算机程序的核心,对于提高程序的质量和性能具有至关重要的作用
115 33
|
3月前
|
数据采集 存储 算法
Python 中的数据结构和算法优化策略
Python中的数据结构和算法如何进行优化?
|
3月前
|
算法
数据结构之路由表查找算法(深度优先搜索和宽度优先搜索)
在网络通信中,路由表用于指导数据包的传输路径。本文介绍了两种常用的路由表查找算法——深度优先算法(DFS)和宽度优先算法(BFS)。DFS使用栈实现,适合路径问题;BFS使用队列,保证找到最短路径。两者均能有效查找路由信息,但适用场景不同,需根据具体需求选择。文中还提供了这两种算法的核心代码及测试结果,验证了算法的有效性。
157 23