| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1370 人关注过本帖
标题:觉得胜者树排序中,从底层和次底层的外部结点向上比赛的PlayUp()函数怎么这 ...
只看楼主 加入收藏
geninsf009
Rank: 3Rank: 3
等 级:论坛游民
威 望:8
帖 子:613
专家分:95
注 册:2008-8-16
结帖率:100%
收藏
 问题点数:0 回复次数:0 
觉得胜者树排序中,从底层和次底层的外部结点向上比赛的PlayUp()函数怎么这么多种情况啊!?
前几天写的是胜者树的构造,play()函数的实现,由于每次产生一个冠军后就把该冠军移出,所以接下来还得
继续从外部结点继续向上比赛,所以还得写一个PlayUp()函数,可每想到有这么多种情况啊,足足九种情况要
考虑,所以代码写的出奇地长,也觉得是排序中最难写的了,下面是刚写完的完整的胜者树类以及排序的实现:

大家多讨论一下这种排序吧...

#ifndef WINNERTREE_H
#define WINNERTREE_H

#include<iostream.h>
#include<stdlib.h>
const int DS=100;
#include<cmath>

////////////////////////////////////////////////////
//WinTree<T>胜者树的类模板的定义
//参加比赛的人数n可以是任意的(不一定是2的幂方)
////////////////////////////////////////////////////
template<class T>
class WinTree
{
private:
    T* e;                 //存放参加比赛的数组元素
    int* t;               //存放胜者或者是offset之后的叶子结点
    int n;                //当前的参加比赛的人数
    int offset;           //最底层的叶子结点数
    int h;                //最大满二叉树的高度
    int maxValue;
public:
    WinTree(T* arr,int x);//构造函数
    int play();           //进行一趟比赛,返回每趟的冠军
    int PlayUp(int p);    //从数组e中的第p个元素开始向上重新比赛
    void WinSort();       //利用当前的胜者树进行排序
};
////////////////////////////////WinTree<T>类模板结束

////////////////////////////////////////////////////
//带参数的构造函数
//通过数组来对当前的胜者树进行初始化
//arr数组中是参加比赛的元素,x是参加比赛的人数
////////////////////////////////////////////////////
template<class T>
WinTree<T>::WinTree(T* arr,int x)
{
    /*初始化相关参数*/
    n=x;                            //参加比赛的人数
    e=new T[x];                     //开辟比赛选手的数组
    t=new int[x-1];                 //存放胜者的选手号的数组
    for(int i=0;i<x;i++)            //初始化选手数组
        e[i]=arr[i];
    maxValue=10000;

    /*首先根据参加比赛的选手数n求出最
    底曾叶子结点数和次底层叶子结点数*/
    h=int(log(2*n-1)/log(2));       //最大满二叉树的深度
    offset=int(2*n-1-(pow(2,h)-1)); //计算最底层的叶子结点数
};
////////////////////////////////////带参数的构造函数

////////////////////////////////////////////////////
//play()公有成员函数  对所有的选手进行一次比赛
////////////////////////////////////////////////////
template<class T>
int WinTree<T>::play()
{
    /*首先让最底层的叶子结点进行比赛*/
    int parent;                          //存放胜者的父结点地址
    for(int i=0;i<offset;i+=2)
    {
        parent=int((pow(2,h)-1+i)/2);    //先计算父结点地址
        if(e[i]<=e[i+1])                 //如果e[i]胜者
            t[parent]=i;                 //把胜者放入t数组父结点位置
        else                             //如果e[i+1]是胜者
            t[parent]=i+1;
    };
    
    /*让次外层上的叶子结点进行比赛*/
    int p=offset;                        //处理次底层叶子的游标
   
    if(n%2!=0)                           //如果参赛人数是奇数
    {                                    //让次外层第一个叶子结点和
        if(e[t[parent]]<=e[p])             //前一个内部结点进行比赛
            t[(parent-1)/2]=t[parent];   //把胜者存入t中
        else
            t[(parent-1)/2]=p;
        p=p+1;
    };

    /*处理剩下的次外层上的叶子结点*/
    for(;p<n;p+=2)
    {
        int k=int(pow(2,h)-1-n+p);       //计算当前叶子结点p在当前二叉树中编号
        parent=int((k-1)/2);             //计算父结点在t中的地址
        if(e[p]<=e[p+1])                 //把胜者放入到t数组中的父结点位置
            t[parent]=p;
        else
            t[parent]=p+1;
    };

    /*对t中剩下的元素进行继续向上比赛*/
    if(n%2!=0)                           //如果n是奇数,说明已经有一个与叶
        p=n-3;                           //子结点比赛了,p从t中倒数第二个元素开始
    else
        p=n-2;                           //p从t中的倒数第一个元素开始向前比赛

    for(;p>0;p-=2)
    {                                    //p始终指向左子树
        parent=int((p-1)/2);
        if(e[t[p]]>=e[t[p-1]])           
            t[parent]=t[p-1];            //存放胜者的编号
        else
            t[parent]=t[p];
    };
                     
    return t[0];
};
//////////////////////////////play()公有成员函数结束

////////////////////////////////////////////////////
//PlayUp() 从弹出的元素开始向上重新调整确定新的冠军
//p是刚刚作为冠军弹出的元素在e数组中的编号
//返回冠军元素的值
////////////////////////////////////////////////////
template<class T>
int WinTree<T>::PlayUp(int p)
{
    /*先进行叶子结点之间的比赛*/
    int parent;                         //存放当前结点p的父结点
    if(n%2!=0)                          //如果n是奇数
    {
        if(p<offset)                    //如果是最底层的叶子结点
        {
            int k=pow(2,h)-1+p;         //p在整个完全二叉树中的编号
            parent=(k-1)/2;
            if(p%2!=0)                  //如果p是奇数
            {
                if(e[p-1]<=e[p])
                    t[parent]=p-1;
                else
                    t[parent]=p;
            }
            else                        //如果p是偶数
            {
                if(e[p]<=e[p+1])
                    t[parent]=p;
                else
                    t[parent]=p+1;
            }
        }
        else if(p==offset)              //第一个次底层的叶子结点
        {
            parent=(n-2-1)/2;
            if(e[t[n-2]]<=e[p])
                t[parent]=t[n-2];
            else
                t[parent]=p;
        }
        else                            //次底层的叶子结点
        {
            int k=(n-1)+(p-offset);
            parent=(k-1)/2;
            if(p%2!=0)                  //如果p是奇数
            {
                if(e[p]<=e[p+1])
                    t[parent]=p;
                else
                    t[parent]=p+1;
            }
            else                        //如果p是偶数
            {
                if(e[p-1]<=e[p])
                    t[parent]=p-1;
                else
                    t[parent]=p;
            }
        }
    }
    else                                //如果n是偶数
    {
        if(p<offset)                    //如果是最底层叶子结点
        {
            int k=pow(2,h)-1+p;
            parent=(k-1)/2;
            if(p%2!=0)                  //如果p是奇数
            {
                if(e[p-1]<=e[p])
                    t[parent]=p-1;
                else
                    t[parent]=p;
            }
            else                        //如果p是偶数
            {
                if(e[p]<=e[p+1])
                    t[parent]=p;
                else
                    t[parent]=p+1;
            }
        }
        else                            //如果是次底层叶子结点
        {
            int k=(n-1)+(p-offset);
            parent=(k-1)/2;
            if(p%2!=0)                  //如果p是奇数
            {
                if(e[p-1]<=e[p])
                    t[parent]=p-1;
                else
                    t[parent]=p;
            }
            else                        //如果p是偶数
            {
                if(e[p]<=e[p+1])
                    t[parent]=p;
                else
                    t[parent]=p+1;
            }
        }
    }
    p=parent;                           //继续向上层比较
    /*如果p是最后一个内部结点,且n是奇数
    则此时p需要和次外层外部结点比赛*/
    if(p==n-2 && n%2!=0)
    {
        int k=n-2;
        parent=(k-1)/2;
        if(e[t[p]]<=e[offset])
            t[parent]=t[p];
        else
            t[parent]=offset;
        p=parent;
    };
    /*对剩下的内部结点循环向上进行比赛*/    
    while(p!=0)
    {
        parent=(p-1)/2;
        if(p%2!=0)
        {
            if(e[t[p]]<=e[t[p+1]])
                t[parent]=t[p];
            else
                t[parent]=t[p+1];
        }
        else
        {
            if(e[t[p-1]]<=e[t[p]])
                t[parent]=t[p-1];
            else
                t[parent]=t[p];
        };
        p=parent;
    };               
    return t[0];                         //返回冠军的选手号
};
////////////////////////////////////PlayUp()函数结束

////////////////////////////////////////////////////
//WinSort()公有成员函数  利用当前的胜者树进行排序
//时间复杂度是O(n*log2(n))
////////////////////////////////////////////////////
template<class T>
void WinTree<T>::WinSort()
{
    int p;                //每次移出的冠军选手号
    p=play();             //首先构造一棵胜者树,并产生第一个冠军
    for(int i=1;i<=n;i++)
    {
        cout<<e[p]<<" ";  //显示每次产生的冠军的内容
        e[t[0]]=maxValue;     //移出当前冠军选手
        p=PlayUp(p);      //进行从底层向上层的调整比赛
    };
};
///////////////////////////////////WinSort()函数结束

#endif
搜索更多相关主题的帖子: 结点 底层 PlayUp 函数 
2008-11-02 20:02
快速回复:觉得胜者树排序中,从底层和次底层的外部结点向上比赛的PlayUp()函数怎 ...
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.021057 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved