用桥梁模式实现螺旋矩阵算法

前两天写了一篇文章,分析了“内螺旋矩阵算法”的实现,讨论到了面向对象编程的可扩展性,于是今天用桥梁模式将代码做了些改造,具体如下:

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”两个对象封装的多种输出。

其他就不多说了,代码可以运行,直接拷贝到机器上跑一下应该就明白了,有什么不足或者疑问欢迎大家一起讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值