算法实验报告4

实验四 文本索引

  1. 问题描述与需求分析

编写一个构建大块文本索引的程序,然后进行快速搜索,来查找某个字符串在该文本中的出现位置。

你的程序应该使用两个文件名作为命令行参数:文本文件(我们称为语料库)和包含查询的文件。 假设这两个文件只包含小写字母、空格和换行符,查询文件中的查询由换行符分隔。 这不是一个限制,因为你可以使用一个过滤器将任何文件转换为此格式。

你的程序应该读取语料库,将其存储为(可能巨大)字符串,并可能为其创建索引,如下所述。 然后它应该逐个读取查询(假设在命令行中的第二个命名文件中,每行有一个查

询),并打印出语料库中每个查询在文本文件中首次出现的位置。对于由如下内容构成的corpus 文件

it was the best of times it was the worst of times it was the age of wisdom it was the age of foolishness

it was the epoch of belief it was the epoch of incredulity it was the season of light it was the season of

darkness it was the spring of hope it was the winter of despair

以及如下内容构成的 query 文件

wisdom

season

age of foolishness

age of fools

查询结果如下:

18 wisdom

40 season

22 age of foolishness

-- age of fools

解决这个问题有很多种不同的方法,这些方法在实现方便性,空间要求和时间要求方面都有不同的特点。 此任务的一部分是吸收此信息,以帮助你确定使用哪种方法以及如何将其解决问题。

 

 

  1. 解决方案

使用Algs4的jar包读入文件,然后用BM算法根据坏字符规则和好后缀规则进行查找,实际移动的字符数可以计算出来

  1. 代码核心设计
  1. BoyerMoore类设计

    在查找子字符串的算法当中,BM(Boyer-Moore)算法是一种非常高效的字符串搜索算法,它由Bob Boyer和JStrother Moore设计于1977年。主要原理是两条关于移动字符数规则:坏字符规则和好后缀规则,实际的移动字符数为通过这两条规则计算出的最大移动个数。

    主要功能设计:

    class BoyerMoore {

        public BoyerMoore(String pat); // 构造函数,初始化变量,对字符串的每个字符按其建立索引

        public int search(String txt); // 利用坏字符规则和好后缀规则求得移动字符串数,进行字符串查找

        public int searchPos(String txt, int n); // 计算某个字符串之前的单词数目

    }

  2. readTxt()函数

    主要功能:将查询文件中的换行符用空格替换

    public static String readTxt(){

        建立File对象;

        核心代码是一个try-catch文件块,用于读取文件的内容,注意把换行符换掉

    }

    try {

                if (file.length() != 0) {

                    is = new FileInputStream(file);

                    InputStreamReader streamReader = new InputStreamReader(is);

                    BufferedReader reader = new BufferedReader(streamReader);

                    String line;

                    stringBuilder = new StringBuilder();

                    while ((line = reader.readLine()) != null) {

                        stringBuilder.append(line);

                        stringBuilder.append(' ');

                    }

                    reader.close();

                    is.close();

                } else {

                    StdOut.println("文件为空");

                }

     

    四.实验全部代码

    package exp4;

     

     

     

    import java.io.File;

    import java.io.FileInputStream;

    import edu.princeton.cs.algs4.In;

    import edu.princeton.cs.algs4.StdOut;

    import java.io.BufferedReader;

    import java.io.File;

    import java.io.FileInputStream;

    import java.io.InputStreamReader;

     

    // BM字符串搜索算法

    class BoyerMoore {

        private final int R;

        private int[] right;

        private String pat;

     

        public BoyerMoore(String pat) {

            this.R = 256;

            this.pat = pat;

            right = new int[R];

            for (int c = 0; c < R; c++)

                right[c] = -1;

            for (int j = 0; j < pat.length(); j++)

                right[pat.charAt(j)] = j;

        }

     

        public int search(String txt) {

            int m = pat.length();

            int n = txt.length();

            int skip;

            for (int i = 0; i <= n - m; i += skip) {

                skip = 0;

                for (int j = m - 1; j >= 0; j--) {

                    if (pat.charAt(j) != txt.charAt(i + j)) {

                        skip = Math.max(1, j - right[txt.charAt(i + j)]);

                        break;

                    }

                }

                if (skip == 0) return i;// 找到了,则返回第一个字符的位置

            }

            return -1; // 没找到 返回-1

        }

     

        public int searchPos(String txt, int n) {

            int count = 0;

            char[] tx = txt.toCharArray();

            for (int i = 0; i < n; i++) {

                if (tx[i] == ' ') count++;

            }

            return count;

        }

    }

     

    public class TextIndex {

        public static void main(String[] args) {

            String txt1 = readTxt();

    // StdOut.println(txt1);

    // File file = new File("C:\\p1.txt");

            File file = new File("C:\\p2.txt");

            FileInputStream is = null;

            try {

                if (file.length() != 0) {

                    is = new FileInputStream(file);

                    InputStreamReader streamReader = new InputStreamReader(is);

                    BufferedReader reader = new BufferedReader(streamReader);

                    String line;

                    while ((line = reader.readLine()) != null) {

                        BoyerMoore boyermoore = new BoyerMoore(line);

                        int offset = boyermoore.search(txt1);

                        if (offset == -1)

                            StdOut.println("-- "+line);// 没找到

                        else {

                            int pos = boyermoore.searchPos(txt1,offset);

                            StdOut.print(pos+1);

                            StdOut.println(' '+line);

                        }

                    }

                    reader.close();

                    is.close();

                } else {

                    StdOut.println("打开文件为空");

                }

            } catch (Exception e) {

                e.printStackTrace();

            }

        }

     

        public static String readTxt() {

    // File file = new File("C:\\test1.txt");

            File file = new File("C:\\test2.txt");

            FileInputStream is = null;

            StringBuilder stringBuilder = null;

            try {

                if (file.length() != 0) {

                    is = new FileInputStream(file);

                    InputStreamReader streamReader = new InputStreamReader(is);

                    BufferedReader reader = new BufferedReader(streamReader);

                    String line;

                    stringBuilder = new StringBuilder();

                    while ((line = reader.readLine()) != null) {

                        stringBuilder.append(line);

                        stringBuilder.append(' ');

                    }

                    reader.close();

                    is.close();

                } else {

                    StdOut.println("文件为空");

                }

     

            } catch (Exception e) {

                e.printStackTrace();

            }

            return String.valueOf(stringBuilder);

        }

    }

     

    1. 结果示例
    2. 对于Corpus实例文件,实验结果如下

     

    1. Corpus文件的实验结果如下
    2. 实验总结

    在本次实验中,我自己实现了BM算法来进行字符串查找,对后缀自动机有了更加深刻的理解,我一开始想用kMP和暴力匹配做的,最后觉得确实算法有点慢

posted @ 2021-01-22 23:25  coolwx  阅读(499)  评论(0编辑  收藏  举报