最近在一个项目中需要针对上百万条(大约在800W条)的字符串进行相关的处理。该字符串是以文本的形式存放在本地硬盘,并且更新频率为20分钟一次。

具体需求:

1、判断某一个字符串是否存在这800W条字符串中,时间要求在5ms以内

2、根据字符串前缀,返回包含此前缀的10-100条字符串。时间要求在5ms以内

3、占用内存要小

本人接到此需求第一反应用List,或者二叉树啥的。结果效率慢得死,

后经过大量资料查阅,发现采用DAWG(Directed Acyclic Word Graph)和Trie可以很快速的查找到相应的字符串。

主要思路:将每个字符串的字符进行创建相应的Node,如果有相同的字符则放置在同一个节点中。

例如有6个字符串:Top, Tops, Tap, Tapc, Topa and Taps。根据DAWG和Trie的原理将创建成如下一个Tree

在添加字符串的时候,根据字符串的字符创建树形结构,每个节点代表一个字符。如果是相同字符时,则存储在同一个节点中。这样可少占用内存。

在进行判断字符串是否存在时,只需要依次判断字符串的节点是否存在。

首先创建一个字符节点类LetterNode. 该类主要用于存储相关字符节点的信息:子节点,父节点等等。

View Code

    /// <summary>
    /// The Dawg's letter node
    /// </summary>
    internal sealed class LetterNode
    {
        private const int InitialSpreadCapacity = 4;

private Dictionary<char, LetterNode> _childNodes;

/// <summary>
        /// Initializes a new instance of the <see cref="LetterNode"/> class.
        /// </summary>
        public LetterNode()
        {
        }

/// <summary>
        /// Initializes a new instance of the <see cref="LetterNode"/> class.
        /// </summary>
        /// <param name="letter">The letter.</param>
        public LetterNode(char letter)
            : this()
        {
            Letter = letter;
        }

/// <summary>
        /// The node's child nodes
        /// </summary>
        public Dictionary<char, LetterNode> ChildNodes
        {
            get
            {
                if (this._childNodes == null)
                {
                    this._childNodes = new Dictionary<char, LetterNode>(InitialSpreadCapacity);
                }
                return this._childNodes;
            }
        }

/// <summary>
        /// Describe the node is end of the word.
        /// </summary>
        public bool IsEndOfWord
        {
            get;
            set;
        }

/// <summary>
        /// Gets or sets the letter.
        /// </summary>
        /// <value>The letter.</value>
        public char Letter
        {
            get;
            set;
        }

/// <summary>
        /// Gets or sets the parent of this node.
        /// </summary>
        /// <value>The parent.</value>
        public LetterNode Parent
        {
            get;
            set;
        }

/// <summary>
        /// Gets the word defined at this element.
        /// </summary>
        /// <value>The word ending here (if this is a word, or the empty string.</value>
        public string Word
        {
            get
            {
                if (IsEndOfWord)
                {
                    StringBuilder sb = new StringBuilder(20);
                    sb.Append(Letter);
                    var node = Parent;
                    while (node != null)
                    {
                        sb.Insert(0, node.Letter);
                        node = node.Parent;
                    }
                    return sb.ToString();
                }
                else
                {
                    return string.Empty;
                }
            }
        }

}

接下来实现Dawg针对字符串创建树形节点。思路是参照上图。

        /// <summary>
        /// Adds the specified item.
        /// </summary>
        /// <param name="item">The item.</param>
        public void Add(string item)
        {
            if (string.IsNullOrEmpty(item))
            {
                return;
            }

item = item.ToLowerInvariant();

LetterNode node = null, parentNode = null;

if (!this._rootNodes.TryGetValue(item[0], out node))
            {
                node = new LetterNode(item[0]);
                this._rootNodes[item[0]] = node;
            }

for (int i = 1; i < item.Length; ++i)
            {
                parentNode = node;
                if (!node.ChildNodes.TryGetValue(item[i], out node))
                {
                    node = new LetterNode(item[i]);
                    node.Parent = parentNode;
                    parentNode.ChildNodes[item[i]] = node;
                }
            }

if (!node.IsEndOfWord)
            {
                node.IsEndOfWord = true;
                this._count++;
            }
        }

判断字符串是否存在:

        private LetterNode SearchPrefixLetterNode(string prefix)
        {
            prefix = prefix.ToLowerInvariant();

Dictionary<char, LetterNode> nodes = this._rootNodes;

LetterNode node = null;

for (int i = 0; i < prefix.Length; ++i)
            {
                if (nodes.TryGetValue(prefix[i], out node))
                {
                    nodes = node.ChildNodes;
                }
                else
                {
                    return null;
                }
            }
            return node;
        }

        public bool Contains(string item)
        {
            var node = this.SearchPrefixLetterNode(item);
            return node != null && node.IsEndOfWord;
        }

代码可从此处下载:http://files.cnblogs.com/foolishfox/Dawg.zip

转载于:https://www.cnblogs.com/foolishfox/archive/2011/07/13/2105405.html

采用DAWG方式在大批量字符串中查询字符串相关推荐

  1. 如何用js获取浏览器URL中查询字符串的参数

    首先要知道Location这个对象以及这个对象中的一些属性: href:设置或返回完整的url.如本博客首页返回http://www.cnblogs.com/wymninja/ host:设置或返回主 ...

  2. flask带有传入参数既有URL还有其他参数类型:建议使用方式二(flask 使用查询字符串的方式)

    方式一: 例如此时,既需要传递带有URL的训练数据地址,还需要传入其他的参数 由于path类型会将所有的 / 不忽略,那么此时的 traget_cls 参数会被忽略,于是我们将带有URL的参数(即pa ...

  3. php 字符串中插入字符,PHP字符串中插入子字符串方法总结[原创]_php技巧

    本文实例讲述了PHP字符串中插入子字符串方法.分享给大家供大家参考,具体如下: 首先来看看一个网上常见的方法: 方法一:字符串遍历 function str_insert($str, $i, $sub ...

  4. Java案例——统计字符串中每个字符串出现的次数

    统计字符串中每个字符串出现的次数 需求: 1.键盘录入一个字符串,要求统计字符串中每个字符串出现的次数 举例:键盘录入"aababcabcdabcde" 在控制台输出:" ...

  5. 查找两个字符串中相同字符串_使两个字符串相同的最低成本

    查找两个字符串中相同字符串 Problem statement: 问题陈述: Given two strings string1 and string2 find the minimum cost r ...

  6. hiho1482出勤记录II(string类字符串中查找字符串,库函数的应用)

    string类中有很多好用的函数,这里介绍在string类字符串中查找字符串的函数. string类字符串中查找字符串一般可以用: 1.s.find(s1)函数,从前往后查找与目标字符串匹配的第一个位 ...

  7. URL 中,查询字符串与HTML实体冲突,可能带来的问题.

    此问题相关信息(我不放在最前面,似乎有些朋友会找不到的样子.) IE10+, Safari5.17+, Firefox4.0+,Opera12+, Chrome7+ 已经按新标准实现. 所以就没有这个 ...

  8. Elasticsearch:使用新的 wildcard 字段更快地在字符串中查找字符串 - 7.9 新功能

    在 Elasticsearch 7.9 中,我们将引入一种新的 "wildcard" 字段类型,该字段类型经过优化,可在字符串值中快速查找模式.这种新的字段类型采用了一种全新的方式 ...

  9. php 查字符串,PHP查询字符串技巧分享

    对于一个经验丰富的PHP程序员来说,实现字符串的查询功能已经不是什么难事了.在这里我们将会介绍一种PHP查询字符串的捷径技巧,供大家参考. RL传递变量对于程序员来说已经是司空见惯的事情,很多人会因此 ...

最新文章

  1. [二叉树] 判断一个二叉树是否是平衡(剑指offer39)
  2. java数据生成excel_Java 数据库数据生成Excel
  3. 下载的java游戏怎么运行不了_java运行环境下载
  4. python语句分为_python以什么划分语句块
  5. 密码学专题 非对称加密算法指令概述 DSA算法指令
  6. ltspice 双脉冲_焊烟脉冲布袋式除尘器制作
  7. signature=0727ee8cc38ba70036807ebbc0b018d6,NMSSM+
  8. 鸿蒙app安卓版包,支付宝鸿蒙版本下载-支付宝鸿蒙app最新版 v10.2.8.7000-优盘手机站...
  9. 斯诺登:澳大利亚的监视政策比NSA还下流
  10. GCC 编译安装在线文档
  11. 动易2007后台模板上传任意文件漏洞
  12. Linux 串口驱动 问题
  13. 动态规划算法——2020美团校招合并金币算法
  14. 科学家学习天竺葵特性,研制出用水分子来驱动的微型机器人
  15. 极致Review,阿里绩效管理的核心工具
  16. 造成BGA焊接不良问题有哪些?
  17. 对于爱情的透彻性理解:恋爱变成一场无间道...
  18. PHP检测及判断手机登录用户是安卓或爱疯(iPhone)客户端
  19. WWDC 2020 特别活动主题演讲 全套源文件下载 视频、幻灯片图片、中英文全稿 WWDC 2020 Special Event Keynote
  20. Python编程(0-1)——Eric6界面初识

热门文章

  1. python 英语分词_英文分词算法(Porter stemmer)
  2. java环境变量win7_win7如何配置jdk环境变量|win7配置java环境变量的方法
  3. 计算机硬件 软件指什么,什么叫软件,什么又叫硬件呀?(是电脑知识)
  4. python socket发包_python 多线程tcp udp发包 Dos工具。
  5. 【筛法求素数】HDU-1239 Calling Extraterrestrial Intelligence Again
  6. 不知道起什么标题 03
  7. 在中文版Windows 10 中安装日语支持
  8. 纸牌博弈问题 动态规划
  9. VTK:数据动画用法实战
  10. Apollo坐标系转换