[算法]敗者樹


  勝者樹和敗者樹都是完全二叉樹,是樹形選擇排序的一種變型。每個葉子結點相當於一個選手,每個中間結點相當於一場比賽,每一層相當於一輪比賽。
  不同的是,勝者樹的中間結點記錄的是勝者的標號;而敗者樹的中間結點記錄的敗者的標號
  勝者樹與敗者樹可以在log(n)的時間內找到最值。任何一個葉子結點的值改變后,利用中間結點的信息,還是能夠快速地找到最值。在k路歸並排序中經常用到。

  葉子節點相當於參賽選手,中間節點是比賽,比賽中敗者記錄在中間節點,勝者繼續參加后面的比賽,直到根節點。根節點之上的一個節點用來記錄最終勝者。

  敗者樹的建立:在參賽者數組b[]的最后添加一位,存放一個參賽選手的絕對最小值(選手都是正數的話,如-1)。所有中間節點都記錄這個最小值的下標。然后依次調整(adjust())各個選手即可。

  敗者樹的調整:當改變一個選手的值,需要調整以維持敗者樹的形態。敗者樹只需調整選手的父節點即可。當子節點的值大於父節點,則子節點記錄於父節點(小為勝利,記錄敗者),父節點繼續與其父節點比賽;若子節點小於父節點,則直接使用子節點進行下一輪比賽。

#define LEN 5//敗者樹容量,多路歸並數目
#define MIN -1//所有數據的可能最小值

int ls[LEN+1];//敗者樹,ls[0]存放勝者,其余存放敗者
int buf[LEN+1];//存放多路歸並的頭元素值,多出來的一位放MIN

void adjust(int s,int *buf){//s是需要調整的buf的下標
    int t=(s+LEN)/2;//得到s的在敗者樹上面的父節點
    while(t>0){//不斷與父節點對比,直到敗者樹的根節點
        if(buf[s]>buf[ls[t]]){//如果當前節點s(勝者)大於父節點
            ls[t]^=s;//交換ls[t]和s
            s^=ls[t];//s記錄勝者
            ls[t]^=s;//父節點記錄敗者
        }
        t/=2;//得到敗者樹的上一個父節點,繼續與當前勝者s比較
    }
    ls[0]=s;//最終的勝者記錄於ls[0]
}

void build(int *buf){
    buf[LEN]=MIN;//最后一位放MIN
    for(int i=0;i<LEN+1;++i)
        ls[i]=LEN;//所有敗者樹初始化為MIN的下標
    for(i=0;i<LEN;++i)
        adjust(i,buf);//依次調整即可完成初始化
}

int main()
{
    //初始buf
    int tmp[5]={18,21,16,11,19};
    memcpy(buf,tmp,LEN*sizeof(int));
    build(buf);
    cout<<buf[ls[0]]<<endl;//輸出11

    //取出11后,buf[3]=17
    int tmp1[5]={18,21,16,17,19};
    memcpy(buf,tmp1,LEN*sizeof(int));
    adjust(3,buf);
    cout<<buf[ls[0]]<<endl;//輸出16

    return 0;
}

 用最小堆也可以,兩者都可以在log2(n)時間內找出最小值,數據大時敗者樹稍微快一點

標題:班門弄斧,發一篇自己寫的算法分析文章(續)

發信站:水木社區(SatSep218:12:162006),站內

昨晚睡覺之前,還在想堆和敗者樹到底哪一個更優的題目。終極通過心算得出答案(感愛好的人可以算一下,並不難):假如將N個數的分布看作是完全隨機分布,則通過求和可以計算出,當從N個數中提取出一個新的數m時,假如該數比之前找到的n個最大的數中的最小的x大,則會替換x進進“堆”或者“敗者樹”。

在這一次重新維護堆和敗者樹的時候,堆的期看比較次數是2logn-1,而敗者樹是logn。但是由於敗者樹內部節點存放的是葉子節點的下標,在進行比較的時候需要間接取值(先訪問內部節點得到下標,在用此下標取到葉子節點中存放的數),所以比較時敗者樹訪問內存次數是堆的兩倍。

而在交換次數上(堆是父節點和子節點交換,敗者樹是往上走的優越者和內部節點存放的敗者進行交換,每次交換需要三次操縱),堆的交換次數期看值是1/2logn-1/4,而敗者樹是1/2logn(這里全都忽略了logn的取整題目)。

我不能確定到底一次比較和一次內存訪問到底哪一個更快,我猜想是內存訪問更快,那樣的話,敗者樹的比較性能會比堆更優。而在交換方面,到底那1/4的差會有多大影響,我也不好說了。

看來除非做實驗,很難分出堆和敗者樹的高下了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM