第十三章 赢/输者树(选择树,决策树

 赢者树总 :

   C++(数据结构与算法):45---竞赛树/选择树(赢者树、输者树)_董哥的黑板报-CSDN博客    

//
//  main.cpp
//  winner
//
//  Created by 🐻先生 on 2021/11/21.
//

#include<iostream>
#include<queue>
using namespace std;
 
template<class T>
class winnerTree
{
public:
    virtual ~winnerTree() {}
 
    //用数组thePlayer[1:numberOfPlayers]生成赢者树
    virtual void initialize(T *thePlayer, int theNumberOfPlayers) = 0;
 
    //返回赢者的索引
    virtual int winner()const = 0;
 
    //在参赛者thePLayer的分数变化后重赛
    virtual void rePlay(int thePLayer) = 0;
};
struct player
{
    int id, key;
 
    operator int() const { return key; }
};
template<class T>
class completeWinnerTree :public winnerTree<T>//最小赢者树
{
public:
    completeWinnerTree(T *thePlayer, int theNumerOfPlayers) {
        //构造函数,将赢者树初始化为空,然后生成赢者树
        this->tree = nullptr;
        initialize(thePlayer, theNumerOfPlayers);
    }
    ~completeWinnerTree() {
        //析构函数
        if (tree) {
            delete[] tree;
        }
        tree = nullptr;
    }
 
    //用数组thePlayer[1:numberOfPlayers]生成赢者树
    void initialize(T *thePlayer, int theNumberOfPlayers);
    //返回最终赢者的索引
    int winner()const  { return this->tree[1]; }
    //返回竞赛树某个节点的赢者
    int winner(int i) const{
        return (i < this->numberOfPlayers) ? this->tree[i] : 0;
    }
    //在参赛者thePLayer的分数变化后重赛
    void rePlay(int thePlayer);
 
    //输出赢者树中的一些信息
    void output()const;
    void winnerToLoserTree();
    int RElowExt(){return lowExt;}         //供对象使用
    int REoffset(){return offset;}
    int* root(){return tree};
    int leftChild(int i){ if(i*2<numberOfPlayers-1) return temp*2; return 0;}
    int rightChild(int i){ if(i*2+1<numberOfPlayers-1) return temp*2+1; return 0;}
private:
    /*
        对tree[p]节点进行比赛,leftChild为左子节点,rightChild为右子节点
        如果还有父节点,继续向上比赛
    */
    void play(int p, int leftChild, int rightChild);
private:
    int lowExt;         //最底层外部节点个数
    int offset;         //offset=2*s-1(s为最底层最左端的内部节点)
    int *tree;          //赢者树
    int numberOfPlayers;//竞赛选手的数量
    T *player;          //保存竞赛选手
};
template<class T>
void completeWinnerTree<T>::winnerToLoserTree(){
     queue<int>  q;//层次遍历  赢者树tree【i】 的孩子可以知道比赛的选手
     int temp;
     bool flag=1;
     int left,right,rightFirstPlayer;
     int s=numberOfPlayers-lowExt/2; //最后一个内部节点序号 反解
        q.push(1);
     while(!q.empty()){
         temp=q.front();
         q.pop();
         if(temp*2<numberOfPlayers-1){//反解定位到左子树
                left= player[ tree[temp*2] ];
                if(flag)
                  tree[0]= tree[temp*2];
         }
                  else if( temp*2>=s )
                    left= player[2*temp-offset];
                     else
                       left= player[2*temp+1+lowExt-numberOfPlayers];

         if(temp*2+1<numberOfPlayers-1){
               right=player[ tree[temp*2+1] ];
               if(flag)
                 rightFirstPlayer=tree[temp*2+1];
         }
               
                  else if( temp*2+1>=s )
                    right= player[2*temp-offset+1];
                     else
                       left= player[2*temp+1+lowExt-numberOfPlayers+1];
          if(flag){
              //赢者是最小的
              if(left>right)
                 tree[0]=rightFirstPlayer;
                   flag=0;
          }
            tree[temp]= left>right? left:right;
          if(temp*2<numberOfPlayers)
            q.push(temp*2);
           if(temp*2+1<numberOfPlayers)
             q.push(temp*2+1);
            
     }
      cout<<tree[0];
}
 
//用数组thePlayer[1:numberOfPlayers]生成赢者树
template<class T>
void completeWinnerTree<T>::initialize(T *thePlayer, int theNumberOfPlayers)
{
    int n = theNumberOfPlayers;//竞赛者的数量 //如果竞赛者的数目小于2,不能进行竞赛
    if (n < 2)
    {
           cout<<"error!"<<endl;
           exit(1);
    }
        
 
    //初始化类内数据成员
    this->player = thePlayer; //竞赛者
    this->numberOfPlayers = n;//当前竞赛者的数目
    delete[] this->tree;      //删除竞赛树
    this->tree = new int[n];        //创建竞赛树数组
    
    //计算s=2^log (n-1)
    int i, s;
    for (s = 1; 2 * s <= n - 1; s += s);
 
    this->lowExt = 2 * (n - s);//最底层外部节点个数(见公式) 13-1
    this->offset = 2 * s - 1;
 
    //为最低级别的外部节点进行匹配
    for (i = 2; i <= this->lowExt; i += 2)    //从外部右孩子节点来比较
        play((this->offset + i) / 2, i - 1, i);

            //处理剩余的外部节点
    if (n % 2 == 1) {
        //特殊情况下奇数n,发挥内部和外部节点
        play(n / 2, this->tree[n - 1], this->lowExt + 1);
        i = this->lowExt + 3;
    }
    else {
        i = this->lowExt + 2;
    }
 
    //i是最左边剩余的外部节点
    for (; i <= n; i += 2)
        play((i - this->lowExt + n - 1) / 2, i - 1, i);
 

}
 
/*
    对tree[p]节点进行比赛,leftChild为左子节点,rightChild为右子节点
    如果还有父节点,继续向上比赛
*/
template<class T>
void completeWinnerTree<T>::play(int p, int leftChild, int rightChild)
{
    //因为为最小赢者树,所以返回值比较小的为赢者
    //* 将play 和replay 的<= 改为> 即为最大赢者树
    this->tree[p] = (this->player[leftChild] > this->player[ri
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值