前两天写了一篇文章,分析了“内螺旋矩阵算法”的实现,讨论到了面向对象编程的可扩展性,于是今天用桥梁模式将代码做了些改造,具体如下:
package com.algo; class Position { private int x; private int y; public Position(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } } /** * 螺旋走向接口 */ abstract class Direction { protected StartPos startPos; protected Position pos;// 当期的位置 protected Position periodPos;// 一个周期的开始位置 protected int max;// 行列的最大值 protected int min;// 行列的最小值 protected int len;// 方阵的阶数 private void init() { if (startPos == null || len <= 0) return; Position tempPos = startPos.getPos(len); pos = new Position(tempPos.getX(), tempPos.getY()); periodPos = new Position(tempPos.getX(), tempPos.getY()); max = len - 1; min = 0; } public void setStartPos(StartPos startPos) {// 设置开始位置并重新初始化 this.startPos = startPos; init(); } public void setLen(int len) {// 设置长度并重新初始化 this.len = len; init(); } public int getLen() { return len; } public Position getPos() { int currRow = pos.getX(); int currCol = pos.getY(); Position currPos = new Position(currRow, currCol); genNextPos(); return currPos; } protected abstract void genNextPos(); } /** * 顺时针螺旋实现 */ class ClockwiseDir extends Direction { protected void genNextPos() { int row = pos.getX(); int col = pos.getY(); if (row == min && col < max) { col++; } else if (row < max && col == max) { row++; } else if (row == max && col > min) { col--; } else if (row > min && col == min) { row--; } else{ return; //匹配不到任何条件,则直接跳出(指螺旋的最后一个位置) } if (row == periodPos.getX() && col == periodPos.getY()) { min++; max--; genNextPos(); periodPos = new Position(pos.getX(), pos.getY()); } else { pos.setX(row); pos.setY(col); } } } /** * 逆时针螺旋实现 */ class AntiClockwiseDir extends Direction { protected void genNextPos() { int row = pos.getX(); int col = pos.getY(); if (row == min && col > min) { col--; } else if (row < max && col == min) { row++; } else if (row == max && col < max) { col++; } else if (row > min && col == max) { row--; } else{ return; //匹配不到任何条件,则直接跳出(指螺旋的最后一个位置) } if (row == periodPos.getX() && col == periodPos.getY()) { min++; max--; genNextPos(); periodPos = new Position(pos.getX(), pos.getY()); } else { pos.setX(row); pos.setY(col); } } } /** * 螺旋起始位置接口 */ interface StartPos { public Position getPos(int len); } /** * 起始位置为左上角的实现 */ class TopLeft implements StartPos { public Position getPos(int len) { return new Position(0, 0); } } /** * 起始位置为右上角的实现 */ class TopRight implements StartPos { public Position getPos(int len) { return new Position(0, len - 1); } } /** * 起始位置为左下角的实现 */ class BottomLeft implements StartPos { public Position getPos(int len) { return new Position(len - 1, 0); } } /** * 起始位置为右下角的实现 */ class BottomRight implements StartPos { public Position getPos(int len) { return new Position(len - 1, len - 1); } } public class HelixAlgo { public void print(Direction dir,int initVal,int step) { int len = dir.getLen(); if (len <= 0) { System.out.println("请输入大于0的整数!"); return; } int[][] helix = calculate(dir, len,initVal,step); for (int i = 0; i < helix.length; i++) { for (int j = 0; j < helix[i].length; j++) { System.out.print(helix[i][j] + "\t"); } System.out.println(""); } } private int[][] calculate(Direction dir, int len,int val,int step) { int[][] helix = new int[len][len]; for (int i = 0; i < len * len; i++) { Position pos = dir.getPos(); int row = pos.getX(); int col = pos.getY(); helix[row][col] = val; val+=step; } return helix; } public static void main(String[] args) { HelixAlgo algo = new HelixAlgo(); int len = 5; Direction dir_clockwise = new ClockwiseDir(); dir_clockwise.setLen(len); //用set方法动态地插入长度 Direction dir_antiClockwise = new AntiClockwiseDir(); dir_antiClockwise.setLen(len); System.out.println("\n左上角开始顺时针内旋(长度" + len + "):"); dir_clockwise.setStartPos(new TopLeft()); //用set方法动态地插入开始位置 algo.print(dir_clockwise,1,1); System.out.println("\n右上角开始顺时针内旋(长度" + len + "):"); dir_clockwise.setStartPos(new TopRight()); algo.print(dir_clockwise,1,1); System.out.println("\n右下角开始顺时针内旋(长度" + len + "):"); dir_clockwise.setStartPos(new BottomRight()); algo.print(dir_clockwise,1,1); System.out.println("\n左下角开始顺时针内旋(长度" + len + "):"); dir_clockwise.setStartPos(new BottomLeft()); algo.print(dir_clockwise,1,1); System.out.println("\n左上角开始逆时针内旋(长度" + len + "):"); dir_antiClockwise.setStartPos(new TopLeft()); algo.print(dir_antiClockwise,1,1); System.out.println("\n右上角开始逆时针内旋(长度" + len + "):"); dir_antiClockwise.setStartPos(new TopRight()); algo.print(dir_antiClockwise,1,1); System.out.println("\n右下角开始逆时针内旋(长度" + len + "):"); dir_antiClockwise.setStartPos(new BottomRight()); algo.print(dir_antiClockwise,1,1); System.out.println("\n左下角开始逆时针内旋(长度" + len + "):"); dir_antiClockwise.setStartPos(new BottomLeft()); algo.print(dir_antiClockwise,1,1); System.out.println("\n中心点开始顺时针外旋(长度" + len + "):"); dir_antiClockwise.setStartPos(new TopLeft()); algo.print(dir_antiClockwise,len*len,-1); System.out.println("\n中心点开始逆时针外旋(长度" + len + "):"); dir_clockwise.setStartPos(new TopLeft()); algo.print(dir_clockwise,len*len,-1); } }
螺旋矩阵的解题思路就不多说了,不了解的可以看下我前面的文章“内螺旋矩阵算法分析”,这里主要说下为什么要用桥梁模式:
首先看看螺旋矩阵有哪些变化点:矩阵阶数(即边长),初始位置,和螺旋方向(顺时针,逆时针)
初始位置前面的文章在回复中已经提及,合法的初始位置只有四个既矩阵的四个角,否则会出现死胡同(可参考前面文章在10楼的回复)。
考虑到弹性,这三个变化点都应该是可以独立变化的,其中矩阵阶数只是个整数,它的变化比较方便,而另外两个可以用不同的接口封装,即上面代码的"StartPos"接口和"Direction"抽象类,这样两个变化点便可以独立的变化,因此想到了使用桥梁模式,把这两个变化点的耦合彻底移到对象层面,于是便有了mian函数中“dir_clockwise ”和“dir_antiClockwise”两个对象封装的多种输出。
其他就不多说了,代码可以运行,直接拷贝到机器上跑一下应该就明白了,有什么不足或者疑问欢迎大家一起讨论。