【发布时间】:2018-09-06 05:49:21
【问题描述】:
所以基本上我必须验证在数组上的文件中计算单词的次数。
Edit#2(之后我会通过 cmd 运行这个程序)
这个程序有许多命令行参数:
1) 要打开的文件
2+) 要搜索和统计的单词
如果你不给它任何要搜索的词,它默认为这些词:“医生”, “科学怪人”、“那个”、“怪物”、“伊戈尔”、“学生”、“大学”、“闪电”、 “电”、“血”、“魂”。 你可能想用更少或不同的词来运行它,例如:
$ java ReadSearchAndSort frankenstein.txt frankenstein doctor igor monster
编辑/更新*: 如果我们考虑简单的程序:
public class CopyCat{
public static void main(String[] arguments){
for (int ii = 0; ii < arguments.length; ii++){
System.out.println("Argument "+ ii + " = " +
arguments[ii]);
}
}
}
如果我们这样运行它:
$ java CopyCat a b c
我们将得到以下输出
Argument 0 = a
Argument 1 = b
Argument 2 = c
以此为基础:
获取第一个参数并将其存储在一个名为 filename 的字符串中
● 获取其余参数并将它们放在一个名为的字符串数组中
queryWords(这应该是正确的大小以容纳所有要计数的单词,
并且不应该有最大大小——忽略你的内存需求
系统)
在文件中保留内容时循环扫描扫描仪(即hasNext() 为真)
并获取文件中的下一个单词(即调用 next())
● 将单词放入数组中——注意,你需要不断调整数组的大小——
○ 所以首先在for循环之外实例化一个空数组
String[] words = new String[0]();
○ 然后,当您阅读一个单词时,使用Arrays.copyof 调整数组的大小,即
words = Arrays.copyOf(words, words.length+1)
○ 然后将单词放在数组的最后一个位置 ■ … 但首先,我们要将其设为小写
word = word.toLowerCase();
■ 并删除所有非字母
word = word.replaceAll("[^a-zA-Z ]", "");
对于我们单词列表中的每个单词,我们需要遍历我们读过的单词数组
并计算每个实例。为此,我们将创建一个辅助函数:
实现函数countWordsInUnsorted
创建一个计数器变量来记录我们看到一个单词的次数。创建一个
循环遍历数组中的每个单词。每次一个词与查询词匹配时,递增计数器。我们需要使用equals 方法,因为我们关心的是两个字符串中是否有相同的字符,而不是它们是否完全相同
对象。
完成上述两项任务后,您就可以运行代码了。验证
"frankenstein" 出现 26 次
总的来说,我无法理解方向以及我应该如何订购我的代码,以便它可以理解。如果您能提供帮助,我将不胜感激。我知道它很长,但这甚至不是整个作业,所以它被缩短了。
EDIT 9/7/18 更新说明 在 Java 中计时 您的代码运行了多长时间?
在本次作业中,我们将看到一些搜索算法比其他算法运行得更快。为了查看速度快多少,我们将记录代码运行所需的时间。
这是一个计时码的例子:
// Look at the clock when we start
long t0 = (new Date()).getTime();
for (var i = 0; i < 100000; i++) {
// Do something that takes time
}
// 完成后看表
long t1 = (new Date()).getTime();
long elapsed = t1 - t0;
System.out.println("My code took " + elapsed + "milliseconds to
run.")
这已经在 main 中为您设置好了,它将输出您的代码运行所用的时间。
你的工作是实现和调用你的函数,并确保它们正常工作
正确。如果您查看起始代码,您会发现我们正在运行您的两个不同的
search 和 count 方法 100 次,以便得到一个很好的平均值。
需要。我们只进行一次排序,因为对 75289 个单词的数组进行排序已经需要
一会儿。
4. 使用合并排序对单词数组进行排序
(35 分)
● 实现mergeSort(不要使用Java 内置的Array.sort 进行这个赋值)
● 在 main 中调用你的新方法
● 检查你是否正确: 单词(在输出中的 SORTED 之后)将在
按字母顺序。
执行mergeSort
实现一个对字符串数组进行排序的mergeSort 方法。为此签名
方法应该是:
public static void mergeSort(String[] arrayToSort, String[]
tempArray, int first, int last)
第一个参数是要排序的String[],第二个参数是一个空的临时
应该与要排序的数组大小相同的数组,第三个参数是开始
要排序的数组部分的索引,第四个参数是结尾
要排序的数组部分的索引。
请注意,我们将在原地实现排序 arrayToSort 的 mergeSort 版本。 这意味着您将未排序的数组传递给 mergeSort 并在调用之后
现在对相同的数组进行排序。 请注意,mergeSort 涉及比较值以查看哪个更大。有数字 您可以使用 来比较它们。
如果你有两个字符串 s1 和 s2,那么:
● s1.compareTo(s2) == 0 如果 s1 和 s2 包含相同的字符串。
● s1.compareTo(s2) < 0 如果 s1 在 s2 之前按字母顺序排列。
● s1.compareTo(s2) > 0 如果 s1 将按字母顺序排列在 s2 之后。
在主目录中调用mergeSort
要在main中调用mergeSort,首先需要创建一个与allWords长度相同的临时字符串数组。
我们要对整个数组进行排序,所以第三个参数应该是allWords 中第一个单词的索引,第四个参数应该是
allWords 中最后一个单词的索引。调用 mergeSort 的四个参数是:
● 我们要排序的数组是allWords。
● 我们创建的新临时数组的长度与allWords 相同。
● allWords 中第一个单词的索引(提示:数组的第一个元素的索引总是什么?)。
● allWords中最后一个单词的索引(提示:如果你知道数组的长度,你可以很容易地计算出最后一个元素的索引)。
检查你是对的 这对单词数组进行了排序吗?该程序每 500 个字打印一次。他们看起来 排序? 5. 计算单词(使用二分搜索)并计时 (35 分)
● 实施
public static int binarySearch(String[] sortedWords,
String query, int startIndex, int endIndex)
● 实施
public static int getSmallestIndex(String[] words,
String query, int startIndex, int endIndex)
● 实施
public static int getLargestIndex(String[] words, String
query, int startIndex, int endIndex)
● 在 main 中调用 getSmallestIndex 和 getLargestIndex 以获得最小的和
您要查找的单词出现在排序数组中的最大索引。
使用这两个值来计算该词出现的次数。 ● 检查您是否正确:您将获得与第一个搜索部分相同的值,但要快得多。
实现binarySearch binarySearch 的参数是: ● 要搜索的单词排序数组。 ● 要搜索的词。 ● 数组中开始搜索的索引。 ● 数组中停止搜索的索引。 二进制搜索返回找到单词的数组索引。如果单词在数组中只出现一次,那么这个索引就是它出现的地方。
但如果单词在排序后的数组中出现多次(因此该单词的所有实例在数组中将彼此相邻),那么此索引将指向组中间的单词之一。
二分查找算法不保证这将是组中的第一个元素或组中的最后一个元素。 所以我们需要实现一些其他的方法来做到这一点。
实现getSmallestIndex
方法getSmallestIndex 将是一个递归方法,它使用
binarySearch 方法来查找在数组中找到单词的最小索引。
这种方法的大纲是:
● 使用binarySearch 查找单词的索引。如果索引binarySearch
返回是 -1,然后找不到这个词,getSmallestIndex 应该只是
返回-1。这是基本情况。
● 如果binarySearch 确实找到了这个词,则递归调用getSmallestIndex on
找到单词之前的数组部分。这是从索引 0 开始
到(但不包括)找到该单词的索引。如果返回 -1 则
我们知道我们已经有了最小的索引,否则递归调用
getSmallestIndex 找到了最小的索引,我们应该返回它。这是
递归情况。
实施getLargestIndex
方法getLargestIndex 将是一个使用binarySearch 的递归方法
方法来查找在数组中找到单词的最大索引。大纲为
此方法与上述getSmallestIndex 的大纲非常相似,不同之处在于
递归调用应该搜索从 where binarySearch 之后开始的数组部分
找到了这个词。
使用getSmallestIndex 和getLargestIndex in main计算字数
由于您正在使用的数组已按这一点排序,所以都一样
单词彼此相邻出现(例如,单词“frankenstein”的所有 26 次出现
在数组中彼此相邻)。所以如果你找到了最小和最大的索引
一个词,那么你可以只减去两个索引来计算单词!但这并不完全
单词只出现一次(所以第一个和最后一个索引是相同的)和情况
这个词根本没有出现。
检查你是否正确
检查你得到的答案是否与迭代的幼稚方法相同
整个数组。另外,看看这种方法对天真的方法有多快
方法!
示例参数和输出
$ java ReadSearchAndSort frankenstein.txt student college frankenstein blood the
Arguments: use ''student,college,frankenstein,blood,the'' words, time 100 iterations, search for words:
student,college,frankenstein,blood,the
NAIVE SEARCH:
student:2
college:3
frankenstein:26
blood:19
the:4194
96 ms for 500 searches, 0.192000 ms per search
SORTING:
38 ms to sort 75097 words
SORTED (every 498 word): a a aboard affection all although ancient and and and and and angel approached
as asked attended be been believe boat but but by cause clerval comprehensive continued country dante
decay desire died do duvillard end escape exception eyes favourite few flourishing for frankenstein from
girl grief had happiness have he heart her his histories however i i i i i ice impossible in in
inhabitants investigating it its know leaves limbs love man me me might mixture most my my my my nature
no not oatmeal of of of of of old on or over passed philosophy possession profoundly rain regular
resolve room saved seem shape should smiles some spirit straw sun tavernier that that the the the the
the the the the the then thick those time to to to to town uncle upon vessels was was was were when
which while will with with would you you
BINARY SEARCH:
student:2
college:3
frankenstein:26
blood:19
the:4194
6 ms for 500 searches, 0.012000 ms per search
当然,运行搜索和排序的实际时间会因您的计算机而异, 取决于您的计算机的速度以及在其上运行的其他进程的数量。
编辑 9/7/18
import java.io.*;
import java.util.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Scanner;
public class ReadSearchAndSort {
public static void main(String[] args) throws FileNotFoundException {
String filename = args[0];
int n = args.length - 1;
String[] queryWords = null;
String[] allWords = readWords("frankenstein.txt");
String[] tempAllWords = new String[allWords.length];
if (n > 0) { //if user provides the querywords
queryWords = new String[n];
for (int i = 1; i < args.length; i++) {
queryWords[i - 1] = args[i];
}
} else { //if user doesn't provide querywords
queryWords = new String[]{"doctor", "frankenstein", "the", "monster", "igor", "student", "college", "lightning", "electricity", "blood", "soul"};
}
ReadSearchAndSort.readWords("C:/Users/Jordles/IdeaProjects/TimeConversionToSecond.java/out/production/GettingStarted/cs141/frankenstein.txt");
int timingCount = 100;
System.out.println("\nArguments: use '" + String.join(",", queryWords) + "' words, time " + timingCount + " iterations, search for words: " + String.join(",", queryWords) + "\n");
System.out.println("NAIVE SEARCH:");
// Record the current time
long t0 = new Date().getTime();
// Time how long it takes to run timingCount loops
// for countWordsInUnsorted
for (int j = 0; j < timingCount; j++) {
for (int i = 0; i < queryWords.length; i++) {
int count = countWordsInUnsorted(allWords, queryWords[i]);
if (j == 0) {
System.out.println(queryWords[i] + ":" + count);
}
}
}
long t1 = (new Date()).getTime();
long timeToSearchNaive = t1 - t0;
int searchCount = timingCount * queryWords.length;
// Output how long the searches took, for how many searches
// (remember: searches = timingcount * the number of words searched)
int searches = timingCount * 500;
System.out.printf("%d ms for %d searches, %f ms per search\n", timeToSearchNaive, searchCount, timeToSearchNaive * 1.0f / searchCount);
// Sort the list of words
System.out.println("\nSORTING: ");
mergeSort(allWords, tempAllWords, 0, allWords.length);
long t2 = (new Date()).getTime();
// Output how long the sorting took
long timeToSort = t2 - t1;
System.out.printf("%d ms to sort %d words\n", timeToSort, allWords.length);
// Output every 1000th word of your sorted wordlist
int step = (int) (allWords.length * .00663 + 1);
System.out.print("\nSORTED (every " + step + " word): ");
for (int i = 0; i < allWords.length; i++) {
if (i % step == 0)
System.out.print(allWords[i] + " ");
}
System.out.println("\n");
System.out.println("BINARY SEARCH:");
// Run timingCount loops for countWordsInSorted
// for the first loop, output the count for each word
for (int j = 0; j < timingCount; j++) {
for (int i = 0; i < queryWords.length; i++) {
int count = countWordsInUnsorted(allWords, queryWords[i]);
if (j == 0) {
System.out.println(queryWords[i] + ":" + count);
}
}
}
long t3 = (new Date()).getTime();
long timeToSearchBinary = t3 - t2;
System.out.printf("%d ms for %d searches, %f ms per search\n", timeToSearchBinary, searchCount, timeToSearchBinary*1.0f/searchCount);
}
public static String[] readWords(String fileName) throws FileNotFoundException{
String[] words = new String[0];
int i = 0;
File file = new File(fileName);
Scanner input = new Scanner(file, "UTF-8");
input.useDelimiter("\\s+|\\-");
while(input.hasNext()){
String word = input.next();
word = word.toLowerCase();
word = word.replaceAll("[^a-zA-Z ]", "");
words = Arrays.copyOf(words, words.length + 1);
words[i++] = word;
}
return null;
}
public static int countWordsInUnsorted(String[] WordsToCount, String countedWord){
if ((countedWord == null) || (WordsToCount == null)){
return 0;
}
int counter = 0;
for( String word : WordsToCount){
if (word.equals(countedWord)){
counter++;
}
}
return counter;
}
public static void mergeSort(String[] arrayToSort, String[] tempArray, int first, int last){
if (first == last){
return;
}
int mid = (first + last)/2;
mergeSort(arrayToSort, tempArray, first, mid);
mergeSort(arrayToSort, tempArray, mid + 1, last);
merge(arrayToSort, tempArray, first, mid, mid + 1, last);
}
public static void merge(String[] arrayToSort, String[] tempArray, int first, int mid, int mid1, int last){
int j = first;
int k = mid1;
int l = first;
do{
if (tempArray[j].compareTo(tempArray[k]) < 0){
arrayToSort[l] = tempArray[j];
j++;
}
else{
arrayToSort[l] = tempArray[k];
k++;
}
}
while (j <= mid && k <= last){
}
}
public static int binarySearch(String[] sortedWords, String query, int startIndex, int endIndex){
if (startIndex > endIndex){
}
int mid = (startIndex + endIndex)/2;
if(query.compareTo(sortedWords[mid]) == 0){
return;
}
if (query.compareTo(sortedWords[mid]) < 0){
binarySearch(sortedWords, query, startIndex, mid -1 );
}
if (query.compareTo(sortedWords[mid]) > 0){
binarySearch(sortedWords, query, mid + 1, endIndex);
}
return -1;
}
public static int getSmallestIndex(String[] words, String query, int startIndex, int endIndex){
return -1;
}
public static int getLargestIndex(String[] words, String query, int startIndex, int endIndex){
return -1;
}
public static int countWordsInSorted(String[] wordsTocount, String countedWord){
return 0;
}
}
【问题讨论】:
-
toLowerCase() 是 String 而非 String[] 的方法。
-
扔掉这个程序,重新开始。并按部就班地工作。这意味着:首先制作一个“获取第一个参数并将其存储在名为文件名的字符串中”的程序。比测试程序是否正确执行。比下一步扩展您的程序并再次测试它。以此类推。
-
好的,所以我在顶部更新以显示更多上下文,我不确定以下示例代码如何与我的论点联系起来? (这在我完成后在 cmd 中运行)我是否使用扫描仪并自己输入参数?我文件中的文字是论据吗?如果很明显,对不起,我只是不明白被问到什么。
-
@Ralf Renz 我如何将字符串传递给数组然后使 toLowerCase() 工作?
-
反过来:首先将 toLowerCase() 添加到字符串中,然后将修改后的字符串添加到数组中。
标签: java arrays java.util.scanner