一、实验要求
- 抽象类、上转型、方法重写、运行时多态等知识要点。
- 熟悉抽象编程和框架编程的方法。
- 掌握复杂条件判断的编程方法。
- 实验实现目标:编写一个抽象类,该类实现了方阵遍历的一般框架,实现了遍历和显示的大部分方法。继承这个抽象类,实现4个具体类(其中一个作为例子已经给出),实现它们分别的任意规模的方阵遍历。
二、实验内容和步骤
1.实验背景介绍
(1)方阵的行数和列数相等,遍历方阵的方式方法有很多,包括列主序、行主序、对角遍历、反对角遍历、顺时针遍历、逆时针遍历等等。
(2)首先实现一个抽象类,实现这些遍历方式的共同点和共同功能。
(3)继承抽象类,实现所有具体类,并加以测试。
2.用记事本书写一个Java程序
(1)、建立个人子目录
步骤1:建立个人子目录
第一次上机时先在D盘上建立一个以自己学号+姓名为目录名的子目录,如学号为210824109的张三同学,就用“210824109张三”为子目录名。实验完成的源代码、Java字节码和实验报告三个文件都要放在这个文件夹下(称为上交文件夹)。
步骤2:建立Java源代码文件
在所建立的文件夹下建立一个记事本文件SquarePoint.txt, SquareTraversal.txt, RowMajor.txt, ColMajor.txt, Diagonal.txt, AntiDiagonal.txt, SquareTraversalApplication.txt,并把它重命名为SquarePoint.java, SquareTraversal.java, RowMajor.java, ColMajor.java, Diagonal.java, AntiDiagonal.java, SquareTraversalApplication.java,
(2)、编写源代码
步骤1:创建7个公共类SquarePoint, SquareTraversal, RowMajor, ColMajor, Diagonal, AntiDiagonal, SquareTraversalApplication.
要创建的公共类在exp1包中,可引入其它的包。所创建的7个公共类在文件中的一行如下:
public class SquarePoint{… …}
public class SquareTraversal {… …}
……
步骤2:建立主方法main( )
在类SquareTraversalApplication的类体中编写主方法:
public static void main(String[] args){… …}
步骤3:编写各类的方法和SquareTraversalApplication的主方法main( )
主方法用于测试。各个类都已经给出了部分代码,请参考附件。
3.调试和运行
(1)、调试
步骤1:使用命令行工具,先进入用所建的目录下。参见图1。
步骤2:用javac exp2/SquareTraversalApplication.java编译并调试源代码文件。参见图1。
(2)、运行
使用java exp2.Fraction运行程序。参见文件最后的运行结果。
运行说明:路径每产生一个节点都要打印一次,不要等到所有路径产生之后再打印。
//文件 AntiDiagonal.java
package exp2;
/*
* 本类实现反对角方式的方阵遍历:
*/
public class AntiDiagonal extends SquareTraversal {
public AntiDiagonal(int size) {
initiate(size);
}
@Override public SquarePoint getInitPoint() {
return new SquarePoint(0, 0);
}
@Override public SquarePoint getNext() {
// Add your code here
SquarePoint currentPoint = currentPath.get(currentPath.size() - 1);
int currRow = currentPoint.getRow();
int currCol = currentPoint.getCol();
int nextRow = currRow;
int nextCol = currCol;
if(currRow == size - 1 && currCol == size - 1)
{
return null;
}
else if(currRow > 0 && currCol < size - 1)
{
nextCol = currCol + 1;
nextRow = currRow - 1;
}
else if(currCol == size -1 && currRow == 0)
{
nextCol = 1;
nextRow = size - 1;
}
else if(currRow == 0)
{
nextCol = currRow;
nextRow = currCol + 1;
}
else if(currCol == size - 1)
{
nextCol = currRow + 1;
nextRow = currCol;
}
return new SquarePoint(nextRow, nextCol);
}
}
// 文件ColMajor.java
package exp2;
/*
* 本类实现列主序的方阵遍历方式。
*/
public class ColMajor extends SquareTraversal {
public ColMajor(int size) {
initiate(size);
}
@Override public SquarePoint getInitPoint() {
return new SquarePoint(0, 0);
}
@Override public SquarePoint getNext() {
// Add your code here
SquarePoint currentPoint = currentPath.get(currentPath.size() - 1);
int currRow = currentPoint.getRow();
int currCol = currentPoint.getCol();
int nextRow = currRow;
int nextCol = currCol;
if (currRow < size-1) {
nextRow = currRow + 1;
}
else {
if (currCol == size-1) {
return null;
}
else {
nextCol = currCol + 1;
nextRow = 0;
}
}
return new SquarePoint(nextRow, nextCol);
}
}
// 文件Diagonal.java
package exp2;
/*
* 本类实现对角方式的方阵遍历。
*/
public class Diagonal extends SquareTraversal {
public Diagonal(int size) {
initiate(size);
}
@Override
public SquarePoint getInitPoint() {
return new SquarePoint(size - 1, 0);
}
@Override
public SquarePoint getNext() {
SquarePoint currentPoint = currentPath.get(currentPath.size() - 1);
int currRow = currentPoint.getRow();
int currCol = currentPoint.getCol();
int nextRow = currRow;
int nextCol = currCol;
if(currCol == size - 1 && currRow == 0)
{
return null;
}
else if(currCol < size - 1 && currRow < size - 1)
{
nextCol = currCol + 1;
nextRow = currRow + 1;
}
else if(currRow == size - 1 && currCol == size - 1)
{
nextCol = 1;
nextRow = 0;
}
else if(currRow == size - 1)
{
nextCol = size - 1 - currRow;
nextRow = size - 1 - currCol - 1;
}
else if(currCol == size - 1)
{
nextCol = size - 1 - currRow + 1;
nextRow = size - 1 - currCol;
}
return new SquarePoint(nextRow, nextCol);
}
}
// 文件RowMajor.java
package exp2;
/*
* 本类实现行主序的方阵遍历。
*/
public class RowMajor extends SquareTraversal {
public RowMajor(int size) {
initiate(size);
}
@Override public SquarePoint getInitPoint() {
return new SquarePoint(0, 0);
}
@Override public SquarePoint getNext() {
SquarePoint currentPoint = currentPath.get(currentPath.size() - 1);
int currRow = currentPoint.getRow();
int currCol = currentPoint.getCol();
int nextRow = currRow;
int nextCol = currCol;
if (currCol < size-1) {
nextCol = currCol + 1;
}
else {
if (currRow == size-1) {
return null;
}
else {
nextRow = currRow + 1;
nextCol = 0;
}
}
return new SquarePoint(nextRow, nextCol);
}
}
//文件SquarePoint.java
package exp2;
/*
* 本类对象表示方阵中的一个点。一个点由行和列两个坐标表示。
* 最上方的行号最小,为0;最左边的列号最小,为0。
*/
public class SquarePoint {
int row = 0;
int col = 0;
public SquarePoint() { }
public SquarePoint(int row, int col) {
this.row = row;
this.col = col;
}
public void setRow(int row) {
this.row = row;
}
public void setCol(int col) {
this.col = col;
}
public int getRow() {
return row;
}
public int getCol() {
return col;
}
@Override public String toString() {
return "(" + row + "," + col + ")";
}
}
//文件SquareTraversal.java
package exp2;
import java.util.ArrayList;
/*
* 这是一个抽象类,对任何一种遍历方阵的方法给出了整体的框架。
* 已经实现了遍历的关键步骤和打印输出的主要功能。
* 两个可变的方法需要用户实现,以适应不同的需求。
*/
public abstract class SquareTraversal {
// 方阵的规模,用size表示方阵的边长:
int size = -1; //一开始强制为-1,容易在子类运行中暴露没有初始化的问题。
// 获取遍历的初始点。使用抽象方法的意义是:强迫用户实现这个方法,而不至于遗漏。这个方法千万不可实现(最简单的实现那种),否则,最终用户很难发现问题所在。
public abstract SquarePoint getInitPoint();
// 遍历过程中当前的路径:
ArrayList<SquarePoint> currentPath = new ArrayList<>();
// 方阵初始化:size表示方阵的大小;initRow和initCol表示路径的起始位置:
public void initiate(int size) {
this.size = size; //这一句话和下一条语句千万不能颠倒,否则是一个打错。
SquarePoint initPoint = getInitPoint(); //只有使用上一句中赋值的size才是正确的。
currentPath.add(initPoint);
}
// 查找下一个点。
// 如果存下一个点,则返回这个点;否则返回null。
// 这个方法交给具体的类按照自己的场景去实现:
public abstract SquarePoint getNext();
// 路径推进一步(该步骤的执行之前先要判断是否存在可行的下一步):
public void step(SquarePoint nextPoint) {
currentPath.add(nextPoint); // 一条语句就可以实现这个功能。
}
@Override
public String toString() {
return "size: " + size + "; currentPath: " + currentPath;
}
String str [][] = new String[10][10];
public void Initstr()
{
for(int i=0;i<10;i++)
for(int j=0;j<10;j++)
str[i][j] = "-";
}
// 这个方法打印当前路径在整个方阵中的分布情况。
// 没有遍历过的点用减号表示;已经遍历过的点用加号表示;当前遍历点(最后一个点)用星号表示,以突出其变化:
// 具体实现留给同学们自己实现,打印格式轻参看附件的结果输出。
public void printCurrentPath() {
// Add your code here
SquarePoint currentPoint = currentPath.get(currentPath.size() - 1);
int currRow = currentPoint.getRow();
int currCol = currentPoint.getCol();
str[currRow][currCol] = "*";
String all = "";
for(int i=0;i<size;i++)
{
for(int j=0;j<size;j++)
{
all += str[i][j];
}
System.out.println(all);
all = "";
}
str[currRow][currCol] = "+";
}
// 用这个方法执行遍历的全过程。每遍历一步,都要打出路径的整体分布情况。
public void traverse() {
Initstr();
printCurrentPath();
System.out.println();
SquarePoint nextPoint = null;
while ((nextPoint = getNext()) != null) {
step(nextPoint);
printCurrentPath();
System.out.println();
}
System.out.println("The whole path is : " + currentPath);
System.out.println();
}
}
// 文件SquareTraversalApplication.java
package exp2;
/*
* 本类用来规模化测试抽象类下的每一个具体类的遍历情况。
*/
public class SquareTraversalApplication {
public static void main(String[] args) {
exp2.SquareTraversal[] squareTraversals = new exp2.SquareTraversal[4];
int[] sizes = {3, 3, 5, 4};
String[] names = {"行主序", "列主序", "反对角", "对角"};
squareTraversals[0] = new exp2.RowMajor(sizes[0]);
squareTraversals[1] = new exp2.ColMajor(sizes[1]);
squareTraversals[2] = new exp2.AntiDiagonal(sizes[2]);
squareTraversals[3] = new exp2.Diagonal(sizes[3]);
for (int i=0; i<squareTraversals.length; i++) {
System.out.println(names[i] + ", size: " + sizes[i]);
squareTraversals[i].traverse();
}
}
}