`
achi217
  • 浏览: 10215 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

关于分词算法---双数组T树java实现

阅读更多
首先要声明的是, 这个代码我也参考过一个C++的实现, 不过, 他实在写的过于烦琐,一堆的模板代码, 和stl的使用。 幸好10年前摸过C/C++ 2年, 否则还真不知道他在干什么。 可惜这个代码有些致命的缺点是,字典需要生成后使用, 无法做动态的扩展。 不过呢, 动态加入一个新词, 性能是是致命的。 程序的工作模式是:
1. 通过build()函数,把所有的词生成数据,
2. 然后通过save()函数保存数据。
3. 使用的时候就可以用load()载入数据。

 

public class DoubelArrayTrie{

    // 节点信息
    private int            baseArray[];
    private int            checkArray[];
  
    // 保存节点已经使用
    private boolean        usedArray[];

    private int            nextCheckPos;
    private int            writeSize = 0;

    public void build(List<char[]> wordList, PreProcess process) {
        if (wordList == null) {
            return;
        }
        int size = wordList.size();
        if (size > 0) {
            List<Element> elements = null;
            if (process != null) {
                elements = process.process(wordList);
            } else {
                elements = new ArrayList<Element>(wordList.size());
                for (char[] cs : wordList) {
                    elements.add(new GenericElement(cs));
                }
            }
            Collections.sort(elements, new CharArrayComparator<Element>());
            resize(1);
            baseArray[0] = 1;
            nextCheckPos = 0;
            Node root_node = new Node();
            root_node.left = 0;
            root_node.right = size;
            root_node.depth = 0;
            List<Node> siblings = createSiblings();
            fetch(elements, root_node, siblings);
            insert(elements, siblings);
            size = size + (1 << 8 * 2) + 1;
            if (size > usedArray.length) {
                resize(size);
            }

        }
    }

    private int insert(List<Element> elements, List<Node> siblings) {
        int begin = 0;
        int nonZeroCount = 0;
        boolean first = false;

        int pos = (siblings.get(0).code + 1 > nextCheckPos ? siblings.get(0).code + 1 : nextCheckPos) - 1;
        if (pos >= usedArray.length) {
            resize(pos + 1);
        }
        while (true) {
            pos++;

            if (pos >= usedArray.length) {
                resize(pos + 65535);
            }
            if (checkArray[pos] != 0) {
                nonZeroCount++;
                continue;
            } else if (!first) {
                nextCheckPos = pos;
                first = true;
            }
            begin = pos - siblings.get(0).code;

            int t = begin + siblings.get(siblings.size() - 1).code;
            if (t > usedArray.length) {
                resize(t + 65535);
            }

            if (usedArray[begin]) {
                continue;
            }
            boolean flag = false;
            for (int i = 1; i < siblings.size(); i++) {
                if (checkArray[begin + siblings.get(i).code] != 0) {
                    flag = true;
                    break;
                }
            }
            if (!flag) break;
        }

        if (1.0 * nonZeroCount / (pos - nextCheckPos + 1) >= 0.95) {
            nextCheckPos = pos;
        }
        usedArray[begin] = true;
        writeSize = Math.max(writeSize, begin + siblings.get(siblings.size() - 1).code + 1);
        for (Node node : siblings) {
            checkArray[begin + node.code] = begin;
        }

        for (Node node : siblings) {
            List<Node> newSiblings = createSiblings();
            if (fetch(elements, node, newSiblings) == 0) {
                baseArray[begin + node.code] = -node.left - 1;
               

            } else {
                int ins = insert(elements, newSiblings);
                baseArray[begin + node.code] = ins;
            }

        }

        return begin;
    }

    private List<Node> createSiblings() {
        return new ArrayList<Node>();
    }

    private void resize(int size) {
        // checkArray array
        int tmp[] = new int[size];
        if (baseArray != null) {
            System.arraycopy(baseArray, 0, tmp, 0, baseArray.length);
        }
        baseArray = tmp;

        // baseArray array
        int tmp1[] = new int[size];
        if (checkArray != null) {
            System.arraycopy(checkArray, 0, tmp1, 0, checkArray.length);
        }
        checkArray = tmp1;

        // usedArray array
        boolean tmp2[] = new boolean[size];
        if (usedArray != null) {
            System.arraycopy(usedArray, 0, tmp2, 0, usedArray.length);
        }
        usedArray = tmp2;

     

    }

    private int fetch(List<Element> words, Node parent, List<Node> siblings) {
        int prev = 0;
        Node preNode = null;
        for (int i = parent.left; i < parent.right; i++) {
            char word[] = words.get(i).getChars();
            int len = word.length;
            if (len < parent.depth) {
                continue;
            }
            int cur = 0;
            if (len != parent.depth) {
                cur = word[parent.depth] + 1;
            }

            if (prev > cur) {
                throw new RuntimeException("Fatal: sort dictionary first.\n");
            }
            if (cur != prev || siblings.size() == 0) {
                Node tmpNode = new Node();
                tmpNode.depth = parent.depth + 1;
                tmpNode.code = cur; // 重新计算每个字的映射?
                tmpNode.left = i;
                if (len == parent.depth + 1) {
                    tmpNode.frequence = words.get(i).getFrequence();
                }
                if (preNode != null) {
                    preNode.right = i;
                }
                preNode = tmpNode;
                siblings.add(tmpNode);
            }
            prev = cur;
        }

        if (preNode != null) {
            preNode.right = parent.right;
        }
        return siblings.size();
    }

    public void save(String file) throws IOException {
        DataOutputStream out = null;
        int dsize = checkArray.length;
        try {
            out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
            out.writeInt(dsize);
            for (int i = 0; i < dsize; i++) {
                out.writeInt(checkArray[i]);
                out.writeInt(baseArray[i]);
             
            }
            out.close();
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }

    public void load(String fileName) throws IOException {
        File file = new File(fileName);
        DataInputStream is = null;
        try {
            is = new DataInputStream(new BufferedInputStream(new FileInputStream(file), 1024 * 1024));
            load(is);
        } finally {
            if (is != null) is.close();
        }
    }

    public void load(InputStream in) throws IOException {
        DataInputStream is = new DataInputStream(new BufferedInputStream(in, 1024 * 1024));
        int size = is.readInt();
        checkArray = new int[size];
        baseArray = new int[size];
     
        for (int i = 0; i < size; i++) {
            checkArray[i] = is.readInt();
            baseArray[i] = is.readInt();
          
        }
     
    }

    public int search(String key) {
        return search(key.toCharArray(), 0, key.length());
    }

    public int search(char key[], int pos, int len) {
        if (len == 0) {
            len = key.length;
        }
        int b = baseArray[0];
        int p;
        for (int i = pos; i < len; i++) {

            p = b + key[i] + 1;
            if (b == checkArray[p]) {
                b = baseArray[p];
            } else {
                return -1;
            }
        }
        p = b;
        int n = baseArray[p];
        if (b == checkArray[p] && n < 0) {
            return -n - 1;
        }
        return -1;
    }

   

    public List<Word> prefixSearch(char[] key, int pos, int len) {
        int p, n, i, b = baseArray[0];
        List<Word> result = new ArrayList<Word>();
        for (i = pos; i < len; ++i) {
            p = b; // + 0;
            n = baseArray[p];
            if (b == checkArray[p] && n < 0) {
                Word w = new Word();
                w.position = -n - 1;
                w.begin = pos;
                w.length = i - pos;
             
                result.add(w);
            }
            p = b + (key[i]) + 1;
            if (b == checkArray[p]) {
                b = baseArray[p];
            } else {
                return result;
            }
        }
        p = b;
        n = baseArray[p];
        if (b == checkArray[p] && n < 0) {
            Word w = new Word();
            w.position = -n - 1;
            w.begin = pos;
            w.length = i - pos;
          
            result.add(w);
        }

        return result;
    }

    public Word prefixSearchMax(char[] key, int pos, int len) {
        int p, n, i, b = baseArray[0];
        Word w = null;
        for (i = pos; i < pos + len; ++i) {
            p = b; // + 0;
            n = baseArray[p];
            if (b == checkArray[p] && n < 0) {
                if (w == null) {
                    w = new Word();
                }
                w.position = -n - 1;
                w.begin = pos;
                w.length = i - pos;
              
            }
            p = b + (key[i]) + 1;
            if (b == checkArray[p]) {
                b = baseArray[p];
            } else {
                return w;
            }
        }
        p = b;
        n = baseArray[p];
        if (b == checkArray[p] && n < 0) {
            if (w == null) {
                w = new Word();
            }
            w.position = -n - 1;
            w.begin = pos;
            w.length = i - pos;
         
        }
        return w;
    }
 
//字符数组比较子
public class CharArrayComparator<T> implements Comparator<T> {

    public int compare(T o1, T o2) {
        char[] a = ((Element) o1).getChars();
        char[] b = ((Element) o2).getChars();
        int loop = a.length > b.length ? b.length : a.length;
        for (int i = 0; i < loop; i++) {
            int c = a[i] - b[i];
            if (c != 0) {
                return c;
            }
        }
        return a.length - b.length;
    }
}

//在生成数据前, 这个接口实现了特定的数据处理
public interface PreProcess {
    public  List<Element> process(List<char[]> lines);
}

里面还有一些简单的数据结构, 当然这些都不是必然需要的, 我为了自己的业务需求, 实现了一些特定的数据结构。 当然, 这个版本我已经删除了我的业务代码, 可能会编译通过不了。 但是, 所有BUG已经被修正了。

 
分享到:
评论

相关推荐

    史上最快速基于词典的分词算法----为违禁字过滤算法而实现

    NULL 博文链接:https://show-your-sister.iteye.com/blog/277286

    基于双数组Trie_树中文分词研究

    ### 基于双数组Trie树中文分词研究 #### 概述 本文献针对中文信息处理中的分词问题,研究了一种基于双数组Trie树(Double-Array Trie, DAT)的优化方法。传统的分词算法面临着空间利用率低、插入速度慢等问题,...

    java实现中文分词simhash算法

    总的来说,Java实现的中文分词SimHash算法结合了Sanford分词库的分词功能和SimHash的相似度检测,为中文文本的相似度分析提供了一种高效且准确的方法。在实际应用中,这种技术广泛应用于搜索引擎的去重、推荐系统、...

    java 实现的中文分词算法(代码)

    Java实现的中文分词算法是自然语言处理领域中的重要技术,尤其在文本挖掘、搜索引擎、信息检索等场景中发挥着关键作用。FMM(Fast Mapping Model)和BMM(Bigram Mapping Model)是两种常见的中文分词算法,它们都是...

    中文分词-基于互信息+邻接信息熵实现的中文分词算法-附项目源码-优质项目实战.zip

    中文分词_基于互信息+邻接信息熵实现的中文分词算法_附项目源码_优质项目实战

    中文分词工具word-1.0,Java实现的中文分词组件多种基于词典的分词算法

    word分词是一个Java实现的中文分词组件,提供了多种基于词典的分词算法,并利用ngram模型来消除歧义。 能准确识别英文、数字,以及日期、时间等数量词,能识别人名、地名、组织机构名等未登录词。 同时提供了Lucene...

    CQ V2.0分词bates(基于双数组tire树)

    综上所述,CQ V2.0分词系统基于双数组Trie树和Bates策略,实现了高效、准确的分词效果。其开源特性使得这个系统更加透明且具有可扩展性,为自然语言处理领域的研究和应用提供了有力的支持。通过深入学习和实践,我们...

    分语算法,分词算法介绍

    分词算法 汉语分词介绍分词算法 汉语分词介绍分词算法 汉语分词介绍分词算法 汉语分词介绍分词算法 汉语分词介绍分词算法 汉语分词介绍分词算法 汉语分词介绍分词算法 汉语分词介绍分词算法 汉语分词介绍分词算法 ...

    JAVA实现的中文分词程序

    Java实现的中文分词程序是一种基于Java编程语言的文本处理工具,主要应用于处理中文文本,将其拆分成有意义的词汇单元,这一过程被称为分词。在自然语言处理(NLP)领域,分词是预处理阶段的关键步骤,为后续的文本...

    双数组Trie树算法优化及其应用研究.pdf

    ### 双数组Trie树算法优化及其应用研究 #### 摘要与关键词解析 本文主要探讨了一种针对双数组Trie树(Double-Array Trie)算法的优化策略,并通过实验验证了该策略的有效性。双数组Trie树是一种高效的数据结构,常...

    最新逆向最大匹配分词算法 盘古分词 分词算法 中文分词 源码

    在提供的压缩包文件中,包含了各种与分词相关的源码,例如"zt_逆向最大匹配分词算法"可能是实现逆向最大匹配算法的具体代码,"秒盘古分词"可能是指快速版本的盘古分词程序,"中文分词"和"英文分词"源码分别针对中文...

    不依赖第三方的java分词算法

    在这个标题为“不依赖第三方的java分词算法”的项目中,开发者提供了一个独立的Java实现,旨在避免对其他外部库的依赖,使得在进行分词操作时更加灵活和高效。 分词算法通常有多种,其中提到的“正向最大匹配”...

    双数组Trie优化算法及其应用研究

    1. **查询速度:** 通过比较不同索引机制下的词典查询速度,发现采用优化后的双数组Trie树算法构建的词典在查询速度上明显优于其他机制。 2. **空间占用:** 测试结果显示,即使在数据量较大的情况下,优化后的双数组...

    TFIDF算法 java实现

    ### TF-IDF算法Java实现详解 #### 一、算法简介 TF-IDF(Term Frequency-Inverse Document Frequency)是一种常用于信息检索与文本挖掘中的权重计算公式。它通过统计单词在文档中出现的频率以及在整个文集中的频率...

    中文词库-分词算法必备

    ### 中文词库与分词算法:构建高效自然语言处理基石 #### 一、中文词库的重要性 在自然语言处理(NLP)领域,中文词库扮演着至关重要的角色。与英文等西方语言不同,中文没有明确的词界标记,这使得中文文本的切分...

    中文自动分词算法

    中文自动分词算法 中文自动分词算法是自然语言处理中的一项基本技术,旨在将中文文本切分成单个词语,以便更好地进行信息检索、自动标引、自动文摘、机器翻译、语言学研究、搜索引擎研究和自然语言理解等领域的应用...

    src_seg(java).rar_java 分词_中文文本分词_分词 java_分词算法

    1. jieba-java:移植自Python的jieba分词库,支持精确模式、全模式、搜索引擎模式等多种分词方式。 2. HanLP:由福州大学与自然语言处理实验室开发,提供了分词、词性标注、命名实体识别等功能。 3. IK Analyzer:...

    ICTCLAS分词系统-java实现

    ICTCLAS分词的实现案例,完整的使用java代码实现,可以直接导入工程运行。

    使用IK Analyzer实现中文分词之Java实现

    IK Analyzer 是一个开源的,基于 java 语言开发的轻量级的中文分词工具包。从 2006年 12 月推出 1.0 版... 在 2012 版本中,IK 实现了简单的分词歧义排除算法,标志着 IK 分词器从单纯的词典分词向模拟语义分词衍化。

Global site tag (gtag.js) - Google Analytics