EssentialC++_chapter06 binary tree 的学习笔记记录及问题

Essential C++ chapter06 binary tree 的学习笔记记录及问题

  • Author:Dargon
  • Note date:2021/02/28
  • Source: 《Essential C++》 and 《C ++ primer plus》
  • Note: 关于二叉树的构建 插入 移除 和打印 利用C++ template
  • Version: 更改错误 关于输出 << 运算符的问题 2021/03/03

1 BTnode class template 的构建

  • 主要是对于tree 的节点信息的存储 包括value值 、左右子节点的指针 在将此 Class 进行初始化,其余的就是数据结构里正常的 树节点的insert remove and clear 等操作。
/***********************************************************
  * @name    Essential C++ 6th chapter
  * @brief   BTnode class 的声明区域
  * @date    2021/02/26 
*********************************************************/
template<typename elemType>
class BinaryTree; /* forward declaration */

template < typename valType >
class BTnode {
    friend class BinaryTree<valType>; /* 声明友元函数 需要在前面进行声明 */

    public:
        BTnode() {}
        BTnode( const valType &val );
        void insert_value( const valType& val );
        void remove_value( const valType &val, BTnode *& prev );
        static void lchild_leaf( BTnode *leaf, BTnode *subtree );

    private:
        valType _val; /* node 所存储的具体信息 值 */
        int _cnt; /* 记录重复次数 */
        BTnode *_lchild; /* 左右子节点 */
        BTnode *_rchild;

};

template<typename valType>
inline BTnode<valType>::
BTnode( const valType &val ) : _val(val) {
    _cnt =1;
    _lchild =_rchild =0;
}

template<typename valType>
void BTnode<valType>::
insert_value( const valType& val ) {
    if( val ==_val ) {
        _cnt++;
        return;
    }

    if( val <_val ) {
        if( ! _lchild ) {
            _lchild =new BTnode( val );
        }
        else {
            _lchild->insert_value( val );
        }
    }
    else {
        if( ! _rchild ) {
            _rchild =new BTnode( val );
        }
        else {
            _rchild->insert_value( val );
        }
    }
}

template<typename valType>
void BTnode<valType>::
remove_value( const valType &val, BTnode * & prev ) { /* 这个 “* & ” 是有点东西的 */
    if( val <_val ) {
        if( ! _lchild ) {
            return; /* 不在此 binary tree 中 */
        }
        else {
            _lchild->remove_value( val, _lchild ); /* 进行递归的 remove */
        }
    }
    else if( val >_val ) {
        if( ! _rchild ) {
            return;
        }
        else {
            _rchild->remove_value( val, _rchild );
        }
    }
    else {
        /* 找到需要删除的value */
        if( _rchild ) { /* 利用 右子树 进行 取代移除点的位置 */
            prev =_rchild;
            if( _lchild ) { /* 原来节点的左子树 */
                if( ! prev->_lchild ) {
                    prev->_lchild =_lchild;
                }
                else {
                    BTnode<valType>::lchild_leaf( _lchild, prev->_lchild );
                }
            }
            
        }
        else { /* remove节点 没有右子树 直接上左子树 */
            prev =_lchild; 
        }
        delete this; 
    }
        
}

template<typename valType>
inline void BTnode<valType>::
lchild_leaf( BTnode *leaf, BTnode *subtree ) {
    while( subtree->_lchild ) {
        /* 找左子树的 叶节点(最小值) */
        subtree =subtree->_lchild;
    }
    /* 将此 leaf 接在 左边最后面 */
    subtree->_lchild =leaf;
}

2 Binary Tree Class template 的构造

  • 对于整体树 的一个class template的构造 其中遇到的一个问题 在进行operator << 的重构时,出现不明问题 待解决 代码部分已进行注释 其余的操作见代码。
/***********************************************************
  * @name    Essential C++ 6th chapter
  * @brief   BinaryTree class 的声明区域
  * @date    2021/02/26
*********************************************************/

template < typename elemType >
class BinaryTree {

    public:
        /*  这句没有按照书上的写友元函数  */
        //friend ostream& operator<<( ostream &, const BinaryTree<elemType>& );
        /* constructor */
        BinaryTree();
        BinaryTree( const BinaryTree& );
        /* destructor */
        ~BinaryTree();
        /* operator = */
        BinaryTree& operator=( const BinaryTree& );

        void insert( const elemType& );
        void remove( const elemType& elem );
        void remove_root();
        bool empty() { return _root ==0; }

        void clear() { if( _root ) { clear( _root ); _root =0;} } /* 对应下面自己家的clear */
        void preorder(); 
        void pre_recursion( BTnode<elemType> *node ); /* 所使用的输出 */
        void inorder();
        void in_recursion( BTnode<elemType> *node );
        void postorder();
        void post_recursion( BTnode<elemType> *node );

        void preorder( BTnode<elemType> *node, ostream &os =cout );        
        static ostream & display_val( elemType &nodevalue, ostream &os =cout );        
        BTnode<elemType> * get_root() { return _root; }

        ostream& print( ostream &os =cout );

    private:
        BTnode<elemType> *_root; /* 只声明一个 指向BTnode 型的指针 */
        void clear( BTnode<elemType> *node );
        /* copy operator */
        void copy( BTnode<elemType> *tar, BTnode<elemType> *src );
        
};

/* default constructor */
template<typename elemType>
inline BinaryTree<elemType>::BinaryTree() : _root(0) {}

/* copy constructor */
template<typename elemType>
inline BinaryTree<elemType>::BinaryTree( const BinaryTree &rhs ) {
    copy( _root, rhs._root );
}

template<typename elemType>
inline BinaryTree<elemType>::~BinaryTree() {
    clear();
}

template<typename elemType>
inline BinaryTree<elemType> &BinaryTree<elemType>:: /* 相当于 返回类型 */
operator=( const BinaryTree &rhs ) {
    if( this != &rhs ) {
        clear();
        copy( _root, rhs._root );
    }
    return *this;
}

/* insert */
template<typename elemType>
inline void BinaryTree<elemType>::
insert( const elemType &elem ) {
    if( ! _root ) {
        _root =new BTnode<elemType> (elem);
    }
    else {
        _root->insert_value( elem ); /* 还未初始化 */
    }
}

/* remove */
template<typename elemType>
inline void BinaryTree<elemType>::
remove( const elemType &elem ) {
    if( _root ) {
        if( _root->_val ==elem ) {
            remove_root(); /* 对于根节点的操作 特殊处理 */
        }
        else {
            _root->remove_value( elem, _root ); /* 正常情况的处理 */
        }
    }
}

template<typename elemType>
inline void BinaryTree<elemType>::
remove_root() {
    if( ! _root ) return;

    BTnode<elemType> *tmp =_root;
    /* 从右子树 下手 */
    if( _root->_rchild ) {
        _root =_root->_rchild; /* 右子树 取代根 的位置 */

        /* 下面只需要将根 的 左子树部分 搬移到 右子节点 左子树的底部 即可 */
        if( tmp->_lchild ) {
            BTnode<elemType> *lc =tmp->_lchild;     /* 原来根的 左子树 */
            BTnode<elemType> *newlc =_root->_lchild;/* 现在根的 左子树 */
            if( ! newlc ) { 
                /* 没有 直接接上 */
                _root->_lchild =lc; 
            }
            else {
                /* 有的话 找到左子树的 底部 接到下面就可以 */
                BTnode<elemType>::lchild_leaf( lc, newlc );
            }
        }
    }
    /* 直接 左子树 接上 */
    else {
        _root =_root->_lchild;
    }

    delete tmp; /* delete root node */
}

/* clear */
template<typename elemType>
inline void BinaryTree<elemType>::
clear( BTnode<elemType> *pt ) {
    if( pt ) {
        clear( pt->_lchild );
        clear( pt->_rchild );
        delete pt;
    }
}

/* preorder */
template<typename elemType>
inline void BinaryTree<elemType>::
preorder() {
    pre_recursion( _root );
}

template<typename elemType>
inline void BinaryTree<elemType>::
pre_recursion( BTnode<elemType> *node ) {
    if( node ) {
        std::cout << node->_val << " ";

        if( node->_lchild ) {
            pre_recursion( node->_lchild );
        }
        if( node->_rchild ) {
            pre_recursion( node->_rchild );
        }
    }
}

/* inorder */
template<typename elemType>
inline void BinaryTree<elemType>::
inorder() {
    in_recursion( _root );
}

template<typename elemType>
inline void BinaryTree<elemType>::
in_recursion( BTnode<elemType> *node ) {
    if( node ) {
        std::cout << node->_val << " ";

        if( node->_lchild ) {
            in_recursion( node->_lchild );
        }
        if( node->_rchild ) {
            in_recursion( node->_rchild );
        }
    }
}

/* postorder */
template<typename elemType>
inline void BinaryTree<elemType>::
postorder() {
    post_recursion( _root );
}

template<typename elemType>
inline void BinaryTree<elemType>::
post_recursion( BTnode<elemType> *node ) {
    if( node ) {
        std::cout << node->_val << " ";

        if( node->_lchild ) {
            post_recursion( node->_lchild );
        }
        if( node->_rchild ) {
            post_recursion( node->_rchild );
        }
    }
}

/* 未使用的遍历方法 */
template<typename elemType>
inline void BinaryTree<elemType>::
preorder( BTnode<elemType> *node, ostream &os ) {
    if( node ) {
        display_val( node->_val, os );
        preorder( node->_lchild, os );
        preorder( node->_rchild, os );
    }
}

template<typename elemType>
ostream & BinaryTree<elemType>::
display_val( elemType &nodevalue, ostream &os ) {
    os << nodevalue << ' ';
    return os;
}

template<typename elemType>
ostream & BinaryTree<elemType>::
print( ostream &os ) {
    preorder( _root, os );
    return os;
}

/* 关乎 输出运算符问题 此处更改错误 */
/* 把参数的 const 类型声明去掉 原因 是在调用时候 你所定义的函数就是 non-const类型 所以输出也要一样 */
template<typename elemType>
inline ostream&
operator<<( ostream &os, BinaryTree<elemType> &bt ) {
    os << "\nTree: " << endl;
    //return bt.print(os);
    return os;
}

3 关于class template 的测试

  • 此处打印 树 使用 前序遍历preorder 进行显示 “<<" 操作符未使用
int exercise_06_01() {
    BinaryTree<string> bt;

    bt.insert( "Piglet" );
    bt.insert( "Eeyore" );
    bt.insert( "Roo" );
    bt.insert( "Tigger" );
    bt.insert( "Chris" );
    bt.insert( "Pooh" );
    bt.insert( "Kanga" );

    cout << "Preorder tracersal: \n";
    bt.preorder();

    bt.remove( "Piglet" );
    cout << "\n\nPreorder traversal after Piglet remove: \n";
    bt.preorder();

    bt.remove( "Eeyore" );
    bt.insert( "Piglet" );
    cout << "\n\nPreorder traversal after Eeyore remove: \n";
    bt.preorder();

    BinaryTree<string> bt;
    cout << bt << endl;

    return RUN_TEST_OK;
}

程序的输出测试:
Preorder tracersal:
Piglet Eeyore Chris Kanga Roo Pooh Tigger 

Preorder traversal after Piglet remove:   
Roo Pooh Eeyore Chris Kanga Tigger        

Preorder traversal after Eeyore remove:   
Roo Pooh Kanga Chris Piglet Tigger        
Tree:
Roo Pooh Kanga Chris Piglet Tigger

"I'm fine, Dargon !"

按任意键关闭终端。

4 记录

  • 初学习 C++ ,把Essential C++ 学习结束,应该不太适合没有任何语言接触的同学学习,之前有C的基础 但是对于作者 想在漫不经意中所传达的知识,自己肯定有很多没有get 到的。其实 对于语言这种东西 还得老老实实的学习 不要相信多少多少天完成 都是扯淡 。学习嘛! 沉甸甸的 踏实 好些。 对于新接触的一门语言来说 重要的是你要按照它的语法来描述同一样的东西 这点是很重要的,其实远远没有到使用逻辑技巧去解决一些实用性的问题 暂且 把这称作基础吧!
  • 隔几天 突然找到问题所在 特此回来更改 一天天的 净写BUG了
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值