算法-排序(2)锦标赛排序

用完全二叉树定义胜者树,前n-1个结点t[1]~t[n-1]为内部结点(胜者),后n个结点e[1]~e[n]是参赛者

t数组存的是参赛者编号,即e[t[0]]才是最终胜者的值

template <class T>
class WinnerTree{
public:
    const T maxValue=9999;
    WinnerTree(int TreeSize=20):maxSize(TreeSize),n(0){t=new int[TreeSize];}
    ~WinnerTree(){delete []t;}
    bool Initial(T a[],int size,int (*Winner)(int a,int b));
    bool rePlay(int i,int(*Winner)(int a,int b));
    void Updata(){e[t[1]]=maxValue;}   //t[1]并没有改变
    int Winner()const{return(n!=0)?t[1]:0;}
    int Winner(int i)const{return(i<n)?t[i]:0;}
    int Winner(int a,int b){return(e[a]<e[b])?a:b;}
private:
    int maxSize;  //允许最大选手数
    int n;        //当前大小(外部结点数)
    int lowExt;   //最远层外部结点数
    int offset;   //按深度满结点数(加1即为第1个外部结点)
    int *t;       //胜者树数组
    T *e;         //选手数组
    void Play(int k,int lc,int rc,int(*Winner)(int a,int b));
};

template <class T>
bool WinnerTree<T>::Initial(T *a, int size, int (*Winner)(int a, int b)) {
    if(size>maxSize || size<2) return false;
    n=size;e=a;
    int i,s;
    for(s=1; 2*s<=n-1; s+=s);  //s为最远端最左侧内结点编号
    lowExt=2*(n-s);   //最远层外部结点个数lowExit等于最远层内部结点数两倍
    offset=2*s-1;
    for(i=2; i<=lowExt; i+=2)
        Play((offset+i)/2,i-1,i,Winner);  //比较第i-1和第i个选手
    if(n%2==0) i=lowExt+2;
    else{
        Play(n/2,t[n-1],lowExt+1,Winner);  //当n为奇数时,最后一个内部结点指向的外部结点需要和次远层第一个外部结点比赛
        i=lowExt+3;
    }
    for(;i<=n;i+=2)
        Play((i-lowExt+n-1)/2,i-1,i,Winner);
    return true;
}

template <class T>
void WinnerTree<T>::Play(int k, int lc, int rc, int (*Winner)(int a, int b)) {
    t[k]=Winner(lc,rc);
    while(k>1 && k%2!=0){  //从右子女处向上比赛,直到根;如果不是右结点就不比了
        t[k/2]=Winner(t[k-1],t[k]);
        k/=2;  //到父结点
    }
}

template <class T>
bool WinnerTree<T>::rePlay(int i, int (*Winner)(int a, int b)) {
    if(i<=0 || i>n) return false;
    int k,lc,rc;
    if(i<=lowExt){   //被选中结点是最远层外部结点
        k=(offset+i)/2;    //i的父结点
        lc=2*k-offset;rc=lc+1; //父结点的左右子女
    }
    else{    //被选中结点是次远层外部结点
        k=(i-lowExt+n-1)/2;
        if(2*k==n-1){lc=t[2*k];rc=i;}    //被选中结点的左兄弟是最后一个内部结点
        else{lc=2*k-n+1+lowExt;rc=lc+1;}
    }
    t[k]=Winner(lc,rc);
    k/=2;
    for(; k>=1; k/=2)
        t[k]=Winner(t[2*k],t[2*k+1]);
}

template <class T>
void TournamentSort(T a[],const int left,const int right){  //建立胜者树WT,把a[]中元素复制到胜者树中并排序,并把结果送回a[]
    int size=right-left+1;
    WinnerTree<T> WT(size);   //因为t[0]没用上,所以size-1是不够的
    T data[size];    //书上这里是size+1
    int i;
    for(i=1; i<=size; i++) a[i+left-1]>>data[i];
    WT.Initial(data,size,Winner);
    for(i=1; i<=size; i++){
        a[i+left-1]=WT.Winner();
        WT.Updata();
        WT.rePlay(t[1],Winner);   //本来想把WT.t[1]改成a[i+left-1],后来想到其实不用改
        if(WT.Winner()==maxValue) break;
    }
    
}
//最后a[]中貌似只是个1~size的序列,不是原数值的排列
原文地址:https://www.cnblogs.com/yangyuliufeng/p/10720113.html