【2023.6.7练习】jmu-Java-05集合-4-倒排索引

文章描述了一个Java程序,用于建立文本的倒排索引并实现多关键字搜索功能。程序利用TreeMap存储单词及其所在行号,通过split方法处理输入的句子,并使用TreeSet处理相同单词可能出现多次的情况。搜索时,程序检查多个关键字在句子中的共同出现。
摘要由CSDN通过智能技术生成

题目描述:

对若干行文字建立倒排索引(根据单词找到所在行号)。
然后根据关键字,在倒排索引查找进行查找,找到包含所有该关键字所在的行数并输出。

输入说明

  1. 若干行英文,以!!!!!为结束。
  2. 输入一行查询关键字,以1个空格为分隔

输出说明

  1. 输出所创建倒排索引。索引的key按照字母升序,索引的value按照行号升序
  2. 输出查询结果。如果找到,输出行集与行集内每一行的内容,如果没找到输出found 0 results

输入样例

where are you from are you ok
this is a test 
that is an apple
there are lots of apples you eat it
who are you
!!!!!
you are
eat
you test
abc

输出样例

a=[2]
an=[3]
apple=[3]
apples=[4]
are=[1, 4, 5]
eat=[4]
from=[1]
is=[2, 3]
it=[4]
lots=[4]
of=[4]
ok=[1]
test=[2]
that=[3]
there=[4]
this=[2]
where=[1]
who=[5]
you=[1, 4, 5]
[1, 4, 5]
line 1:where are you from are you ok
line 4:there are lots of apples you eat it
line 5:who are you
[4]
line 4:there are lots of apples you eat it
found 0 results
found 0 results

题目分析:

由于题目要求从句段中提取出单词和其所在行号,且单词拥有不重复的特性。因此考虑采用拥有键值对的Map集合

输入句子时为了区分空格与换行,考虑采用nextLine方法

为了将每句话的单词提取出来,使用split方法将String句子拆分为单词。

因为该程序要实现的功能较为复杂,故准备定义多个


设计重点:

1.如何存储复杂的单词信息:一开始只是想用Map集合分别存储单词的内容和位置,然而由于同一个单词可能会出现在多个不同位置,因此值的类型又是一个TreeSet集合,因此这是一个嵌套集合。

    TreeMap<String, TreeSet<Integer>> map = new TreeMap<>();//记录单词内容和出现句子

2.为什么split把句子拆成了字母:由于regex分隔符是用来识别哪里开始拆的,因此需要在分隔符

“ ”中加入空格,句子会在每个空格处拆开变成单词。

3.如何提取出两个单词共同存在的句子:要实现这个功能非常麻烦。通过建立两个集合分别存储每个单词所在句子和共同所在句子的方式,实现了这个方法。


最终代码:

import java.util.ArrayList;
import java.util.Scanner;
import java.util.TreeMap;
import java.util.TreeSet;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        boolean s1 = false;
        int n = 1;//输入的句子数
        addtoMap add = new addtoMap();//该类用于将句子转化为单词信息并存储

        ArrayList<String> arr = new ArrayList<>();//用于储存每句话的信息
        //第一步:输入句子
        while (s1 == false) {
            String sentence = sc.nextLine(); //输入句子直至出现"!!!!!"为止
            if (sentence.equals("!!!!!")) {
                s1 = true;
                break;
            }
            arr.add(sentence);
            String words[] = sentence.split(" ");//将句子转入数组
            add.Add(words, n);
            n++;
        }

        add.map.forEach((String k, TreeSet val) -> System.out.println(k + "=" + val));
        //第二步:查找单词
        boolean s2 = false;

        while(s2==false) {
            String sentence = sc.nextLine(); //输入句子直至出现"abc"为止
            ArrayList<Integer> A = add.Check(sentence);
            if (A.isEmpty()) {
                System.out.println("found 0 results");
            } else {
                System.out.println(A);
                for (int i = 0; i < A.size(); i++) {
                    int m = A.get(i);
                    System.out.println("line "+m+":"+arr.get(m - 1));
                }
            }

        }


    }
}

class addtoMap {
    TreeMap<String, TreeSet<Integer>> map = new TreeMap<>();//记录单词内容和出现句子

    public void Add(String[] w, int i) {
        boolean S = false;
        for (int j = 0; j < w.length; j++) {
            if (map.containsKey(w[j])) {

                TreeSet<Integer> num = map.get(w[j]);//通过单词找存储句子的集合(键找值)
                num.add(i);
                map.put(w[j], num);

            } else {
                TreeSet<Integer> num = new TreeSet<>();//记录出现的句子号数
                num.add(i);
                map.put(w[j], num);

            }
        }
    }

    public ArrayList Check(String h) {
        TreeSet<Integer> keysentence = new TreeSet<>(); // 先将每个关键词对应的句子存储
        ArrayList<Integer> realsentence = new ArrayList<>(); //再将有重叠句子的单独存储
        String keyword[] = h.split(" ");//将句子转入数组
        for (int i = 0; i < keyword.length; i++) {
            if (map.containsKey(keyword[i])) {
                TreeSet<Integer> num = map.get(keyword[i]);//键找值
                for (int n : num) {  //遍历储存句子序号的集合
                    if (keysentence.add(n) == false || keyword.length == 1) {
                        realsentence.add(n);
                    }
                }

            }
        }
        return realsentence;
    }


}

由于未知原因,运行范例时结果完全正确,但有一个测试点答案错误。


总结:该题目较有难度。考察对集合各种方法的应用和代码多重复杂功能的实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值