C++ 二叉树性质及相关题目

1.二叉树有如下特性:

(1)包含n(n>0)个元素的二叉树边数为n-1;

(2)若二叉树的高度为h,h≥0,则该二叉树最少有h个元素,最多有2^{h}-1个元素;

(3)包含n个元素的二叉树的高度最大为n,最小为\left \lceil log_{2}(n+1) \right \rceil

2. 完全二叉树的定义

若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。

 3. 完全二叉树的性质

设完全二叉树中艺元素的序号为i,1≤i≤n。则有以下关系成立:

(1)当i=1时,该节点为二叉树的根。若i>1,则该节点的父节点编号为\left \lfloor i/2 \right \rfloor

(2)当2i>n时,该节点无左子。否则,其左孩子的编号为2i;

(3)当2i+1>n时,该节点无右子。否则,其右孩子的编号为2i+1。

4. 二叉树的前序、中序、后序遍历

struct BinaryTreeNode{
    int mdata;
    BinaryTreeNode* leftChild;
    BinaryTreeNode* rightChild;
};

//前序遍历
void PreOrder(BinaryTreeNode* r){
    if(r == NULL){
        return;
    }
    cout << r->mdata << endl;
    PreOrder(r->leftChild);
    PreOrder(r->rightChild);
}

//中序遍历
void MedianOrder(BinaryTreeNode* r){
    if(r == NULL){
        return;
    }
    MedianOrder(r->leftChild);
    cout << r->mdata << endl;
    MedianOrder(r->rightChild);
}

//后序遍历
void PostOrder(BinaryTreeNode* r){
    if(r == NULL){
        return;
    }
    PostOrder(r->leftChild);
    PostOrder(r->rightChild);
    cout << r->mdata << endl;
}

5. 树的层序遍历

树的层序遍历就是从根开始,从上到下,从左到右,依次把树里的元素遍历一遍。比如,按照层序遍历方式,下面的二叉树输出1->2->3->4->5->6。这种先进先出的形式很好地符合了队列(queue)的性质,因此先用队列来存储遍历到的元素是个不错的选择。

// 二叉树的层序遍历
void LayerOrder(BinaryTreeNode* r){  
    queue<BinaryTreeNode*> treenum;
    treenum.push(r);
    while(!treenum.empty()){
        BinaryTreeNode* fro = treenum.front();
        cout << fro->mdata << endl; //输出头部元素
        treenum.pop();//删除头部元素
        if(fro->leftChild != NULL)
            treenum.push(fro->leftChild); //加入左子
        if(fro->rightChild != NULL)
            treenum.push(fro->rightChild); //加入右子
    }

}

6. 二叉树的重构

只由一种方式的输出结果是不能重构出二叉树的,但是只要知道其中任意两种的输出结果,就能准确地重构出二叉树。比如得知前序遍历序列{1,2,4,7,3,5,6,8},中序遍历序列{4,7,2,1,5,3,8,6},根据两种输出方式的特点,就可以重构出二叉树如下:

 

由于前序遍历的输出方式为:根→左子树→右子树,中序遍历的输出方式为:左子树→根→右子树,所以,可以先由前序遍历的序列确定根节点,再由中序遍历序列确定根节点的左右子树,再递归地处理左右子树。

struct BinaryTreeNode{
    int value;
    BinaryTreeNode* left;
    BinaryTreeNode* right;
};

//重构二叉树的核心函数
/*
参数说明:
start_preorder 为前序遍历序列首元素指针
end_preorder   为前序遍历序列尾后指针
start_inorder  为中序遍历序列首元素指针
start_inorder  为中序遍历序列尾后指针

返回:root 根节点
*/
BinaryTreeNode* ReconstructCore(int* start_preorder, int* end_preorder,
    int* start_inorder, int* end_inorder){
        if((end_preorder - start_preorder < 0) || (end_inorder - start_inorder < 0))
            throw exception("Invalid Input."); 
       
        //前序遍历序列的首元素变为根节点
        int root_value = start_preorder[0];
        BinaryTreeNode* root = new BinaryTreeNode;
        root->value = root_value;
        root->left = NULL;
        root->right = NULL;
        if(end_preorder == start_preorder){
            if(start_inorder == end_inorder && *start_preorder == *start_inorder)
                return root; //二叉树中只有一个节点的情况
            else  
                throw exception("Invalid Input.");
        }
        int* temp_inorder = start_inorder;
        int len_left = 0;
        for(; temp_inorder != end_inorder; ++temp_inorder,++len_left){
            if(*temp_inorder == root_value){
                //cout << *temp_inorder << endl;
                break; //找出中序遍历序列中根节点所在的位置,以确定左右子树中的结点元素
            }
            if(temp_inorder == end_inorder && *temp_inorder != root_value){
                throw exception("Invalid Input.");
            }
        }
        //int len_left = temp_inorder - start_inorder;
        int length = end_preorder - start_preorder;
        if(len_left <= length){
            if(len_left > 0 ){
                //递归地重构左子树
                root->left = ReconstructCore(start_preorder+1, start_preorder+len_left, start_inorder,temp_inorder-1);
            }
            int len_right = length - len_left;
            if(len_right > 0){
                //递归地重构右子树
                root->right = ReconstructCore(start_preorder+len_left+1, end_preorder,temp_inorder + 1,end_inorder);
            }                
        }
        return root;
}

//重构二叉树的主函数
/*
参数说明:
preorder 为前序遍历序列
inorder  为中序遍历序列
length   树中的结点个数

返回:root 根节点
*/
BinaryTreeNode* ReconstructTree(int* preorder, int* inorder, int length){
    if(preorder == NULL || inorder == NULL || length < 0)
        return NULL;
    return ReconstructCore(preorder,preorder+length-1,inorder,inorder+length-1);
}



int main()
{
    
    int pre[8] = {1,2,4,7,3,5,6,8}; //前序遍历序列
    int ino[8] = {4,7,2,1,5,3,8,6}; // 中序遍历序列
    BinaryTreeNode* root = ReconstructTree(pre,ino,8);
    cout << root->left->value << endl;
    return 0;
}

7. 其他,创建了一个二叉树的类,实现了简单的计算叶子数,树的高度,判断节点是否在树中等功能。

class BinaryTreeNode{
private:
    int data;
    BinaryTreeNode* left, *right;
public:
    BinaryTreeNode(int num,BinaryTreeNode* l = NULL,BinaryTreeNode* r = NULL)
        :data(num),left(l),right(r){}
    BinaryTreeNode(){}
    BinaryTreeNode(const BinaryTreeNode& oldnode){
        data = oldnode.data;
        left = new BinaryTreeNode;
        right = new BinaryTreeNode;
        left = oldnode.left;
        right = oldnode.right;
    }
    ~BinaryTreeNode(){delete left,right;}

public:
    void set_data(int item){
        data = item;
    }
    int get_data()const{
        return data;
    }
    void set_left(BinaryTreeNode* l){
        left = l;
    }
    BinaryTreeNode* get_left()const{
        return left;
    }
    void set_right(BinaryTreeNode* r){
        right = r;
    }
    BinaryTreeNode* get_right()const{
        return right;
    }
    BinaryTreeNode& operator= (const BinaryTreeNode& oldnode){
        if(this == &oldnode)
            return *this;
        if(left != NULL)
            delete left;
        if(right != NULL)
            delete right;
        data = oldnode.data;
        left = new BinaryTreeNode;
        right = new BinaryTreeNode;
        left = oldnode.left;
        right = oldnode.right;
        return *this;
    }
};

class BinaryTree{
private:
    BinaryTreeNode* root;

public:
    BinaryTree(BinaryTreeNode* t = NULL):root(t){}
    ~BinaryTree(){delete root;}
public:
    void set_root(BinaryTreeNode* t){
        root = t;
    }
    BinaryTreeNode* get_root()const{
        return root;
    }
    BinaryTreeNode* Create_Tree();
    void PreOeder(BinaryTreeNode* t);
    int Get_leaf_num(BinaryTreeNode* t) const;
    int Get_tree_height(BinaryTreeNode* t)const;
    bool is_in_tree(BinaryTreeNode *r,BinaryTreeNode *t) const;
    int Get_node_num(BinaryTreeNode* r) const;
    void Delete(BinaryTreeNode* r);

};

BinaryTreeNode* BinaryTree::Create_Tree(){
    char item;
    BinaryTreeNode *t,*t_l,*t_r;
    cin>>item;
    if(item != '#')
    {
        BinaryTreeNode *pTmpNode = new BinaryTreeNode(item-48);
        t = pTmpNode;
        t_l = Create_Tree();
        t->set_left(t_l);
        t_r = Create_Tree();
        t->set_right(t_r);
        return t;
    }
    else
    {
        t = NULL;
        return t;
    }

}

void BinaryTree::PreOeder(BinaryTreeNode* t){
    if(t != NULL){
        cout << t->get_data() << " ";
        PreOeder(t->get_left());
        PreOeder(t->get_right());
    }
}

int BinaryTree::Get_leaf_num(BinaryTreeNode* t) const{
    
    if(t == NULL)
        return 0;
    if(t->get_left() == NULL && t->get_right() == NULL)
        return 1;
    return Get_leaf_num(t->get_left())+Get_leaf_num(t->get_right());    
    
}

int BinaryTree::Get_tree_height(BinaryTreeNode* t) const{
    if(t == NULL)
        return 0;
    if(t->get_left() == NULL && t->get_right() == NULL)
        return 1;
    return max(Get_tree_height(t->get_left()),Get_tree_height(t->get_right()))+1;
}

bool BinaryTree::is_in_tree(BinaryTreeNode *r,BinaryTreeNode *t) const{
    if(r == NULL)
        return false;
    if(r == t)
        return true;
    bool isintree = false;
    if(r->get_left() != NULL){
        isintree = is_in_tree(r->get_left(),t);
    }
    if(!isintree && r->get_right() != NULL){
        isintree = is_in_tree(r->get_left(),t);
    }
    return isintree;
}

int BinaryTree::Get_node_num(BinaryTreeNode* r) const{
    if(r == NULL)
        return 0;
    if(r->get_left() == NULL && r->get_right() == NULL)
        return 1;
    return Get_node_num(r->get_left()) + Get_node_num(r->get_right()) + 1;
}

待续。。。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值