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

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

   當(dāng)然,這種方法是有的,那就是很多高級(jí)A*程序更苛求速度的一種做法,利用Binary Heap數(shù)據(jù)結(jié)構(gòu),也就是二叉堆,來維護(hù)開放列表。

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

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

   那么應(yīng)用于A*的開放列表里,我們只要反過來,父結(jié)點(diǎn)的鍵值總是小于或等于任何一個(gè)子節(jié)點(diǎn)的鍵值,這樣就沒問題了。

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


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

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

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

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

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

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

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

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

                theNewIndex = theParentIndex;   //置新節(jié)點(diǎn)的處理下標(biāo)為換過位置以后的值
            }
            else
            {
                break;
            }
        }
        else                                    //如果父節(jié)下標(biāo)計(jì)算出來為0,則停止查找位置
        {
            break;
        }
    }
}

BinaryHeapDelete函數(shù)
1 把開放列表中1號(hào)元素取出并放在最后返回出來使用

2 需要對(duì)開放列表進(jìn)行一次2叉堆特性重新維護(hù),首先把vector中最后一個(gè)元素移動(dòng)到1號(hào)下標(biāo)位置,(1號(hào)元素為當(dāng)前處理元素)

3 對(duì)1號(hào)下標(biāo)位置的當(dāng)前處理元素利用父子節(jié)點(diǎn)下標(biāo)計(jì)算關(guān)系找出他的左子節(jié)點(diǎn)和右子節(jié)點(diǎn),然后把這個(gè)元素與他的左子節(jié)點(diǎn)元素的F值和右子節(jié)點(diǎn)的F值大小分別做比較,如果子節(jié)點(diǎn)的比他更小,則把他與子節(jié)點(diǎn)的位置進(jìn)行互換,如果兩個(gè)子節(jié)點(diǎn)的值都比他小,則與較小的那個(gè)子節(jié)點(diǎn)進(jìn)行位置互換,如果產(chǎn)生了互換行為,則針對(duì)新位置上的當(dāng)前處理元素再次進(jìn)行本次動(dòng)作

4 如果子節(jié)點(diǎn)的值都大于或者等于當(dāng)前處理元素的值,或者計(jì)算出來的子節(jié)點(diǎn)下標(biāo)已經(jīng)朝出了vector最大元素個(gè)數(shù),則停止排序,函數(shù)可以返回原來存起來的最小值

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

     //先把最后一個(gè)元素放到1號(hào)位置
     POINTINFO* tmpinfo = _openPoint[1];    //下標(biāo)1位置的元素先存儲(chǔ)起來,函數(shù)結(jié)束的時(shí)候要return出去
     _openPoint[1] = _openPoint.back();    //把vector中的最后一個(gè)元素放到下標(biāo)1位置
     _openPoint.pop_back();
     _openPoint[1]->openIndex = 1;

     int theSelectIndex = 1;       //要處理元素的下標(biāo)值
     while (true)
     {
         int theLeftChildIndex = theSelectIndex * 2;               //左子節(jié)點(diǎn)下標(biāo)值
         int theRightChildIndex    = theSelectIndex * 2 + 1;          //右子節(jié)點(diǎn)下標(biāo)值
         if (theLeftChildIndex >= _openPoint.size())   //這個(gè)數(shù)沒有子節(jié)點(diǎn),則停止排序
         {
             break;                                   
         }
         else if ( theLeftChildIndex == (_openPoint.size() -1)) //左子節(jié)點(diǎn)正好是vector中最后一個(gè)元素,即只有左子節(jié)點(diǎn),沒有右子節(jié)點(diǎn)
         {
             if (_openPoint[theSelectIndex]->F > _openPoint[theLeftChildIndex]->F)   //如果父節(jié)點(diǎn)的F值比左子節(jié)點(diǎn)更大
             {
                 //交換
                 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())  //既有左子節(jié)點(diǎn)又有右子節(jié)點(diǎn)
         {
             if (_openPoint[theLeftChildIndex]->F <= _openPoint[theRightChildIndex]->F )   //左右子節(jié)點(diǎn)先互相比較 左邊的小
             {
                 if (_openPoint[theSelectIndex]->F > _openPoint[theLeftChildIndex]->F)      //處理的父節(jié)點(diǎn)F值比左子節(jié)點(diǎn)大
                 {
                     //交換(與左子節(jié)點(diǎn))
                     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值比右子節(jié)點(diǎn)大
                 {
                     //交換(與右子節(jié)點(diǎn))
                     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;
}

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

而尋路過程中由于F值重計(jì)算而導(dǎo)致的重排序,其實(shí)和添加操作的原理是一樣的,我們只需要把那個(gè)改過F值的元素,把他和他的父節(jié)點(diǎn)的F值進(jìn)行比較,如果改過的值小,則互換,如果并不小或者沒有了父節(jié)點(diǎn),則停止
void AStarBase::RetaxisBinaryHeap(int index)
{
    int theNewIndex = index;   //當(dāng)前處理的下標(biāo)
    while (true)
    {
        int theParentIndex = theNewIndex / 2;     //當(dāng)前處理節(jié)點(diǎn)的父節(jié)點(diǎn)下標(biāo)值
        if (theParentIndex != 0)
        {
            if (_openPoint[theNewIndex]->F < _openPoint[theParentIndex]->F)   //新進(jìn)來的F值比他的父節(jié)點(diǎn)值大
            {
                //進(jìn)行交換
                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個(gè)操作函數(shù)所算出來的尋路結(jié)果,與一開始使用在無序開放列表里每次利用比較法找出最小F值所得到的結(jié)果是一樣的,
POINT(2,2)尋路到 POINT(398,398)



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


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

以上代碼沒有經(jīng)過任何優(yōu)化工作,僅僅是實(shí)現(xiàn)了下二叉堆的功能,各位將就著看了 ^O^

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

  
posted on 2008-03-11 11:48 火夜風(fēng)舞 閱讀(3171) 評(píng)論(0)  編輯 收藏 引用

只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            葵司免费一区二区三区四区五区| 久久天堂成人| 麻豆freexxxx性91精品| 久久久www成人免费精品| 国产视频欧美视频| 欧美刺激性大交免费视频| 欧美日韩1080p| 久久国产精品99国产精| 欧美不卡视频一区发布| 午夜精品久久久久久久99水蜜桃| 午夜精品视频在线观看一区二区| 在线看片第一页欧美| 亚洲六月丁香色婷婷综合久久| 国产一区在线播放| 最新成人在线| 国精品一区二区| 一区二区三区四区五区精品| 激情一区二区| 欧美一区三区三区高中清蜜桃| 日韩性生活视频| 久久久噜噜噜久久中文字幕色伊伊| 亚洲综合日韩| 亚洲国产精品va| 欧美电影免费观看大全| 久久免费视频一区| 国产精品专区h在线观看| 这里是久久伊人| 一区二区欧美激情| 欧美激情在线狂野欧美精品| 欧美日韩国产美| 在线亚洲一区观看| 亚洲欧美中日韩| 国产欧美精品va在线观看| 亚洲午夜免费福利视频| 日韩一级黄色片| 欧美日韩视频在线| 99视频在线精品国自产拍免费观看| 在线欧美福利| 欧美极品色图| 亚洲影视综合| 国产自产女人91一区在线观看| 久久国产精品高清| 亚洲精品久久久久中文字幕欢迎你| 亚洲视频一二三| 狠狠色噜噜狠狠色综合久| 麻豆成人在线| 99精品热视频只有精品10| 欧美一级专区| 亚洲精品一区二区三区蜜桃久| 欧美区二区三区| 久久激情视频免费观看| 亚洲国产高清自拍| 久久精品午夜| 亚洲天堂网在线观看| 伊人成人在线视频| 国产精品美女在线| 欧美激情一区在线观看| 久久久xxx| 亚洲在线不卡| 亚洲欧美日韩精品久久久| 一区二区三区在线高清| 国产精品成人免费| 欧美精品www| 免费观看成人www动漫视频| 欧美一区二区三区四区在线 | 欧美a级一区| 亚洲综合激情| 亚洲欧美综合| 亚洲欧美日韩国产| 亚洲视频一区在线| 亚洲视频精品在线| 中日韩美女免费视频网址在线观看| 亚洲国产精品v| 亚洲另类春色国产| 日韩一区二区免费高清| 亚洲精品字幕| 午夜精品av| 久久婷婷综合激情| 亚洲黄色影片| 午夜精品久久久久| 久久婷婷麻豆| 欧美日韩精品综合| 国产日韩欧美a| 亚洲激情成人| 午夜精品视频在线| 免费中文字幕日韩欧美| 日韩午夜免费视频| 久久综合色播五月| 国产九区一区在线| 亚洲国产一区二区三区高清| 亚洲香蕉成视频在线观看 | 久久国产欧美精品| 99热这里只有精品8| 亚洲电影第三页| 国产精品99久久久久久久久久久久| 小黄鸭精品aⅴ导航网站入口| 欧美成人黑人xx视频免费观看| 欧美久久久久久久久久| 久久综合久久美利坚合众国| 91久久精品国产91性色tv| 一区二区三区色| 亚洲精品1区2区| 久久精品伊人| 国产精品一页| 午夜国产精品视频免费体验区| 欧美xart系列高清| 欧美一级大片在线观看| 国产精品视频你懂的| 中文精品视频一区二区在线观看| 亚洲国产精品视频一区| 久久久久久午夜| 一区二区三区在线免费视频| 亚洲一二三区精品| 亚洲一区不卡| 国产精品自拍在线| 久久精品夜色噜噜亚洲aⅴ| 亚洲视频视频在线| 国产自产精品| 麻豆国产精品777777在线| 久久国产精品亚洲va麻豆| 国产一区二区三区直播精品电影| 久久久精品2019中文字幕神马| 亚洲亚洲精品三区日韩精品在线视频| 国产精品久久久久久影院8一贰佰| 宅男精品导航| 久久久久这里只有精品| 99精品国产99久久久久久福利| 亚洲精品欧美日韩| 国产精品一区二区三区四区五区| 另类激情亚洲| 国产精品久久久久久久久久久久久 | 午夜久久资源| 激情综合网激情| 一本久久a久久精品亚洲| 国产女主播一区二区三区| 久久视频国产精品免费视频在线| 免费中文字幕日韩欧美| 先锋亚洲精品| 欧美屁股在线| 在线观看国产欧美| 亚洲精品乱码久久久久久蜜桃麻豆 | 久久婷婷久久一区二区三区| 欧美精品123区| 免费在线看一区| 韩日在线一区| 午夜精品一区二区三区在线播放| 日韩网站在线观看| 欧美成人精品激情在线观看| 久久亚洲综合网| 国产色产综合产在线视频| 亚洲肉体裸体xxxx137| 亚洲高清免费在线| 久久精品亚洲精品国产欧美kt∨| 中日韩高清电影网| 欧美午夜精品久久久久久超碰| 亚洲高清久久网| 亚洲免费观看视频| 欧美另类极品videosbest最新版本| 欧美阿v一级看视频| 亚洲激情二区| 欧美激情第1页| 亚洲一区二区精品在线观看| 亚洲女女女同性video| 国产精品视频久久一区| 亚洲一区二区毛片| 久久国产精品72免费观看| 国产一区二区三区在线观看免费 | 最新亚洲一区| 亚洲一区二区黄色| 国产九九精品视频| 久久人人爽人人爽| 亚洲黄页一区| 久久九九精品| 99v久久综合狠狠综合久久| 国产精品二区在线| 久久免费国产精品| 亚洲视频一起| 亚洲国产视频一区二区| 久久国产高清| 亚洲一区二区三区三| 狠狠色综合色区| 国产欧美日韩精品在线| 久久亚洲国产成人| 亚洲一区国产精品| 亚洲精品一二三区| 激情成人在线视频| 国产精品免费一区豆花| 欧美国产精品久久| 久久综合免费视频影院| 欧美在线精品免播放器视频| 99国产麻豆精品| 亚洲精品一区二区三| 欧美激情欧美激情在线五月| 久久九九国产| 久久婷婷成人综合色| 性久久久久久久久| 欧美一级专区免费大片| 亚洲欧美日韩一区二区在线| 亚洲欧美日韩视频一区| 性色一区二区三区|