字典树查找字符串(java版)

  一、概念:

Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。

    Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。
二、3个基本性质:
    1.根节点不包含字符,除根节点外每一个节点都只包含一个字符。
    2.
从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
    3.
每个节点的所有子节点包含的字符都不相同。

三、Trie树的构建
     本质上,Trie是一颗存储多个字符串的树。相邻节点间的边代表一个字符,这样树的每条分支代表一则子串,而树的叶节点则代表完整的字符串。和普通树不同的地方是,相同的字符串前缀共享同一条分支。举一个例子。给出一组单词,inn, int, at, age, adv, ant, 我们可以得到下面的Trie:


    

    搭建Trie的基本算法很简单,无非是逐一把每则单词的每个字母插入Trie。插入前先看前缀是否存在。如果存在,就共享,否则创建对应的节点和边。比如要插入单词add,就有下面几步:
    1.
考察前缀"a",发现边a已经存在。于是顺着边a走到节点a。
    2.
考察剩下的字符串"dd"的前缀"d",发现从节点a出发,已经有边d存在。于是顺着边d走到节点ad
    3.
考察最后一个字符"d",这下从节点ad出发没有边d了,于是创建节点ad的子节点add,并把边ad->add标记为d。
四、java源代码如下:(普通数组LIST查找字符串和字典树查找字符串比较,其中文件是大约10万个单词)
import java.io.*;
import java.util.*;
//测试字典树的建立以及测试
public class testtrie {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		testbasic();
		tree root=null;
		root=createtree(root);
		long startTime = System.currentTimeMillis();//获取当前时间
		teststr(root);
		long endTime = System.currentTimeMillis();
		System.out.println("字典树查询字符串程序运行时间:"+(endTime-startTime)+"ms");
	}
	//普通数组测试查找字符串
	public static void testbasic(){
		try {
			List<String> strlist=new ArrayList<String>();
            File file=new File("E:\\strs.txt");
            if(file.isFile() && file.exists()){ //判断文件是否存在
                InputStreamReader read = new InputStreamReader(
                new FileInputStream(file));//考虑到编码格式
                BufferedReader bufferedReader = new BufferedReader(read);
                String lineTxt = null;
                while((lineTxt = bufferedReader.readLine()) != null){
                	strlist.add(lineTxt);
                }
                read.close();
                long startTime = System.currentTimeMillis();//获取当前时间
                try {
                     file=new File("E:\\strs.txt");
                    if(file.isFile() && file.exists()){ //判断文件是否存在
                         read = new InputStreamReader(
                        new FileInputStream(file));//考虑到编码格式
                         bufferedReader = new BufferedReader(read);
                         lineTxt = null;
                        while((lineTxt = bufferedReader.readLine()) != null){
                      	  if(!strlist.contains(lineTxt)){
                      		 System.out.println("NO");
                      	  }
                        }
                        read.close();
            }else{
                System.out.println("找不到指定的文件");
            }
            } catch (Exception e) {
                System.out.println("读取文件内容出错");
                e.printStackTrace();
            }	
                long endTime = System.currentTimeMillis();
        		System.out.println("普通查询字符串程序运行时间:"+(endTime-startTime)+"ms");
    }else{
        System.out.println("找不到指定的文件");
    }
    } catch (Exception e) {
        System.out.println("读取文件内容出错");
        e.printStackTrace();
    }
	}
	//字典树方法测试查找字符串
	public static void teststr(tree root){
		  try {
              File file=new File("E:\\strs.txt");
              if(file.isFile() && file.exists()){ //判断文件是否存在
                  InputStreamReader read = new InputStreamReader(
                  new FileInputStream(file));//考虑到编码格式
                  BufferedReader bufferedReader = new BufferedReader(read);
                  String lineTxt = null;
                  while((lineTxt = bufferedReader.readLine()) != null){
                	  if(!Search_intree(root,lineTxt)){
                		  System.out.println("NO");
                	  }
                  }
                  read.close();
      }else{
          System.out.println("找不到指定的文件");
      }
      } catch (Exception e) {
          System.out.println("读取文件内容出错");
          e.printStackTrace();
      }	
	}
	public static tree createtree(tree root){
	  root=new tree('#');
		  try {
              File file=new File("E:\\strs.txt");
              if(file.isFile() && file.exists()){ //判断文件是否存在
                  InputStreamReader read = new InputStreamReader(
                  new FileInputStream(file));//考虑到编码格式
                  BufferedReader bufferedReader = new BufferedReader(read);
                  String lineTxt = null;
                  while((lineTxt = bufferedReader.readLine()) != null){
                	  insertintotree(root,lineTxt);//建立该字符串的字典树
                  }
                  read.close();
      }else{
          System.out.println("找不到指定的文件");
      }
      } catch (Exception e) {
          System.out.println("读取文件内容出错");
          e.printStackTrace();
      }
	    
		  System.out.println("创建字典树完成!");
		return root;
	}
	public static void insertintotree(tree root,String str){
		if(root==null || str.length()==0){
			return ;
		}
		for(int i=0;i<str.length();i++){
			//只是考虑小写字母
			if(str.charAt(i)>='a' && str.charAt(i)<='z'){
			if(root.childs[str.charAt(i)-'a']==null){
				   tree node=new tree(str.charAt(i));
				   root.childs[str.charAt(i)-'a']=node;
				   root.childcount++;
				   root=node;
				}else{
					root=root.childs[str.charAt(i)-'a'];
				}
			}
		}
		root.flag=true;
	}
	public static void PreOrder(tree root){
		if(root!=null){
			System.out.print(root.data);
			if(root.childcount!=0){
				for(int i=0;i<26;i++){
		    		PreOrder(root.childs[i]);
		    	}
			}else{
			  System.out.println();
			}
		}
	}
	public static boolean Search_intree(tree root,String str){
		if(root==null || str.length()==0){
			return false;
		}else{
			int i=0;
			for(i=0;i<str.length();i++){
				//只是考虑小写字母
				if(root.childs[str.charAt(i)-'a']!=null){
					root=root.childs[str.charAt(i)-'a'];
					}else{
						break;
					}
				}
			if(i!=str.length()){
				return false;
			}else{
				if(root.flag==true){
					return true;
				}else{
					return true;
				}
			}
			}
	}
}
 class tree{
	char data;
	tree []childs;
	int childcount=0;
	boolean flag;//其中有的前缀也许是一个单独的单词,所以标记是否到该节点组成一个已有的字符串
	tree(char d){
		data=d;
		childs=new tree[26];
		childcount=0;
		flag=false;
	}
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值