EasyLearn--JAVA實現32個經典演算法設計(一):A*演算法
A*演算法是一種靜態路網中求解最短路徑最有效的直接搜尋方法,其中經典的圖形有網格影象如下:
根據這個影象來對演算法進行說明主要思想:該演算法又稱為啟發式演算法,啟發之處在於公式F=G+H,F為最終結果值,G為所行走的步數,H就是預估值,其中H可根據不同的策略採用不同的規則定義,此處使用無視障礙物的最短距離最為預估剩餘步數,依次算出起始格周圍的最終結果F值,然後取最小值最為下一步要前進的網格,最終找到終點格。
下面具體看看用程式碼如何實現。
第一步,定義網格的含義實體BEAN
import java.io.Serializable; /** * 節點類,座標上的點,包含資訊如下 * 1.節點座標(x和y座標)、節點的值--節點類別(A為起點,B為終點,“o”表示可通節點,“%”表示牆壁,“#”代表障礙物,“*”代表演算法計算後的路徑) * 2.節點是否可到達(是否為障礙物)、父節點ANode * 3.A*演算法的核心概念F=G+H,從起始節點A開始,F當前節點走向終點B的期望結果值,G為當前節點走向起始節點A所需消耗的步數,假設移動步數只能上下左右移動 */ public class ANode implements Serializable { private Integer x; private Integer y; private NodeEnum value; private Double FValue; private Double GValue; private Double HValue; private Boolean reachable; private ANode parentNode; public ANode() { super(); } public ANode(Integer x, Integer y, NodeEnum value, Boolean reachable) { super(); this.x = x; this.y = y; this.value = value; this.reachable = reachable; } public Integer getX() { return x; } public void setX(Integer x) { this.x = x; } public Integer getY() { return y; } public void setY(Integer y) { this.y = y; } public NodeEnum getValue() { return value; } public void setValue(NodeEnum value) { this.value = value; } public Double getFValue() { return FValue; } public void setFValue(Double FValue) { this.FValue = FValue; } public Double getGValue() { return GValue; } public void setGValue(Double GValue) { this.GValue = GValue; } public Double getHValue() { return HValue; } public void setHValue(Double HValue) { this.HValue = HValue; } public Boolean getReachable() { return reachable; } public void setReachable(Boolean reachable) { this.reachable = reachable; } public ANode getParentNode() { return parentNode; } public void setParentNode(ANode parentNode) { this.parentNode = parentNode; } }
第二步,定義網格影象 AMAP類
import java.io.Serializable; /** * A*各個節點的ANode陣列集合, * 1.定義起始節點 * 2.初始化各個節點(包含節點的座標、類別等資訊) * 3.展示輸出所有節點資訊 */ public class AMap implements Serializable { public static final int weight = 7; public static final int height = 7; private ANode[][] nodes; private ANode startNode; private ANode endNode; public AMap() { nodes = new ANode[weight][height]; // 初始化節點資訊 全部設定為可通節點 for (int w = 0; w < weight; w++) { for (int h = 0; h < height; h++) { nodes[w][h] = new ANode(w, h, NodeEnum.ONODE, true); } } // 初始化weight牆壁節點 for (int d = 0; d < weight; d++) { nodes[d][0].setValue(NodeEnum.BNODE); nodes[d][0].setReachable(false); nodes[d][height-1].setValue(NodeEnum.BNODE); nodes[d][height-1].setReachable(false); } // 初始化height牆壁節點 for (int d = 0; d < height; d++) { nodes[0][d].setValue(NodeEnum.BNODE); nodes[0][d].setReachable(false); nodes[weight-1][d].setValue(NodeEnum.BNODE); nodes[weight-1][d].setReachable(false); } // 動態變動 初始化 起始節點 nodes[3][1].setValue(NodeEnum.STARTNODE); startNode = nodes[3][1]; nodes[3][5].setValue(NodeEnum.ENDNODE); endNode = nodes[3][5]; // 動態變動 初始化 障礙節點 for (int k = 1; k <= 3; k++) { nodes[k + 1][3].setValue(NodeEnum.JNODE); nodes[k + 1][3].setReachable(false); } showMap(); } // 輸出列印各個節點資訊 public void showMap() { System.out.println("運算前節點資訊如下:"); for (int i = 0; i < height; i++) { for (int j = 0; j < weight; j++) { System.out.print(nodes[j][i].getValue().getValue() + " "); } System.out.println(); } } public ANode[][] getNodes() { return nodes; } public void setNodes(ANode[][] nodes) { this.nodes = nodes; } public ANode getStartNode() { return startNode; } public void setStartNode(ANode startNode) { this.startNode = startNode; } public ANode getEndNode() { return endNode; } public void setEndNode(ANode endNode) { this.endNode = endNode; } }
第三步,具體實現A*演算法的解
import java.util.ArrayList; import java.util.Collections; /** * AStar類是用於A*的運算過程,其中包含: * 1.移動步驟時需儲存的“開啟列表”和“關閉列表” * 2.設定各節點的F、G、H的值,結合父節點計算出該結果 定義每一步的能量值為10 * 3.選中節點後將子節點新增到“開啟列表” * 4.將已走過節點新增到“關閉列表” * 5.根據A*演算法規則一次計算選出最優節點路徑 * 6.將標記出最佳路徑的結果進行展示 */ public class AStar { // 每一步所需消耗能量值 private final double energyValue = 10; // 每一步可行動步數 private final int step = 1; private final ArrayList<ANode> open = new ArrayList<>(); private final ArrayList<ANode> close = new ArrayList<>(); /** * 計算當前節點 H 的值 * H值作為理想狀態下到達終點的預估值,可根據不同情況設定不同的演算法規則 * 計算規則 為當前節點X和Y座標的差值之和再乘以能量值 不考慮障礙物是否存在 * * @param currentNode * @param endNode * @return */ public Double getHValue(ANode currentNode, ANode endNode){ return (Math.abs(currentNode.getX()-endNode.getX()) + Math.abs(currentNode.getY()-endNode.getY())) * energyValue; } /** * 計算出當前節點 G 的值 * 計算規則為如果沒有父節點說明是開始節點即G為0,如果不為空則獲取父節點的G+1*能量值 * 每次移動位置只能移動往上下左右移動step的步數 * * @param currentNode * @return */ public Double getGValue(ANode currentNode){ if (currentNode.getParentNode() == null){ return 0.0; } if (currentNode.getParentNode().getGValue() == null){ currentNode.getParentNode().setGValue(0.0); } return currentNode.getParentNode().getGValue() + step*energyValue; } /** * 獲取F值 : G + H * @param currentNode * @return */ public Double getFValue(ANode currentNode){ return currentNode.getGValue() + currentNode.getHValue(); } /** * 該函式的作用是 將當前節點周圍的節點新增到“開啟列表”中 * 新增規則為:當前節點的上下左右為可達節點,對角的節點為不可達 * 設定上下左右節點的父節點為當前節點,並設定F、G、H的值 * * @param node * @param map */ public void isOpen(ANode node ,AMap map){ int x = node.getX(); int y = node.getY(); // 設定上下左右節點的資訊,並且新增到開啟列表中 for (int i = 0; i < 2; i++) { int x1 = i == 0 ? x -1 : x + 1; int y1 = i == 0 ? y -1 : y + 1; setNodeInfo(node, map, x1, y); setNodeInfo(node, map, x, y1); } } /** * 設定周圍節點的節點資訊並新增到“開啟列表” 包含父節點、F G H的值, * 該節點為可達節點且不在“開啟列表”中 * @param node * @param map * @param x * @param y */ private void setNodeInfo(ANode node, AMap map, int x, int y) { if (map.getNodes()[x][y].getReachable() && !open.contains(map.getNodes()[x][y])){ // 設定父節點 map.getNodes()[x][y].setParentNode(node); // 設定 F G H 的值 map.getNodes()[x][y].setGValue(getGValue(map.getNodes()[x][y])); map.getNodes()[x][y].setHValue(getHValue(map.getNodes()[x][y], map.getEndNode())); map.getNodes()[x][y].setFValue(getFValue(map.getNodes()[x][y])); } } /** * 將該節點新增到“關閉列表” * 新增規則:首先判斷 開啟列表 是否存在該節點,存在則設定該節點為不可達和節點狀態, * 同時在開啟列表中刪除該節點並新增到關閉列表 * @param node */ public void isClose(ANode node){ if (open.contains(node)){ node.setReachable(false); open.remove(node); } } /** * 使用Collections.sort的Comparator比較器將“開啟列表”中的節點按F值從小到大排序 */ public void sortOpenList(){ Collections.sort(open, (n1, n2) -> { if (n1.getFValue() > n2.getFValue() || n1.getGValue() < n2.getGValue()){ return 1; } return -1; }); } /** * 從起始節點開始搜尋,每次步進為1耗能為10,根據F值來追尋下一個節點,直到找到結束節點 * 首先初始化起始節點的資訊,而後迴圈獲取下一個節點,最終找到結束節點 * */ public void startSearchPath(AMap map){ // 對初始節點進行操作,關聯周圍節點 isOpen(map.getStartNode(), map); isClose(map.getStartNode()); map.getStartNode().setReachable(false); map.getStartNode().setParentNode(map.getStartNode()); // 迴圈取下一節點,當結束節點包含 do { if (open.size() == 0){ break; } isOpen(open.get(0), map); isClose(open.get(0)); sortOpenList(); } while (open.contains(map.getEndNode())); // 設定搜尋最優結果路徑 setBestPathSign(map); // 當開啟列表中包含了結束節點則退出迴圈,清楚open中的結束節點 isClose(map.getEndNode()); // 展示尋找路徑的結果 showSearchPath(map); } private void setBestPathSign(AMap map) { ANode node = map.getEndNode(); while (true){ ANode tempNode = node.getParentNode(); if (tempNode == null || tempNode == map.getStartNode()){ break; } node = tempNode; tempNode.setValue(NodeEnum.XNODE); } } /** * 列印該Map中所有節點資訊(包含了日誌資訊) * @param map */ public void showSearchPath(AMap map) { System.out.println("運算後節點資訊如下:"); for (int i = 0; i < map.height; i++) { for (int j = 0; j < map.weight; j++) { System.out.print(map.getNodes()[j][i].getValue().getValue() + " "); } System.out.println(); } if (map.getEndNode().getParentNode() == null){ System.out.println("沒有結束節點資訊。"); } } }
以上就是A*演算法的具體實現啦!演算法已經再程式碼中說明的很清晰啦,具體就不再多說。程式碼略作修改,小夥伴們還是自己去編寫一遍吧,還是很好意思的。如果實在想要原始碼連線在此啦。程式碼
相關推薦
EasyLearn--JAVA實現32個經典演算法設計(一):A*演算法
A*演算法是一種靜態路網中求解最短路徑最有效的直接搜尋方法,其中經典的圖形有網格影象如下: 根據這個影象來對演算法進行說明主要思想:該演算法又稱為啟發式演算法,啟發之處在於公式F=G+H,F為最終結果值,G為所行走的步數,H就是預估值,其中H可根據不同的策略採用不同的規
如何用Java實現NLP的經典關鍵詞演算法 TF-IDF
面對一篇文章,我們如何提取他的關鍵詞呢。如果是我們自己去提取,那隻需要讀一遍,然後大腦中就會有一定的印象了,但是對於計算機來說,他沒有人那樣的思考能力啊,那怎麼辦,只能依靠演算法了。今天分享的內容呢是如何用Java語言實現NLP(自然語言處理)領域中一個非常著名
java實現兩個向量的相關係數演算法
有兩個向量V1和V2 V1={1:3,2:2,3:1,5:0},V2={1:3,3:1,4:2,5:0} 以表格的形式展現: 將向量V1和V2帶入相關係數公式並展開展開,結果為: n值(n = 4):從表格可以看出,向量V1和V2 的第五位元素上都是0,因此該位置
java 實現多個接口 方法重名的解決辦法——內部類
nehe run .get tar extend pac 接口 內部 java package com.kk.innerClass; /** * 通過內部類實現接口 * 解決多個接口中方法重名問題 * */interface Machine { void run(
java實現兩個int數交換
操作 使用 不用 col int 個數 span 定義 交換 普通方法,進階方法,大神方法 1 @Test 2 public void test3(){ 3 int m = 5; 4 int n = 12; 5
Java 實現32位MD5加密
https utf baidu static post AD pos byte tar MD5介紹【鏈接】 Java代碼實現 1 public class Md5Util { 2 private String Md5Util(String s) { 3
筆記:Java實現三個執行緒A B C,BC執行緒執行完再執行A線
final Lock lc = new ReentrantLock(); .. run() { lc.lock(); ... lc.unlock(); } 可能開啟方式不對吧,沒實現! 改用join() 可以實現(BC與A以單執行緒模式執行),程式碼如下: package
java實現多個檔案以壓縮包匯出到本地
描述:使用java將多個檔案同時壓縮為壓縮包,並匯出到本地 /** *壓縮檔案並匯出 */ public static void zipFiles() throws IOException { File file = null; String zipFileName = ""; File[
Java實現兩個有序的單項鍊表的合併
無意中看到一道題,如下: 現有兩個有序(升序)的單向連結串列,請編寫程式將這兩個連結串列合併成一個,並確保合併後的連結串列也是升序的 單向升序連結串列定義: public class ListNode { int val; ListNode next;
java實現多個執行緒達到一個闕伐值後一起執行
給大家推薦個靠譜的公眾號程式設計師探索之路,大家一起加油 1. CountDownLatch 1.1 簡介 CountDownLatch是一個同步輔助類,通過它可以完成類似於阻塞當前執行緒的功能,即:一個執行緒或多個執行緒一直等待,直到其他執行緒執行的操作完成。CountDownLatch用
java實現兩個有序連結串列合併為一個有序連結串列
節點類 public class Node { private Node next; private Integer number; Node(Integer number) { this.number=number; next=null; } Node() {
JAVA實現多個附件傳輸
需要引入以下jar包 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> &l
Java實現圖的深度和廣度優先遍歷演算法
<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/
演算法設計與分析P8演算法實現第一題
#include<stdio.h> #include<string.h> int main() { int n, t, i,temp; int count[10]; mem
Java實現兩個有序的連結串列合併
Java實現兩個有序的連結串列合併 先實現兩個有序連結串列 程式碼如下: SingleLinkedList sll1 = new SingleLinkedList(); for (int i = 0; i < 10; i += 2) {
java實現兩個矩陣乘法 有個錯誤希望有大佬幫忙
//java實現兩個矩陣相乘 有個錯誤在下邊 有沒有哪個大佬幫我看看 十分感謝 package 實驗五; import java.util.Scanner; public class Matrix { private int rows; private int cols;
C++實現兩個超大的字元數字相加的演算法的程式碼
如下資料是關於C++實現兩個超大的字元數字相加的演算法的程式碼。 #include <iostream> #include <string> #include <stack> using namespace std; void deleteLeadingZeros(st
8皇后以及N皇后演算法探究,回溯演算法的JAVA實現,遞迴方案(一)
八皇后問題,是一個古老而著名的問題,是回溯演算法的典型案例。該問題是國際西洋棋棋手馬克斯·貝瑟爾於1848年提出:在8×8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法。 高斯認為有76種方案。1854年在柏林的象棋雜誌
java實現兩個數值相除並保留指定精度
/** * @param v1 除數 * @param v2 被除數 * @param scale 小數點精度 * @return */ public static double
java實現多個字串排序
編寫應用程式,該類中有一個方法sort()(其原型為:void sort(String str[])),從命令列傳入多個字串,呼叫方法sort()對該字串陣列按字典順序從小到大排序。 程式碼如下: import java.util.*; public clas