【天天数据结构和算法】PHP中trie数据结构的使用场景和代码实例

一、trie介绍

Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树。

Trie一词来自retrieve,发音为/tri:/ “tree”,也有人读为/tra?/ “try”。

Trie树可以利用字符串的公共前缀来节约存储空间。如下图所示,该trie树用10个节点保存了6个字符串tea,ten,to,in,inn,int。

在该trie树中,字符串in,inn和int的公共前缀是“in”,因此可以只存储一份“in”以节省空间。当然,如果系统中存在大量字符串且这些字符串基本没有公共前缀,则相应的trie树将非常消耗内存,这也是trie树的一个缺点。

Trie树的基本性质可以归纳为:

(1)根节点不包含字符,除根节点意外每个节点只包含一个字符。

(2)从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。

(3)每个节点的所有子节点包含的字符串不相同。

二、trie的优点

1.查找或匹配字符串时 时间复杂度只和树的深度有关,和节点数量无关。

2.所以,在查找海量数据,或匹配数据,或过滤数据中有很好的实现。

三、php代码实现

Trie.php

<?php

/**
 * Created by PhpStorm.
 * User: jysdhr
 * Date: 2017/7/4
 * Time: 9:57
 * Description:PHP实现trie字典数据结构
 */
include "TrieNode.php";

class Trie
{
    private $root;

    public function __construct()
    {

        $this->root = new TrieNode();
    }

    public function foreach_trie()
    {
        echo "<pre>";
        print_r($this->root);
    }

    public function insert($str)
    {
        $this->__insert($this->root, $str);
    }

    public function search(string $str): bool
    {
        return $this->__search($this->root, $str);
    }

    private function __insert(&$node, $str)
    {
        if (strlen($str) == 0)
            return;
        //第一个字符,插入哪一个分叉
        $k = ord(substr($str, 0, 1)) - ord(‘a‘);
        if (!isset($node->childs[$k]) || $node->childs[$k] == NULL) {
            //如果分叉不存在则重新开辟分叉
            $node->childs[$k] = new TrieNode();
            //记录字符
            $node->childs[$k]->nodeChar = $k;
            $node->childs[$k]->is_end = strlen($str) == 1 ? true : false;
        }
        $nextWord = substr($str, 1);
        $this->__insert($node->childs[$k], $nextWord);
    }

    /**
     * @Description:查找str是否存在树中
     * @User:jysdhr
     */
    private function __search($node, $str)
    {
        if (strlen($str) == 0)
            return false;
        //首先对str进行拆分
        $k = ord(substr($str, 0, 1)) - ord(‘a‘);
        if (isset($node->childs[$k])) {
            $nextWord = substr($str, 1);
            if (strlen($str) == 1) {
                //匹配最后一个字符
                if ($node->childs[$k]->is_end)
                    return true;
            }
            return $this->__search($node->childs[$k], $nextWord);
        }
        return false;
    }

}

TrieNode.php

<?php

/**
 * Created by PhpStorm.
 * User: jysdhr
 * Date: 2017/7/4
 * Time: 10:01
 * Description:
 */
class TrieNode
{
    public  $nodeChar,$childs,$is_end;
    public function __construct()
    {
        $this->childs = array();
    }
}

testTrie.php

<?php
// 测试文件demo.php
include "Trie.php";
$str = file_get_contents(‘bbe.txt‘);//将整个文件内容读入到一个字符串中
$badword = explode(" ", $str);//转换成数组
$trie = new Trie();
foreach ($badword as $word)
    $trie->insert($word);

// array_combine() 函数通过合并两个数组来创建一个新数组,其中的一个数组是键名,另一个数组的值为键值。如果其中一个数组为空,或者两个数组的元素个数不同,则该函数返回 false。
// array_fill() 函数用给定的值填充数组,返回的数组有 number 个元素,值为 value。返回的数组使用数字索引,从 start 位置开始并递增。如果 number 为 0 或小于 0,就会出错。
//$badword1 = array_combine($badword,array_fill(0,count($badword),‘*‘));

$test_str = ‘knowledgeasdad‘;
$start_time = microtime(true);

var_dump(in_array($test_str,$badword));
$end_time = microtime(true);
echo ($end_time-$start_time).‘</br>‘;

$start_time1 = microtime(true);
var_dump($trie->search($test_str));
$end_time1 = microtime(true);

echo ($end_time1-$start_time1).‘</br>‘;

$start_time2 = microtime(true);
foreach ($badword as $value){
    if ($value == $test_str){
        echo ‘1‘;
        break;
    }
}
$end_time2 = microtime(true);

echo ($end_time2-$start_time2).‘</br>‘;

?>

以上是匹配圣经中的一个单词的实例,in_array是遍历匹配  ,当匹配单词越晚出现,耗时越久,当匹配单词不存在时,耗时不可接受。

trie的表现比较稳定,无论是否存在,或匹配单词出现的早晚都与运行时间无太大影响,只与单词长度有关。(效果最好,最稳定)

遍历查找基本与in_array效果相当。

四、总结

所以在项目开发中,在做到敏感词屏蔽,统计词频,字典等功能时,可以考虑运用trie数据结构生成一个trie树序列化存储起来,待更新词库时重新维护trie树,是不是觉得也不是很困难呢,加油。

时间: 2024-08-03 01:05:01

【天天数据结构和算法】PHP中trie数据结构的使用场景和代码实例的相关文章

编程算法 - 数组中只出现一次的数字 代码(C)

数组中只出现一次的数字 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 一个整型数组里除了两个数字以外, 其他的数字都出现了两次. 请写程序找出这两个只出现一次的数字. 如果从头到尾依次异或数组中的每一个数字, 那么最终的结果刚好是那个只出现一次的数字. 根据结果数组二进制某一位为1, 以此分组, 为1的一组, 为0的一组, 再重新进行异或. 最后得出两个结果. 时间复杂度O(n). 代码: /* * main.cpp * * Create

C#控制台程序中处理2个关闭事件的代码实例

应用场景 我们开发的控制台应用,在运行阶段很有可能被用户Ctrl+C终止或是被用户直接关闭.如果我们不希望用户通过Ctrl+C终止我们的程序,就需要对Ctrl+C或关闭事件作处理. 处理方法 在.net平台下Console类有个CancelKeyPress事件可以处理Ctrl+C,不过对于直接关闭控制台应用,这种处理就无能为力了. 不过Windows API中有个SetConsoleCtrlHandler函数可以处理这两种关闭事件. C#处理代码如下: 代码如下: static class Pr

这谈的数据结构和算法2好基友[数据结构和算法]

在本文中,小乌龟的数据结构和算法的教学视频学习笔记 第一章:谈谈数据结构和算法这2个好基友 一.聊聊数据结构 1.为什么学数据结构?编程能力有质的飞越,不再停留在调用现成的API,做一个上档次的程序猿. 2.什么是数据结构?数据结构是一门研究非数值计算的程序设计问题中的操作对象,以及他们之间的关系和操作等相关问题的学科. 思考:好吧,简单来说程序设计 =数据结构 + 算法,数据结构就是关系,就是数据元素之间存在的一种或多种特定关系的集合. 3.数据结构分为逻辑结构和物理结构,前者指数据对象中数据

数据结构和算法 (二)数据结构基础、线性表、栈和队列、数组和字符串

Java面试宝典之数据结构基础 —— 线性表篇 一.数据结构概念 用我的理解,数据结构包含数据和结构,通俗一点就是将数据按照一定的结构组合起来,不同的组合方式会有不同的效率,使用不同的场景,如此而已.比 如我们最常用的数组,就是一种数据结构,有独特的承载数据的方式,按顺序排列,其特点就是你可以根据下标快速查找元素,但是因为在数组中插入和删除元素会 有其它元素较大幅度的便宜,所以会带来较多的消耗,所以因为这种特点,使得数组适合:查询比较频繁,增.删比较少的情况,这就是数据结构的概念.数据结构 包括

数据结构与算法(1)- 数据结构概览

声明:虽然本系列博客与具体的编程语言无关.但是本文作者对c++相对比较熟悉,其次是java,所以难免会有视角上的偏差.举例也大多是和这两门语言相关. 今天先来看看有哪些常见的数据结构(C++ STL视角,其他应该也大同小异吧.哈哈,我猜的!).所以之后的内容大多从STL出发,然后顺便对比下java中对应的数据结构.作为一名合格的软件开发人员,我们有时不需要深入对这些结构进行深度了解(原子级了解),但是至少我们得知道这些结构的基本原理.构成以及代价(时间空间代价).如果你想对这些结构深度了解,建议

EasyUI中combobox的使用方法和一个代码实例

Combobox用法和方法参数: 1. 需要引入class=" easyui-combobox" 2. 参数设置需要在data-options中设置 3. 属性参数配置: valueField:基础数据值名称绑定到Combobox(提交值) textField:基础数据的字段名称绑定的Combobox(显示值) mode:定义当文本改变时如何加载列表数据,当设置为remote模式下,什么类型的用户将被发送http请求参数名为'q'的服务器,以获取新的数据. url:从远程URL来加载列

数据结构与算法----树(中)

hey,我们继续上篇文章学习树.上篇文章,我们主要讲了树的一些基本概念.定义,抽象数据结构.今天,我们要学习它的数据结构,让我们开始学习吧. 树的存储结构: 一讲到存储结构,就会想到顺序存储与链式存储,让我们来回顾一下它们的概念.顺序存储,就是用一组连续的内存地址来存储数据元素,我们一般用一维数组来表示连续的内存地址.链式存储,用一块儿空闲的内存区域来存放数据元素.存放数据的地址不需要连续,通过元素中的指针域来表示逻辑关系.像之前我们学习的线性表,因为它是有唯一先驱.唯一后继.所以,顺序存储可以

数据结构和算法 (二)数据结构基础之树、二叉树

Java面试宝典之二叉树的实现 我们接着上一篇数据结构继续讲解.本章系数据结构之树与二叉树,从这章开始,我们就要介绍非线性结构了,这些内容理解起来比线性表稍难一些,我尽量写的通俗一些,如果读的过程中有任何问题,请按上述方式联系我! 一.树 树 形结构是一类重要的非线性结构.树形结构是结点之间有分支,并具有层次关系的结构.它非常类似于自然界中的树.树结构在客观世界中是大量存在的,例如家 谱.行政组织机构都可用树形象地表示.树在计算机领域中也有着广泛的应用,例如在编译程序中,用树来表示源程序的语法结

Python中的元组,字典、计算器代码实例及python2与python3的区别

1.计算器实例 #/usr/bin/env python # -*- coding:utf-8 -*- # @time   :2018/1/22 21:09 # @Author :FengXiaoqing # @file   :jsq.py def add(string):     total = 0     numbers = []     numbers += string.split("+")     for num in numbers:         total += in