在下一个例子中,我们将解决一个涉及数字列表的中等复杂问题。我们将从文本文件中读取这个数字列表,并将列表存储在一个数组中。然后我们将使用该数组来解决这个问题。
问题是在整数列表中找到出现次数最多的整数。解决此问题的一个明显策略是询问文件中的每个整数在文件中出现多少次。当我们在可能的整数范围内工作时,我们将记录哪个整数出现的次数最多。
第一步是为我们的程序编写main方法。这个main方法将相当简短,因为在main方法的关键时刻,我们将调用其他方法来帮助我们完成工作。
public static void main(String[] args) {int numbers[] = readNumbers("numbers.txt");//查找数组中最小和最大的数字int smallest = findSmallest(numbers);int large = findbiggest (numbers);int greatestCount = 0;int mostCommonNumber = 0;For (int x = smallest;X <=最大;x++){//计算x出现的次数。int count = countNumber(numbers,x);//检查这是否是最常见的数字。if(count > greatestCount) {greatestCount = count;mostCommonNumber = x;}} //打印结果System.out。println(mostCommonNumber+“出现次数最多”);system . out。println("It seems "+greatestCount+" times.");}
为了完成我们的程序,我们需要为在main中调用的四个方法编写代码。下面是每个方法应该做什么的简要描述。
readNumbers
从文件中读取整型数列表,将其放入数组中,并将该数组返回给我们。findSmallest
查找并返回数组中最小的数字。findLargest
查找并返回数组中最大的数字。countNumber
计算给定数字在数组中出现的次数。下面是这些方法的代码。由于每个方法都有一个定义清晰且相对简单的任务要执行,因此为每个单独的方法编写代码并不太难。
public static int[] readNumbers(String fileName){扫描器输入= null;try {input = new Scanner(new File(fileName));} catch (Exception ex) {ex. printstacktrace ();} //我们需要先计算数字的个数。我们将读取//遍历文件一次,只是为了计算//有多少个数字…int N = 0;while (input.hasNextInt()) {int未使用= input.nextInt();N + +;} input.close ();//一旦我们知道文件中有多少个数字,我们就可以创建一个//数组来保存它们。int[] A = new int[N];//现在我们必须再次读取文件,将数字//放入数组中。try {input = new Scanner(new File(fileName));} catch (Exception ex) {ex. printstacktrace ();} int n = 0;//下一个数字的位置。while (input.hasNextInt()) {A[n] = input.nextInt();n + +;} input.close ();返回一个;}公共静态int findSmallest(int A[]) {int smallest = A[0];For (int n = 1;n < A.length;n++) {if (A[n] <最小){最小= A[n];}}返回最小值;}公共静态int查找最大(int A[]) {int最大= A[0];For (int n = 1;n < A.length;n++) {if (A[n] >最大){最大= A[n];}}返回最大;}公共静态int countNumber(int A[], int x) {int count = 0;For (int n = 0;n < A.length;n++) {if (A[n] == x) {count++;}}返回计数;}
方法的一大优点是它们是可移植的。一旦我们为解决特定问题的方法编写了代码,我们就可以在我们必须解决相同问题的其他项目中重用相同的方法。readNumbers方法就是一个很好的例子。我们将在本课程中看到的许多程序都要求我们从文件中读取整型数列表,并将这些数字放入数组中。为了使该方法更加灵活,我将其设计为以要打开的文件的名称作为参数。这使得在不同的程序中使用该方法更加容易。
您将在这些注释的顶部找到第二个项目,该项目演示了选择排序算法。这个项目中的代码非常直接地取自教科书。你可以在课本7.11节中阅读更多关于select sort的内容。
在许多情况下,能够对数据项列表进行排序为解决问题开辟了新的方法。其中一个例子就是我在讲义开头解决的问题。解决此问题的另一种策略包括首先对数字列表进行排序,然后运行查找连续数字的搜索过程。
如果对包含某些数字重复项的数字列表进行排序,您将看到这些数字在排序列表中形成相同重复数字的运行。搜索这些路线并确定哪条路线最长是一个相对简单的问题。
下面是使用此策略查找文件中最常见数字的程序的主要方法。
public static void main(String[] args) {int numbers[] = readNumbers("numbers.txt");//排序列表selectionSort(numbers);//查找最常见的数字int greatestCount = 1;int mostCommonNumber = number[0];for (int n = 1;n < numbers.length;n++) {if(numbers[n] == numbers[n-greatestCount]) {greatestCount++;mostCommonNumber = number [n];}} //打印结果System.out。println(“数字” + mostCommonNumber + “出现次数最多”);system . out。println("It seems " + greatestCount + " times in the file.");}
这里的循环搜索相同次数的运行,使用一种简单的策略来检测运行。循环中的if语句将列表中的下一个数字与列表中后面几个空格的数字进行比较。如果这两个数相等,我们就发现了一段一定长度的行程。如果这个长度大于我们迄今为止看到的最大长度,我们就可以记录下这个新的获胜数字的细节。
每当我们有多个解决问题的策略时,计算机科学家通过比较两种策略解决问题所需的时间来比较这两种解决方案的相对质量。计算机科学家衡量程序运行时效率的一种方法是,用程序必须处理的数据项数量的函数来表示它所花费的时间。
如果我们有一个需要处理的N个整数的列表,我今天展示的两个解的运行时间都与N2成正比。在第一种算法中,我们必须计算每种可能数字出现的次数。在一个典型的文件中,大约有N个项目需要计数。一次遍历数组来计算某项出现的次数所需的时间与N成正比,因此第一个算法所需的总工作量与N2成正比。在第二种算法中,我们必须对数字进行排序,然后遍历列表以确定最长的运行时间。使用选择排序排序所需的时间与N2成正比,而运行检查所需的时间与n成正比。同样,第二种算法最终所需的时间与N2成正比。
第二种算法的优势在于我们可以用一种更有效的排序算法取代选择排序。在周三的课上,我将展示一些排序算法,它们可以对整数列表进行排序时间正比于N log N,而不是N2。通过使用其中一种更有效的排序算法,我们可以将第二种方法所需的时间减少到nlogn,这比N2有了很大的改进。