public class
|
|--main() 从 L11 - L23
| |
| |--L15 创建数组
| |
| |--L17 输出原数组
| |
| |--L19 查找最值
| |
| |--L21 输出最值
|
|
|--setArr() 从 L26 - L60
| |
| |--L33 - L34 选择随机生成还是手动输入
| |
| |--L36 - L40 如果是随机生成,则输入生成多少个数,系统自动生成
| |
| |--L43 - L48 如果是手动输入,则输入要输入的个数,用户手动输入
| |
| |--L52 - L53 输入要查找几个最值
| |
| |--L55 - L56 输入要分为几个块
|
|
|--printArr() 从 L64 - L88
| |
| |--L71 - L75 对应 L17 的调用进行输出
| |
| |--L79 - L83 对应 L21 的调用进行输出
|
|
|--findArr() 从 L91 - L149
|
|--L93 - L98 确定列数
|
|--L105 - L111 一维数组转二维数组
|
|--L115 - L145 查找最值
|
|--L117 - L122 查找每一行中的最大值,放入 flag[]
|
|--L128 - L139 查找 flag[] 中的最大值
|
|--L141 - L144 把最值放入 arr[]
Arr[][] 一个二维数组,里面存放转置过的数据
array[] 一个一维数组,用来存放输入或生成的数据
arr[] 一个一维数组,用来存放问题中要求的最值
flag[] 一个一维数组,用来存放 Arr[][] 中每一行的最大值
A[] 一个一维数组,用来存放 Arr[][] 中每一行最大值的列下标
简单说一下核心算法:
首先,输入的数据都是存放在一维数组里的吧,为了便于表示,可以将一维数组转为二维数组代码如下:
if( n % I == 0 ) { // I是用户输入的,要分成多少个块,在这里用于定义二维数组行
J = n / I; // J是通过数据个数和行数计算出来的列数
}
else {
J = n / I + 1 ;
}
for( i = 0 ; i < I && p != n ; i++ ) {
for( j = 0 ; j < J && p != n ; j++) {
Arr[i][j] = array[p++];
System.out.printf("%-5d",Arr[i][j]);
}
System.out.println("\n");
}
z = j - 1;
其中 n 是输入了多少个数据,if -- else 就是根据输入了多少数据和要分成多少块来判断二维数组有多少列,能被行数整除则就是除出来的结果,否则还要 +1 不然放不下。i,j 是二维数组的下标,p 是一维数组的下标,当 p == n 也就是转换结束了。
转换成功后,就开始找每一行的最大值嘛,前面不是说了有一个数组用来存放最值嘛,那这个数组没装满是不是就要一直找下去呢?所以这里就可以设置一个直到该数组装满数据才结束的循环 while(arr[s-1] == 0),arr 就是这个数组了,s 就是要存储多少个数据。
arr[0] = 0;
while( arr[s-1] == 0 ) {
for( i = V ; i < I ; i ++ )
for( j = 0 ; ( i < I-1 && j < J ) || ( i == I-1 && j < J ) || ( i == I-1 && j < z ); j++ ) {
if( flag[i] < Arr[i][j] && Arr[i][j] != 0) {
flag[i] = Arr[i][j];
A[i] = j;
}
}
if(o !=0) {
i = I-1;
}
这个 V 干什么用呢?它的初值是 0。请大家想想,这个程序的核心就是在循环中,先把每一行的最大值找出来,放到数组 flag 里存放着(这里的 flag 和 Arr 是对应的,flag 的每一个元素对应存放 Arr 中一行的最大值),然后后面会进行比较,把最大的赋值给 arr 数组,然后把那个最大数据在二维数组中赋值为 0,下次不参与比较,那么说到底,需要重新找最值得就是上一轮最大值的那一行,所以,这个 V 的作用,就是用来标志上一次的最值是哪一行,程序再次循环就直接从那一行开始,避免浪费时间。
同理,变量 o 的作用也是一样,第一轮必须把所有行的最大值找完,在已经确定了第一个最大值后,第二轮循环直接从 V 行开始,然后通过判断 o 的值,达到直接让 i循环 直接结束,不再继续往下寻找。 o 的初值是 0 ,所以第一次并不会执行语句改变 i 的值。
搞清楚了 V 和 o 的作用,就来简单看一下这段吧,while 前面说过了,i循环 控制行(也就是块),j循环 控制列,if 用来找每一行的最值,找到的最值放在 flag 中,数组 A 用来记录每一行最值得列下标,方标后面归零。
第一次找到所有行的最值是吧,然后把最值进行比较,比较完后,将最值中的最大值放入 arr ,并将该最值二维数组中的位置归零,避免重复比较。完后,第二次直接从上一轮的最值行中继续找,其他行因为最值还在,所以不需要重新查找。
i = 1;
max = flag[0];
V = 0;
while(i < I) {
if ( max < flag[i] ) {
max = flag[i];
V = i;
}
++i;
}
arr[f++] = max;
Arr[V][A[V]]=0;
flag[V]=0;
o ++;
}
到了这里就简单明了了,max 最大值,先存放 flag[0] 的值,然后依次比较,新的最大值赋给 max ,而新的最大值对应的行数赋给 V ,然后 i 自增,把最值往 arr 里放,A[V] 里本来存放了各行最大值的列下标,那么 Arr[ V ][ A[V] ] 就可以定位到最值在二维数组中的位置,将值归零。还不要忘了 flag 里也要归零,不然查找的时候就找不到比 flag [V] 更大的了。o++ 使得之后查找完一行后直接结束 i循环
附上完整程序:
setArr() : 用来生成数据,在方法中,会先问用户,是随机生成啊,还是手动输入啊。然后随机会问用户,随机生成多少个数啊?手动输入会问用户,手动输入多少个数啊?这个还是很重要的,关系到数组长度。
printArr() : 用来输出,我懒得写两个方法,于是就用了一个 switch()
findArr() : 这个是核心方法,在上面已经说过了,看不懂的话,,,有问题就问我吧
package Experiment;
import java.util.Scanner;
import Naraku.Nara; // 导入我自己的方法库;
public class tallestPerson{
static int n,s,i, j, f=0,o=0,V=0,p=0,max,I,J,z;
public static void main(String args[]) {
int[] Arr, find;
Arr = setArr();
printArr(Arr);
find = findArr(Arr);
printArr(find);
}
public static int[] setArr() { // 建立一维数组,确定建立数据的个数,确定要找多少个最值,确定要分多少块;
int[] Arr;
String IO;
int i = 0;
Scanner input = new Scanner(System.in);
System.out.println("Do you wanna random or input ?"); //确定是随机还是输入;
IO = input.nextLine();
if(IO.equals("random")) {
System.out.println("How many number do you wanna setup ?"); // 随机生成多少;
n = input.nextInt();
Arr = new int[n];
Arr = Nara.setRandom(n,100);
}
else {
System.out.println("How many number do you wanna input ?"); // 输入多少个值;
n = input.nextInt();
Arr = new int[n];
while(n > i) {
Arr[i++] = input.nextInt();
}
}
System.out.printf("How many number do you wanna find ?\n"); // 要找几个最值;
s = input.nextInt();
System.out.printf("How many block do you wanna divide ?\n"); //要分几个块;
I = input.nextInt();
return Arr;
}
static int abc=0; // 标志第几次输出;
public static void printArr(int[] a) {
int i = 0;
switch (abc++) {
case 0 :{
System.out.println("The array are : ");
for( ; i < n; i++ )
System.out.printf("%-5d",a[i]);
System.out.printf("\n");
break;
} // 第一次输出原一维数组;
case 1 :{
System.out.println("The biggest " + s + " numbers are : ");
for( ; i < s; i++ )
System.out.printf("%-5d",a[i]);
System.out.printf("\n");
break;
} // 第二次输出最值数组;
}
}
public static int[] findArr(int[] array) {
if( n % I == 0 ) {
J = n / I;
}
else {
J = n / I + 1 ;
} // 根据输入数据个数和要分的块数,确定每一行多少列;
int[] arr = new int[s], flag = new int[I], A = new int [I];
int[][] Arr= new int[I][J];
System.out.println("\nYour array has been divided into " + I + " blocks with " + J + " cols\n");
for( i = 0 ; i < I && p != n ; i++ ) {
for( j = 0 ; j < J && p != n ; j++) {
Arr[i][j] = array[p++];
System.out.printf("%-5d",Arr[i][j]);
}
System.out.println("\n");
} //将原一维数组转换成二维数组,并输出;
z = j - 1;
arr[0] = 0;
while( arr[s-1] == 0 ) { // while() 里的判断式,意思为只有把最值找完,才;
for( i = V ; i < I ; i ++ )
for( j = 0 ; ( i < I-1 && j < J ) || ( i == I-1 && j < J ) || ( i == I-1 && j < z ); j++ ) {
if( flag[i] < Arr[i][j] && Arr[i][j] != 0) {
flag[i] = Arr[i][j];
A[i] = j;
} // 找出每一行最大值放到 flag[] 里,列下标放到 A[] 里;
}
if(o !=0) {
i = I-1;
} // 第一轮找最值不影响,第二轮执行,找完第 V 行后直接结束 i循环;
i = 1;
max = flag[0];
V = 0;
while(i < I) {
if ( max < flag[i] ) {
max = flag[i];
V = i;
}
++i;
} // 查找 flag 里的最大值;
arr[f++] = max;
Arr[ V ][ A[V] ]=0;
flag[V]=0;
o++;
} // 把最大值放入 arr ,Arr[][] 和 flag[] 中对应位置归零,防止最值再次参与比较;
return arr;
}
} // 这里面有 1/3 的行数是空格