青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

C++新霖花園
3D園丁
posts - 7,comments - 14,trackbacks - 0
   對于開放列表的維護方案來說,前面我說的,都是一些小花樣了,在一些很小的地圖上用他們并沒有什么太大的問題,但是如果地圖很大,需要搜尋的格子很多,那么開放列表里的元素必然會很多,那么我們是否可以用另外一種思維來考慮一下開放列表的維護工作?
 
   其實我們每次從開放列表里面取值,每次只需要取里面所有元素的最小值就行了,而前面所說的兩種方案都有自己的優點,第一種不需要對開放列表做排序,但每次找起最小值來實在消耗很大,第2種在找最小值的時候只需取第一個元素就行,而麻煩在于需要一直維持開放列表里面所有元素的有序排列,那么我們是不是可以把這兩種方法的優點都結合起來呢

   當然,這種方法是有的,那就是很多高級A*程序更苛求速度的一種做法,利用Binary Heap數據結構,也就是二叉堆,來維護開放列表。

   其實有關二叉堆,相信了解他的高手很多,我就不再班門弄斧,,其實我也只是剛剛學習他而已,這里只簡單的介紹一下他的一些特點以及在A*中他所起到的作用。

   百度百科中對二叉堆的定義: 二叉堆是一種特殊的堆,二叉堆是完全二元樹或者是近似完全二元樹。二叉堆滿足堆特性:父結點的鍵值總是大于或等于任何一個子節點的鍵值。

   那么應用于A*的開放列表里,我們只要反過來,父結點的鍵值總是小于或等于任何一個子節點的鍵值,這樣就沒問題了。

   利用這種特性進行過排列的開放列表,那么我們可以保證,具有F值特性最小的那個元素,肯定是在這個二插樹的根節點,于是取值的時候,只要把根節點上的值取出來用就行了。(當然,取完以后還得維護開放列表的二叉堆特性,這點我下面會談),一般來說,二叉堆是利用數組來表示,那么正好,我所使用的vector結構便可以派上用場,二插堆的結構填往vector中的時候,利用的是一種類似前序遍歷的方式順序進入的,也就是按照 當前節點 -- 當前節點的左子節點 -- 當前節點的右子節點這樣的順序來放入vector中,如下圖


(此圖是借用了Panic所翻譯的《在A*尋路中使用二叉堆》一文中的圖片

不過根節點進入的時候不要放在0號元素上,vector可以隨便先放進一個沒有用的元素,我處理的時候是放了一個NULL型指針進去的,也就是說根節點所在的vector下標為1。而這樣的話對于這個vector中非0下標的任意一個元素,我們要找他的父節或者是子節點就很簡單了,遵循下面一個原則:
具備二叉堆特性的vector中下標為n(n!=0)的一個元素:
他的父節點下標 = n / 2;(小數去掉)    比如下標為9的元素,他的父節點下標就是4
他的左子節點下標 = n * 2;  右子節點下標 = n * 2 +1   比如下標為3的元素他的左子節點下標為6,右子節點下標為7

   對于我們的A*來說,在把元素放進開放列表里面的時候就需要按照二叉堆的添加步驟進行操作,而我們在把下標1的F值最小的元素取出來并且刪除掉以后,則需要把二叉堆重新維護下其二叉堆的特性,而在尋路過程中某個開放列表中元素的G值改變以后,我們則需要對這個開放列表再進行次維護,維持他的二叉堆特性。那么綜合以上,我們只需要3個功能函數,BinaryHeapAdd函數,BinaryHeapDelete函數,RetaxisBinaryHeap函數

BinaryHeapAdd函數,
1 把新的要進入開放列表的元素放進vector的末尾,也就是直接push_back進去 (這個新加進的元素為當前處理元素)
2 利用上面所說的父子節點下標關系,找到當前處理元素的父節點下標,然后比較兩個數,如果新的元素比他的父節點小,則把這個元素和他的父節點的位置互換一下,如果產生了互換行為,則針對新位置上的這個當前處理元素再次重復本次動作;
3 直到新的元素大于等于他的父節點,或者找到的父節點下標為0 ,則新元素的位置確定為找到,這個函數可以結束

void AStarBase::BinaryHeapAdd(POINTINFO* indexPoint)
{
    int tmpF = indexPoint->F;

    _openPoint.push_back(indexPoint);        //先把新的元素放在vector最后

    int theNewIndex = _openPoint.size()-1;   //新元素的下標
    while (true)
    {
        int theParentIndex = theNewIndex / 2;     //新元素當前所在位置的父節下標
        if (theParentIndex != 0)                  
        {
            if (_openPoint[theNewIndex]->F < _openPoint[theParentIndex]->F)   //新元素的F值比他的父節點值大
            {
                //與父節點的位置進行交換
                POINTINFO* tmpinfo = _openPoint[theParentIndex];
                _openPoint[theParentIndex] = _openPoint[theNewIndex];
                _openPoint[theNewIndex] = tmpinfo;

                _openPoint[theParentIndex]->openIndex = theParentIndex;
                _openPoint[theNewIndex]->openIndex = theNewIndex;

                theNewIndex = theParentIndex;   //置新節點的處理下標為換過位置以后的值
            }
            else
            {
                break;
            }
        }
        else                                    //如果父節下標計算出來為0,則停止查找位置
        {
            break;
        }
    }
}

BinaryHeapDelete函數
1 把開放列表中1號元素取出并放在最后返回出來使用

2 需要對開放列表進行一次2叉堆特性重新維護,首先把vector中最后一個元素移動到1號下標位置,(1號元素為當前處理元素)

3 對1號下標位置的當前處理元素利用父子節點下標計算關系找出他的左子節點和右子節點,然后把這個元素與他的左子節點元素的F值和右子節點的F值大小分別做比較,如果子節點的比他更小,則把他與子節點的位置進行互換,如果兩個子節點的值都比他小,則與較小的那個子節點進行位置互換,如果產生了互換行為,則針對新位置上的當前處理元素再次進行本次動作

4 如果子節點的值都大于或者等于當前處理元素的值,或者計算出來的子節點下標已經朝出了vector最大元素個數,則停止排序,函數可以返回原來存起來的最小值

AStarBase::POINTINFO* AStarBase::BinaryHeapDelete()
{
     if (_openPoint.size() <= 1)   //開放列表里面只剩下開始放進去的一個空的POINTINFO指針
     {
          return NULL;
     }

     //先把最后一個元素放到1號位置
     POINTINFO* tmpinfo = _openPoint[1];    //下標1位置的元素先存儲起來,函數結束的時候要return出去
     _openPoint[1] = _openPoint.back();    //把vector中的最后一個元素放到下標1位置
     _openPoint.pop_back();
     _openPoint[1]->openIndex = 1;

     int theSelectIndex = 1;       //要處理元素的下標值
     while (true)
     {
         int theLeftChildIndex = theSelectIndex * 2;               //左子節點下標值
         int theRightChildIndex    = theSelectIndex * 2 + 1;          //右子節點下標值
         if (theLeftChildIndex >= _openPoint.size())   //這個數沒有子節點,則停止排序
         {
             break;                                   
         }
         else if ( theLeftChildIndex == (_openPoint.size() -1)) //左子節點正好是vector中最后一個元素,即只有左子節點,沒有右子節點
         {
             if (_openPoint[theSelectIndex]->F > _openPoint[theLeftChildIndex]->F)   //如果父節點的F值比左子節點更大
             {
                 //交換
                 POINTINFO* tmptmpinfo = _openPoint[theLeftChildIndex];
                 _openPoint[theLeftChildIndex] = _openPoint[theSelectIndex];
                 _openPoint[theSelectIndex] = tmptmpinfo;

                 _openPoint[theLeftChildIndex]->openIndex = theLeftChildIndex;
                 _openPoint[theSelectIndex]->openIndex = theSelectIndex;

                 theSelectIndex = theLeftChildIndex;
             }
             else  //如果小,則停止排序
             {
                 break;
             }
         }
         else if (theRightChildIndex < _openPoint.size())  //既有左子節點又有右子節點
         {
             if (_openPoint[theLeftChildIndex]->F <= _openPoint[theRightChildIndex]->F )   //左右子節點先互相比較 左邊的小
             {
                 if (_openPoint[theSelectIndex]->F > _openPoint[theLeftChildIndex]->F)      //處理的父節點F值比左子節點大
                 {
                     //交換(與左子節點)
                     POINTINFO* tmptmpinfo = _openPoint[theLeftChildIndex];
                     _openPoint[theLeftChildIndex] = _openPoint[theSelectIndex];
                     _openPoint[theSelectIndex] = tmptmpinfo;     

                     _openPoint[theLeftChildIndex]->openIndex = theLeftChildIndex;
                     _openPoint[theSelectIndex]->openIndex = theSelectIndex;
              
                     theSelectIndex = theLeftChildIndex;
                 }
                 else
                 {
                     break;
                 }
             }
             else     //右邊的比較小
             {
                 if (_openPoint[theSelectIndex]->F > _openPoint[theRightChildIndex]->F)      //處理的F值比右子節點大
                 {
                     //交換(與右子節點)
                     POINTINFO* tmptmpinfo = _openPoint[theRightChildIndex];
                     _openPoint[theRightChildIndex] = _openPoint[theSelectIndex];
                     _openPoint[theSelectIndex] = tmptmpinfo;

                     _openPoint[theRightChildIndex]->openIndex = theRightChildIndex;
                     _openPoint[theSelectIndex]->openIndex = theSelectIndex;
   
                     theSelectIndex = theRightChildIndex;
                 }
                 else
                 {
                     break;
                 }    
             }
         }

     }
     return tmpinfo;
}

大家可以看到,上面的兩個函數所做的添加和刪除操作,可以保證開放列表里,1號位置的元素的F值肯定是最小的,而其他地方的大小位置關系,我們可以不需要理會,我們只要保持一個原則,2叉堆里的父節點元素F值不能比子節點大,就可以了

而尋路過程中由于F值重計算而導致的重排序,其實和添加操作的原理是一樣的,我們只需要把那個改過F值的元素,把他和他的父節點的F值進行比較,如果改過的值小,則互換,如果并不小或者沒有了父節點,則停止
void AStarBase::RetaxisBinaryHeap(int index)
{
    int theNewIndex = index;   //當前處理的下標
    while (true)
    {
        int theParentIndex = theNewIndex / 2;     //當前處理節點的父節點下標值
        if (theParentIndex != 0)
        {
            if (_openPoint[theNewIndex]->F < _openPoint[theParentIndex]->F)   //新進來的F值比他的父節點值大
            {
                //進行交換
                POINTINFO* tmpinfo = _openPoint[theParentIndex];
                _openPoint[theParentIndex] = _openPoint[theNewIndex];
                _openPoint[theNewIndex] = tmpinfo;

                _openPoint[theParentIndex]->openIndex = theParentIndex;
                _openPoint[theNewIndex]->openIndex = theNewIndex;

                theNewIndex = theParentIndex;
            }
            else
            {
                break;
            }
        }
        else
        {
            break;
        }
    }
}

利用上面3個操作函數所算出來的尋路結果,與一開始使用在無序開放列表里每次利用比較法找出最小F值所得到的結果是一樣的,
POINT(2,2)尋路到 POINT(398,398)



好吧,其實我們用他的目的是什么?就是要看看他消耗的速度而已,讓我們來看一下性能分析表


大家可以看到,在整個程序中這3個函數所消耗的時間為 0.963394 + 0.437735 + 0.271655 = 1.672784毫秒,是無序找最小值方法所使用時間的十分之一左右,是使用正常一些全排序方法消耗速度的六分之一左右,這還是在路徑非常簡單的情況下,而一旦障礙更多,路徑更復雜,開放列表里的元素更多的時候,Binary Heap方法能體現他更大的速度優勢

以上代碼沒有經過任何優化工作,僅僅是實現了下二叉堆的功能,各位將就著看了 ^O^

如果對A*尋路基礎算法原理不清楚并且有興趣的朋友,可以去gameres上看一下這篇文章
http://data.gameres.com/message.asp?TopicID=25439

  
posted on 2008-03-11 11:48 火夜風舞 閱讀(3171) 評論(0)  編輯 收藏 引用
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国模精品一区二区三区色天香 | 亚洲精品偷拍| 另类天堂视频在线观看| 欧美专区亚洲专区| 亚洲第一视频网站| 99精品99| 狠狠久久五月精品中文字幕| 欧美国产在线电影| 欧美视频一区在线观看| 久久久99爱| 欧美精品在线视频观看| 欧美中文在线免费| 欧美成年网站| 香蕉成人伊视频在线观看| 久久精品亚洲精品| 99视频精品免费观看| 午夜久久久久久| 亚洲欧洲视频在线| 亚洲制服欧美中文字幕中文字幕| 久久国产99| 亚洲精品1区2区| 日韩视频永久免费| 国产一区二区av| 亚洲欧洲日本国产| 国产一区99| 亚洲毛片在线观看.| 国内久久视频| 99v久久综合狠狠综合久久| 国产日韩欧美精品在线| 亚洲精品一二区| 一区在线免费| 亚洲欧美福利一区二区| 亚洲免费观看在线视频| 久久福利影视| 亚洲一区二区在线免费观看视频| 久久艳片www.17c.com| 亚洲欧美亚洲| 欧美日韩国产三级| 欧美成人dvd在线视频| 国产精品一区二区在线观看网站 | 欧美精品二区| 美女国产一区| 国产精品羞羞答答xxdd| 亚洲精品女av网站| 国内外成人免费视频| 亚洲深爱激情| 亚洲一区国产| 欧美性jizz18性欧美| 亚洲欧洲在线一区| 91久久久在线| 麻豆九一精品爱看视频在线观看免费 | 欧美日本久久| 亚洲精品视频免费观看| 亚洲国产综合视频在线观看| 午夜伦理片一区| 欧美在线看片| 国产一级精品aaaaa看| 亚洲视频一区二区| 亚洲欧美在线播放| 国产精品亚洲人在线观看| 99re热精品| 亚洲女同在线| 国产日韩欧美一区二区三区在线观看 | 亚洲国产欧美日韩另类综合| 久久久国产精品亚洲一区 | 欧美一区二区视频在线观看2020| 欧美亚洲免费电影| 国产欧美日本一区二区三区| 亚洲欧美日韩国产一区二区三区| 性欧美8khd高清极品| 国产日韩欧美在线看| 亚洲国产导航| 亚洲久久成人| 亚洲在线观看免费视频| 欧美无乱码久久久免费午夜一区| 一本色道久久综合亚洲精品按摩| 亚洲一区二区三区精品视频| 欧美午夜女人视频在线| 亚洲欧美在线另类| 欧美xx69| 亚洲午夜激情免费视频| 国产精品一区2区| 久久精品视频在线| 最新国产の精品合集bt伙计| 亚洲一区www| 国内久久精品视频| 欧美日韩伦理在线免费| 午夜亚洲性色视频| 亚洲成色777777在线观看影院| 99re6热只有精品免费观看| 国产精品久久夜| 久久久欧美一区二区| 亚洲精品视频在线播放| 久久精品国产综合精品| 亚洲人成在线免费观看| 国产精品美女久久久| 狂野欧美一区| 亚洲天堂av图片| 免费视频一区| 欧美影院成人| 亚洲精品欧美日韩| 国内精品嫩模av私拍在线观看| 免费成人av| 欧美一区二区三区视频免费播放| 亚洲成色精品| 久久久综合视频| 亚洲欧美久久久| 亚洲精品国久久99热| 国产午夜精品麻豆| 欧美午夜电影一区| 欧美激情亚洲| 久久综合国产精品台湾中文娱乐网| 亚洲视屏一区| 日韩一二三区视频| 欧美成人午夜| 久久人体大胆视频| 欧美专区亚洲专区| 亚洲综合国产| 一本高清dvd不卡在线观看| 亚洲国产精品成人久久综合一区 | 久久色在线观看| 亚洲欧美一区二区三区极速播放| 亚洲精选久久| 亚洲激情影视| 欧美国产日本在线| 免费观看不卡av| 久久久人成影片一区二区三区观看| 亚洲女性裸体视频| 亚洲欧美日本在线| 午夜精品久久久久久久99水蜜桃| 国产精品99久久久久久www| 亚洲激情在线| 亚洲日本成人| 亚洲日本免费电影| 亚洲人成在线观看网站高清| 亚洲欧洲一二三| 日韩午夜激情av| 一区二区三欧美| 亚洲午夜在线观看| 亚洲午夜久久久久久久久电影院| 一本色道久久综合亚洲精品不| 亚洲美女精品久久| 一级成人国产| 亚洲欧美另类中文字幕| 欧美亚洲一区| 久久精品亚洲精品| 另类综合日韩欧美亚洲| 欧美日韩一区二区在线播放| 欧美激情麻豆| 欧美日韩精品一本二本三本| 欧美美女bb生活片| 欧美日韩亚洲一区在线观看| 欧美日韩在线免费观看| 国产精品一二三| 精品成人久久| 亚洲精品在线免费| 亚洲一区二区视频| 欧美在线影院| 亚洲第一中文字幕| 99精品视频免费全部在线| 亚洲一区二区三区欧美| 欧美在线日韩| 欧美激情精品久久久久久变态| 欧美日韩在线观看一区二区| 国产毛片精品视频| 亚洲国产岛国毛片在线| 一区二区三区精品视频| 午夜精品久久99蜜桃的功能介绍| 久久国产精品99国产| 欧美va亚洲va国产综合| 99国产精品久久久久久久| 欧美综合国产| 欧美视频在线播放| 伊人伊人伊人久久| 亚洲欧美国产毛片在线| 欧美jjzz| 亚洲在线视频一区| 久久综合网色—综合色88| 欧美日韩中文在线| 亚洲国产91色在线| 午夜影院日韩| 亚洲国产aⅴ天堂久久| 午夜激情亚洲| 欧美日韩精品免费观看视频| 国产在线不卡视频| 正在播放日韩| 欧美电影专区| 欧美一区二区三区免费视频| 欧美日韩国产二区| 在线欧美福利| 久久婷婷成人综合色| 99热在线精品观看| 欧美激情欧美激情在线五月| 国产午夜精品在线观看| 亚洲一区二区日本| 亚洲欧洲精品一区二区三区波多野1战4| 欧美亚洲在线观看| 国产精品伦理| 亚洲免费在线观看| 99热这里只有成人精品国产|