二叉树的基本操作及编程题总结(C++)

**二叉树编程题万变不离其宗在于对递归的理解和使用

要弄懂用好递归 重要的在于一下几条:

1.搞清楚函数递归调用栈帧的变化 特别是二叉递归时的栈帧变化

2.搞清楚各个函数参数 传值和传引用 的函数参数在递归调用时值的变化。

本文中不加注明 所说的二叉树都是普通二叉树

1.定义并构建一颗二叉树

对于一颗普通二叉树的节点 至少要定义出他的值域 和指向其左右子树的左右指针域。
并定义出节点的构造函数 该函数中参数应为要赋予该节点的值 左右指针初始化为空 有树的构造函数处理。

template<class T>
struct BinaryTreeNode
{
    T _value;
    BinaryTreeNode<T>* _pleft;
    BinaryTreeNode<T>* _pright;
    BinaryTreeNode(const T& value)
        : _value(value)
        , _pleft(NULL)
        , _pright(NULL)
    {}
};

对于一颗二叉有 类成员变量中至少应有该树根节点的指针。
在实现构造函数时 运用递归思想 把一棵树分成左子树 右子树 根 三部分 。 每个子树也分成这三部分。

//按前序遍历构造二叉树 ‘#’代表该位置的节点为空  
char arr[] = { '1', '2', '3', '#', '#', '4', '#', '#', '5', '6' };

//变量invalid代表该节点为空                           //数组的索引必须传引用 
BinaryTree<char> BiTree(arr, sizeof(arr) / sizeof(arr[0]), '#');

    Node*  _CreateBinaryTree2(const T arr[], size_t size, size_t& index, const T invalid)
    {
        Node* pRoot = NULL;
        if (index < size && invalid != arr[index])
        {
            pRoot = new Node(arr[index]);
            pRoot->_pleft = _CreateBinaryTree2(arr, size, ++index, invalid);
            pRoot->_pright = _CreateBinaryTree2(arr, size, ++index, invalid);
        //在这里接住下一层的返回值
        }
        return pRoot;
    }

    BinaryTree()
        :_pRoot(NULL)
    {}

    BinaryTree(const T arr[], size_t size, const T& invalid)
    {
        assert(arr);
        size_t index = 0;
        //_CreateBinaryTree1(_pRoot, arr, size, index, invalid);
        _pRoot = _CreateBinaryTree2(arr, size, index, invalid);

 }

二叉树的拷贝构造函数 类似于二叉树的构造函数

    Node*  _CopyBinaryTree(Node* pRoot)
    {
        Node* pNewRoot = NULL;
        if (pRoot){
            pNewRoot = new Node(pRoot->_value);
            pNewRoot->_pleft = _CopyBinaryTree(pRoot->_pleft);
            pNewRoot->_pright = _CopyBinaryTree(pRoot->_pright);
        }
        return pNewRoot;
    }

    BinaryTree(const BinaryTree<T>& bt)
    {
        _pRoot = _CopyBinaryTree(bt._pRoot);
    }

二叉树的析构函数

有所不同 它的逻辑是 先析构左右子树
再析构根节点 因为如果先析构·根节点的话 左右子树将找不到 形成内存泄漏。

~BinaryTree()
    {
        _DestoryBinaryTree(_pRoot);
    }

    void _DestoryBinaryTree(Node*& pRoot)
    {
        if (pRoot){
            _DestoryBinaryTree(pRoot->_pleft);
            _DestoryBinaryTree(pRoot->_pright);
            delete pRoot;
            pRoot = NULL;
        }
    }

二叉树类的赋值运算符重载 注意三个问题

1.不可以自己给自己复制。
2.赋值之前必须进行析构,释放原来自己的内存空间
3.调用二叉树的构造逻辑在根结点上构造新二叉树

    BinaryTree<T>& operator = (const BinaryTree<T>& bt)

    {

        if (this != &bt){

            _DestoryBinaryTree(_pRoot);

            _pRoot = _CopyBinaryTree(bt._pRoot);

        }

        return *this;
    }

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

1.前序遍厉根 -> 左 ->右

先遍历树的根和每一棵子树的根 再递归遍历左子树 左子树遍历好以后退回到根节点这一层函数栈帧再递归遍历右子树 知道每一个节点
都经过遍历:

    void _PreOrder(Node* pRoot)
    {
        if (pRoot){
            cout << pRoot->_value << " ";
            _PreOrder(pRoot->_pleft);
            _PreOrder(pRoot->_pright);
        }

    }

    void PreOrder()
    {
        cout << "PreOrder" << endl;
        _PreOrder(_pRoot);
        cout << endl;
    }
前序遍历的非递归实现
    //把问题分成 树的左路 与 树的其他部分 两块
    //先将节点压栈 遍历后再出栈 以此模仿递归
    void Pre_Order()
    {
        stack<Node*> s;
        Node* cur = _pRoot;
        if (_pRoot == NULL)
            return;

        while (cur || !s.empty()){
  //栈不空说明还有节点未遍历
            while (cur){
                cout << cur->_value << " ";
                s.push(cur);
                cur = cur->_pleft;
            }
            Node* top = s.top();//top 的左边不可能有还没遍历的节点
            s.pop();
            if (top->_pright != NULL)
                cur = top->_pright;
        }
        co
  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值