一、前言公司的程式用的就是這個a*,剛開始將的明白,後面說的不咋明白啊,叫我控制步驟多少,我感覺這個是動態的怎麼控制步數多少呢?在這裡我將對a*演算法的實際應用進行一定的**,並且舉乙個有關a*演算法在最短路徑搜尋的例子。值得注意的是這裡並不對a*的基本的概念作介紹,如果你還對a*演算法不清楚的話,請看姊妹篇《初識a*演算法》。
這裡所舉的例子是參考amit主頁中的乙個源程式,使用這個源程式時,應該遵守一定的公約。
二、a*演算法的程式編寫原理
我在《初識a*演算法》中說過,a*演算法是最好優先演算法的一種。只是有一些約束條件而已。我們先來看看最好優先演算法是如何編寫的吧。
如圖有如下的狀態空間:(起始位置是a,目標位置是p,字母後的數字表示節點的估價值)
搜尋過程中設定兩個表:open和closed。open表儲存了所有已生成而未考察的節點,closed表中記錄已訪問過的節點。演算法中有一步是根據估價函式重排open表。這樣迴圈中的每一步只考慮open表中狀態最好的節點。具體搜尋過程如下:
1)初始狀態:
open=[a5];closed=;
2)估算a5,取得搜有子節點,並放入open表中;
open=[b4,c4,d6];closed=[a5]
3)估算b4,取得搜有子節點,並放入open表中;
open=[c4,e5,f5,d6];closed=[b4,a5]
4)估算c4;取得搜有子節點,並放入open表中;
open=[h3,g4,e5,f5,d6];closed=[c4,b4,a5]
5)估算h3,取得搜有子節點,並放入open表中;
open=[o2,p3,g4,e5,f5,d6];closed=[h3,c4,b4,a5]
6)估算o2,取得搜有子節點,並放入open表中;
open=[p3,g4,e5,f5,d6];closed=[o2,h3,c4,b4,a5]
7)估算p3,已得到解;
看了具體的過程,再看看偽程式吧。演算法的偽程式如下:
best_first_search()
for(每乙個x的子節點y)
//還沒有排序
else
if(y在open表中)
else
//y在close表中
}將x節點插入close表中;
按照估價值將open表中的節點排序;
}//end for
}//end while
}//end func
啊!偽程式出來了,寫乙個源程式應該不是問題了,依葫蘆畫瓢就可以。a*演算法的程式與此是一樣的,只要注意估價函式中的g(n)的h(n)約束條件就可以了。不清楚的可以看看《初識a*演算法》。好了,我們可以進入另乙個重要的話題,用a*演算法實現最短路徑的搜尋。在此之前你最好認真的理解前面的演算法。不清楚可以找我。我的email在文章尾。
三、用a*演算法實現最短路徑的搜尋
先複習一下,a*演算法的核心是估價函式f(n),它包括g(n)和h(n)兩部分。g(n)是已經走過的代價,h(n)是n到目標的估計代價。在這個例子中g(n)表示在狀態空間從起始節點到n節點的深度,h(n)表示n節點所在地圖的位置到目標位置的直線距離。啊!乙個是狀態空間,乙個是實際的地圖,不要搞錯了。再詳細點說,有乙個物體a,在地圖上的座標是(xa,ya),a所要到達的目標b的座標是(xb,yb)。則開始搜尋時,設定乙個起始節點1,生成八個子節點2- 9
因為有八個方向。如圖:
仔細看看節點1、
9、17的g(n)和h(n)是怎麼計算的。現在應該知道了下面程式中的f(n)是如何計算的吧。開始講解源程式了。其實這個程式是乙個很典型的教科書似的程式,也就是說只要你看懂了上面的偽程式,這個程式是十分容易理解的。不過他和上面的偽程式有一些的不同,我在後面會提出來。
先看搜尋主函式:
void astarpathfinder::findpath(int sx, int sy, int dx, int
dy) path =bestnode;
} 再看看生成子節點函式:
void astarpathfinder::generatesuccessors(node *bestnode, int dx, int
dy)
看看最重要的函式:
void astarpathfinder::generatesucc(node *bestnode,int x, int y, int dx, int
dy) }
else
//在closed表中嗎?
//if equal to null then not in open list, else it returns the node in old
if ( (old=checkclosed(tilenums)) !=null )
}//不在open表中也不在close表中
else
} 哈哈!a*演算法我懂了!當然,我希望你有這樣的感覺!不過我還要再說幾句。仔細看看這個程式,你會發現,這個程式和我前面說的偽程式有一些不同,在generatesucc函式中,當子節點在closed表中時,沒有將子節點從closed表中刪除並放入open表中。而是直接的重新的計算該節點的所有子節點的估價值(用propagatedown函式)。這樣可以快一些!另當子節點在open表和closed表中時,重新的計算估價值後,沒有重新的對open表中的節點排序,我有些想不通,為什麼不排呢?:-(,會不會是乙個小小的bug。你知道告訴我好嗎?
好了!主要的內容都講完了,還是完整仔細的看看源程式吧!希望我所的對你有一點幫助,一點點也可以。如果你對文章中的觀點有異議或有更好的解釋都告訴我。我的email在文章最後!
深入了解A
一 前言 在這裡我將對a 演算法的實際應用進行一定的 並且舉乙個有關a 演算法在最短路徑搜尋的例子。值得注意的是這裡並不對a 的基本的概念作介紹,如果你還對a 演算法不清楚的話,請看姊妹篇 初識a 演算法 這裡所舉的例子是參考amit主頁中的乙個源程式,使用這個源程式時,應該遵守一定的公約。二 a ...
深入了解Dojo Data
譯自http www.sitepen.com blog 2010 10 13 dive into dojo data 使用dojo data有助於快速建立web應用的介面,且易於嵌入各種資料來源。它在使用者介面與底層資料之間提供了一層抽象層,使得使用者介面開發人員能夠專注於ui的開發,而無需擔心資料...
深入了解CCtrlView
如果我們要將乙個控制項轉換成檢視類,我們一般會想到cctrlview,用它實現的控制項檢視一般新增乙個get ctrl函式,函式的作用是返回檢視中控制項的引用,如果在mfc程式中跟蹤它的呼叫我們會發現它的實現是這樣的 以cedit控制項為例 afxext inline cedit ceditview...