旋转填数
為什么80%的碼農都做不了架構師?>>> ??
前兩天想起自己大二曾經寫過的旋轉填數。就是向一個矩陣中填充數字,形成螺旋狀,比如5階的:1????? 2?? ?? 3????? 4?? ? 5???
16??? 17??? 18??? 19??? 6???
15??? 24??? 25??? 20??? 7???
14??? 23??? 22??? 21??? 8???
13??? 12??? 11??? 10??? 9????
當時寫的我自認為就很不錯了。因為是用遞歸算法做的,那個年代遞歸被我們視為神技.........
今天又寫了一個版本,不過是基于OO思想的。想法是一只螞蟻從(0,0)點開始爬,每次遇到墻壁或者已經爬過的地方就向右轉,每到一個沒有爬過的地方就就踩一個腳印,這樣踩完以后區域也就填充完成了。個人認為這個版本雖然代碼多,但是可讀性好,想法自然,也便于維護,相比算法版本還要好玩很多。要是討論設計模式,能扯上工廠方法和策略模式....不過現在我對模式這種東西極為反感,寫的時候也沒有去想這些。
?
最后貼代碼:
首先是填充區域類:
package zone;import algo.*;/*** 填充區域* * @author Jeky* */ public class Zone {/*** 構造一個新的填充區域* * @param size 填充區域大小*/public Zone(int size) {this.size = size;board = new int[size][size];}/*** 以特定值填充某個位置* * @param p 位置* @param value 值*/public void fill(Point p, int value) {board[p.getX()][p.getY()] = value;}/*** 以特定值填充某個位置* * @param x 橫坐標* @param y 縱坐標* @param value 值*/public void fill(int x, int y, int value) {board[x][y] = value;}/*** 獲取某個特定位置的值* * @param p 位置* @return 值*/public int get(Point p) {return board[p.getX()][p.getY()];}/*** 獲取某個特定位置的值* * @param x 橫坐標* @param y 縱坐標* @return 值*/public int get(int x, int y) {return board[x][y];}/*** 獲取區域大小* * @return 區域大小*/public int getSize() {return size;}@Overridepublic String toString() {StringBuilder sb = new StringBuilder();for (int i = 0; i < size; i++) {for (int j = 0; j < size; j++) {sb.append(board[j][i] + "\t");}sb.append("\n");}return sb.toString();}private final int size;private int[][] board; }坐標點:
package zone;/*** 二維位置* * @author Jeky* */ public class Point {/*** 以橫縱坐標構造一個新的位置* * @param x 橫坐標* @param y 縱坐標*/public Point(int x, int y) {super();this.x = x;this.y = y;}/*** 獲得橫坐標* * @return 橫坐標*/public int getX() {return x;}/*** 獲得縱坐標* * @return 縱坐標*/public int getY() {return y;}@Overridepublic String toString() {return "(" + x + "," + y + ")";}private final int x;private final int y; }填充接口:
package algo;import zone.Zone;/*** 旋轉填數接口* * @author Jeky* */ public interface ZoneFiller {/*** 向區域填充數據* * @param zone 填充區域*/void fill(Zone zone); }遞歸填充算法:
?
package algo;import zone.Zone;/*** 以遞歸模式進行填充的填充類* * @author Jeky* */ public class RecursionFiller implements ZoneFiller {@Overridepublic void fill(Zone zone) {int size = zone.getSize();this.zone = zone;fill(1, size, 0, 0);}/*** 進行遞歸填充* * @param startNumber 開始數字* @param size 填充長度* @param startX 填充開始橫坐標* @param startY 填充開始縱坐標*/private void fill(int startNumber, int size, int startX, int startY) {if (size == 0) {return;} else if (size == 1) {zone.fill(startX, startY, startNumber);} else {for (int i = startX; i < size + startX - 1; i++) {zone.fill(i, startY, startNumber);startNumber++;}for (int i = startY; i < size + startY - 1; i++) {zone.fill(startX + size - 1, i, startNumber);startNumber++;}for (int i = startX + size - 1; i >= 1 + startX; i--) {zone.fill(i, startY + size - 1, startNumber);startNumber++;}for (int i = startY + size - 1; i >= 1 + startY; i--) {zone.fill(startX, i, startNumber);startNumber++;}fill(startNumber, size - 2, startX + 1, startY + 1);}}private Zone zone; }螞蟻填充算法:
?
package algo;import zone.Point; import zone.Zone;/*** 螞蟻類,負責在填充區域上爬行并踩出記號* * @author Jeky* */ public class Ant implements ZoneFiller{public Ant() {movements = new Movement[4];movements[0] = new RightMovement();movements[1] = new DownMovement();movements[2] = new LeftMovement();movements[3] = new UpMovement();nowMovementIndex = 0;}/*** 爬行并踩出記號* * @param zone 填充區域*/public void fill(Zone zone) {footPrint = 1;location = new Point(0, 0);tread(zone);int maxPrint = zone.getSize() * zone.getSize();while (footPrint <= maxPrint) {Point nextLocation = getNextLocation();if (canWalkTo(zone, nextLocation)) {location = nextLocation;tread(zone);} else {changeDirection();}}}/*** 踩出記號* * @param zone 填充區域*/private void tread(Zone zone) {zone.fill(location, footPrint);footPrint++;}/*** 獲取下一個要爬行到的位置* * @return 下一個爬行到的位置*/private Point getNextLocation() {Movement m = movements[nowMovementIndex];return m.getNextPoint(location);}/*** 是否可以向前爬行* * @param zone 填充區域* @param p 前面的位置* @return 如果可以向前,返回true,否則返回false*/private boolean canWalkTo(Zone zone, Point p) {return p.getX() >= 0&& p.getY() >= 0&& p.getX() < zone.getSize()&& p.getY() < zone.getSize()&& zone.get(p) == 0;}/*** 換方向*/private void changeDirection() {nowMovementIndex = (nowMovementIndex + 1) % 4;}/*** 爬行動作*/private interface Movement {Point getNextPoint(Point p);}/*** 向上爬*/private class UpMovement implements Movement {@Overridepublic Point getNextPoint(Point p) {return new Point(p.getX(), p.getY() - 1);}}/*** 向下爬*/private class DownMovement implements Movement {@Overridepublic Point getNextPoint(Point p) {return new Point(p.getX(), p.getY() + 1);}}/*** 向左爬*/private class LeftMovement implements Movement {@Overridepublic Point getNextPoint(Point p) {return new Point(p.getX() - 1, p.getY());}}/*** 向右爬*/private class RightMovement implements Movement {@Overridepublic Point getNextPoint(Point p) {return new Point(p.getX() + 1, p.getY());}}private Movement[] movements;private int nowMovementIndex;private int footPrint;private Point location; }轉載于:https://my.oschina.net/Jeky/blog/28757
總結
- 上一篇: Oracle SQL Parsing F
- 下一篇: 小米9和华为mate20谁好(MIUI1