隐式图的搜索问题(九宫重排)——项目实现
隐式图的搜索问题(九宫重排)——项目实现
源代码
package SearchPath;
public class test {
public static void main(String[] args) {
Database database = new Database();
SearchPath searchPath = new SearchPath(database);
searchPath.insertFirst();
}
}
package SearchPath;
public class Node {
private int status[];
private int parent[];
public int[] getParent() {
return parent;
}
public void setParent(int[] parent) {
this.parent = parent;
}
public int[] getStatus() {
return status;
}
public void setStatus(int[] status) {
this.status = status;
}
private int g;
private int h;
public void setH(int h) {
this.h = h;
}
public int getG() {
return g;
}
public void setG(int g) {
this.g = g;
}
public int getF() {
return g + h;
}
}
package SearchPath;
import java.util.ArrayList;
import java.util.List;
public class Database {
private List<Node> nodeList = new ArrayList<>();
private List<Node> closeList = new ArrayList<>();
private List<Node> changeList = new ArrayList<>();
private List<Node> pathList = new ArrayList<Node>();
public Database() {
}
public List<Node> getPathList() {
return pathList;
}
public List<Node> getCloseList() {
return closeList;
}
public List<Node> getOpenList() {
return nodeList;
}
public List<Node> getChangeList() {
return changeList;
}
}
package SearchPath;
import java.util.Arrays;
import java.util.List;
public class NodeDao {
private List<Node> openList;
private List<Node> closeList;
private List<Node> changeList;
private List<Node> pathList;
public List<Node> getPathList() {
return pathList;
}
public List<Node> getOpenList() {
return openList;
}
public NodeDao(Database database) {
this.openList = database.getOpenList();
this.closeList = database.getCloseList();
this.changeList = database.getChangeList();
this.pathList = database.getPathList();
}
/**
* 写入open表
* @return
*/
public void insertOpenList(Node node) {
openList.add(node);
}
/**
* 写入close表
*/
public void insertCloseList(Node node) {
closeList.add(node);
openList.remove(node);
}
/**
* 对open表按f(n)由小到大排序
*/
public void sort() {
bubbleSort(openList);
}
/**
*冒泡排序
*/
public void bubbleSort(List<Node> list){
for (int i = 0; i < list.size(); i++) {
for (int j = 0; j < list.size() - i - 1; j++) {
if (list.get(j).getF() > list.get(j + 1).getF()) {
Node temp = list.get(j);
list.set(j, list.get(j + 1));
list.set(j + 1, temp);
}
}
}
}
/**
* 判断是否已存储
*/
public boolean judge(Node node) {
boolean flag = false;
for (int i = 0; i < openList.size(); i++) {
if (Arrays.equals(openList.get(i).getStatus(), node.getStatus())) {
flag = true;
}
}
for (int i = 0; i < closeList.size(); i++) {
if (closeList != null) {
if (Arrays.equals(closeList.get(i).getStatus(), node.getStatus())) {
flag = true;
}
}
}
return flag;
}
/**
* g(n)相同时,将f(n)较大值从open表中删除
*/
public void delete() {
for (int i = 0, j = openList.size() - 1; i < j; i++, j--) {
if (openList.get(i).getG() == openList.get(j).getG()) {
changeList.add(openList.get(i));
changeList.add(openList.get(j));
}
}
if (changeList.size() > 1) {
bubbleSort(changeList);
//由小到大排序 如果最小的有两个,则把其他的删了
if (changeList.get(0).getF() == changeList.get(1).getF()) {
for (int i = 2; i < changeList.size(); i++) {
openList.remove(changeList.get(i));
closeList.add(changeList.get(i));
}
} else {
for (int i = 1; i < changeList.size(); i++) {
openList.remove(changeList.get(i));
closeList.add(changeList.get(i));
}
}
for (int i = 0; i < changeList.size(); i++) {
changeList.remove(i);
}
} else if (changeList.size() == 1) {
openList.remove(changeList.get(0));
closeList.remove(changeList.get(0));
changeList.remove(0);
}
}
/**
* 通过数组找到该结点
*/
public Node previous(int[] arr) {
Node node = null;
for (int i = 0; i < closeList.size(); i++) {
if (Arrays.equals(closeList.get(i).getStatus(), arr)) {
node = closeList.get(i);
//保存至路径表,方便最后按顺序输出
pathList.add(node);
}
}
return node;
}
}
package SearchPath;
import java.util.Arrays;
import java.util.Scanner;
public class SearchPath {
private NodeDao nodeDao;
public SearchPath(Database database) {
nodeDao = new NodeDao(database);
}
int[] start=new int[9];//{2, 5, 8, 3, 4, 6, 1, 7, 0};
int[] target=new int[9];// {2, 8, 6, 3, 5, 0, 1, 4, 7};
int g = 0;
int flag = -1;
/**
* 将输入的数存入数组中
*/
public void inputStart(){
Scanner scanner=new Scanner(System.in);
System.out.println("请输入初始状态:");
for(int i=0;i<9;i++) {
start[i] = scanner.nextInt();
}
}
public void inputTarget(){
Scanner scanner=new Scanner(System.in);
System.out.println("请输入目标状态:");
for(int i=0;i<9;i++) {
target[i] = scanner.nextInt();
}
}
/**
* 将第一个结点写入open表,并进行第一次搜索、随之判断、再搜索、再判断
*/
public void insertFirst() {
inputStart();
inputTarget();
Node node = new Node();
node.setStatus(start);
node.setH(countH(start));
node.setG(0);
nodeDao.insertOpenList(node);
g++;
move(node);
start();
}
/**
* 根据不同的情况选择下一步进行扩展搜索的结点
*/
public void start() {
if (nodeDao.getOpenList().size() > 1) {
if (nodeDao.getOpenList().get(0).getF() != nodeDao.getOpenList().get(1).getF()) {
g++;
move(nodeDao.getOpenList().get(0));
nextSearch();
} else {
g++;
move(nodeDao.getOpenList().get(0));
move(nodeDao.getOpenList().get(1));
nextSearch();
}
} else {
g++;
move(nodeDao.getOpenList().get(0));
nextSearch();
}
}
/**
* 再次搜索与判断
*/
public void nextSearch() {
search();
if (flag >= 0) {
searchParent(nodeDao.getOpenList().get(flag));
printLast();
} else {
//如果g(n)相同,则将f(n)较大的值从open表中删除,放入close表中
nodeDao.delete();
start();
}
}
/**
* 移动空格,产生新的结点
*/
public void move(Node parent) {
int zero = index(parent.getStatus());
if (zero != 0 && zero != 3 && zero != 6) {
//如果能左移,则进行左移创造新结点
int[] A = parent.getStatus().clone();
A[zero] = A[zero - 1];
A[zero - 1] = 0;
insertNew(parent, A);
}
if (zero != 2 && zero != 5 && zero != 8) {
//如果能右移,则进行右移创造新节点
int[] B = parent.getStatus().clone();
B[zero] = B[zero + 1];
B[zero + 1] = 0;
insertNew(parent, B);
}
if (zero != 0 && zero != 1 && zero != 2) {
//如果能上移,则进行上移创造新节点
int[] C = parent.getStatus().clone();
C[zero] = C[zero - 3];
C[zero - 3] = 0;
insertNew(parent, C);
}
if (zero != 6 && zero != 7 && zero != 8) {
//如果能下移,则进行下移创造新节点
int[] D = parent.getStatus().clone();
D[zero] = D[zero + 3];
D[zero + 3] = 0;
insertNew(parent, D);
}
//将父节点存入close表,并从open表中删除
nodeDao.insertCloseList(parent);
nodeDao.sort();
}
/**
* 根据情况将新结点加入open表
*/
public void insertNew(Node parent, int[] arr) {
Node node = new Node();
node.setStatus(arr);
node.setG(g);
node.setH(countH(arr));
node.setParent(parent.getStatus().clone());
if (!nodeDao.judge(node)) {
nodeDao.insertOpenList(node);
}
}
/**
* 计算h(n)
*/
public int countH(int[] arr) {
int flag = 0;
for (int i = 0; i < 9; i++) {
if (arr[i] != target[i]) {
flag++;
}
}
return flag;
}
/**
* 空格即零所在的位置
*/
public int index(int[] now) {
int index = -1;
for (int i = 0; i < 9; i++) {
if (0 == now[i]) {
index = i;
}
}
return index;
}
/**
* 循环找到父结点,存入pathList
*/
public void searchParent(Node targetNode) {
if (targetNode.getParent() != null) {
int[] result = targetNode.getParent();
//通过数组找到该结点,存入pathList
searchParent(nodeDao.previous(result));
}
}
/**
* 判断openList中是否已有目标节点
*/
public void search() {
for (int i = 0; i < nodeDao.getOpenList().size(); i++) {
if (Arrays.equals(target, nodeDao.getOpenList().get(i).getStatus())) {
flag = i;
}
}
}
/**
* 按顺序打印路径
*/
public void printLast() {
System.out.println("最短路径如下:");
int number = 0;
for (int i = nodeDao.getPathList().size() - 1; i >= 0; i--) {
int count = 0;
int[] result = nodeDao.getPathList().get(i).getStatus();
for (int j = 0; j < 9; j++) {
count++;
printOrder(result, count, j);
}
System.out.println("------------");
number++;
}
for (int i = 0; i < target.length; i++) {
flag++;
printOrder(target, flag, i);
}
System.out.println("------------");
System.out.println("一共需要走 " + number + "步 达成目标");
}
/**
* 打印输出
*/
public void printOrder(int[] arr, int tab, int index) {
System.out.print(arr[index] + " ");
if (tab % 3 == 0) {
System.out.println(" ");
}
}
}
运行结果
2021.3.15修改:可输入初始状态和目标状态数组。