二叉树建立,复制,销毁及简单接口

二叉树:节点最多只有两个子树,有左右之分,次序不可颠倒。

二叉树的建立

利用先序序列递归建立二叉树:给定一个先序遍历数组用链表创建二叉树。
建立一个二叉树节点类:

//二叉树节点的类
template<class T>
struct BinaryTreeNode
{
    //节点的构造函数
    BinaryTreeNode(const T& x)
    :_data(x)
    , _leftNode(NULL)
    , _rightNode(NULL)
    {}
    T _data;//节点数据
    BinaryTreeNode<T> *_leftNode;//左子树节点
    BinaryTreeNode<T> *_rightNode;//右子树节点
};
   当数组的元素不为 # 且数组的下标满足要求时,以数组元素数据建立头节点,左子树和右子树的建立属于子问题,用递归实现。

这里写图片描述

//二叉树类
template<class T>
class BinaryTree
{
    typedef BinaryTreeNode<T> Node;
public:

    。。。

    //利用数组建立二叉树
    //invalid用来标识 # 也就是数组中的空元素
    BinaryTree(const T* arr, size_t size, const T& invalid)
    {
        size_t index = 0;
        _root = CreatTree(arr, size, invalid, index);
    }
    Node* CreatTree(const T* arr, size_t size, const T& invalid, size_t& index) 
    //index传引用,可以有累加的功能,防止每次进函数都是从0开始
    {
        Node* root = NULL;
        //当满足if条件时,创建根节点,左子树,右子树
        if (arr[index] != invalid&&index < size)
        {
            root = new Node(arr[index]);
            root->_leftNode = CreatTree(arr, size, invalid, ++index);
            root->_rightNode = CreatTree(arr, size, invalid, ++index);  
        }
        return root;
    }

二叉树的复制

二叉树的复制包括创建新对象并用已存在的对象对其进行初始化,对已存在对象进行赋值操作。

//二叉树的复制(拷贝构造函数)
    BinaryTree(BinaryTree<T>& t)
    {
        _root = CopyTree(t._root);
    }
    Node* CopyTree(Node* root)
    {
        if (root == NULL)
        {
            return NULL;
        }
        Node* cur = new Node(root->_data);
        cur->_leftNode = CopyTree(root->_leftNode);
        cur->_rightNode = CopyTree(root->_rightNode);
        return cur;
    }
    //运算符的重载(还可以使用swap函数直接交换赋值)
    BinaryTree<T>& operator= (BinaryTree<T>& t)
    {
        if (_root)
        {
            Destory(_root);
        }
        _root = CopyTree(t._root);
        return *this;
    }

二叉树的销毁

二叉树的销毁其实就是BinaryTree类的析构函数,用递归的方法,先判断二叉树是否为空,为空直接返回;不为空的时候,转化为子问题,先销毁左子树,再右子树,后根节点。

//二叉树的销毁(析构函数)
    ~BinaryTree()
    {
        Destory(_root);
    }
    void Destory(Node* root)
    {
        //二叉树为空
        if (root == NULL)
        {
            return;
        }
        Destory(root->_leftNode);
        Destory(root->_rightNode);
        if (root)
        {
            delete root;
        }
        root = NULL;
    }

二叉树的大小

用递归的方法,将左子树节点个数和右子树节点个数相加再加上根节点。

//第一种解法:
size_t Size1()
{
    return _Size1(_root);
}
int _Size1(Node* root)
{
    if (root == NULL)
    {
        return 0;
    }
    return _Size1(root->_leftNode) + _Size1(root->_rightNode) + 1;
}

创建了局部变量count用来对节点个数进行记录,只要每次传进函数的节点不为空,count都会进行累加操作, 切记参数传递的时候一定是引用,防止每次进函数时其值是0。

//第二种解法:
size_t Size2()
{
    size_t count = 0;
    return _Size2(_root,count);
}
int _Size2(Node* root,size_t& count)
{
    if (root == NULL)
    {
        return 0;
    }
    count++;
    _Size2(root->_leftNode,count);
    _Size2(root->_rightNode,count);
    return count;
}

二叉树的深度

二叉树的深度是指二叉树所有路径中最长的路径。
运用递归的方法,比较根节点左子树,右子树路径的长度,再对左子树,右子树进行单独处理;根节点的左子树节点会分为左子树,右子树;根节点的右子树节点也会分为左子树,右子树……不断的进行。当整棵树的节点被计算完选择最长的路径再加上根节点就是二叉树的深度。

size_t Depth()
{
    return _Depth(_root);
}
size_t _Depth(Node* root)
{
    if (root == NULL)
    {
        return 0;
    }
    size_t leftD = _Depth(root->_leftNode);
    size_t rightD = _Depth(root->_rightNode);
    return leftD > rightD ? leftD + 1 : rightD + 1;
}

二叉树的叶子节点

二叉树的叶子节点是指一个节点既没有左子树节点也没有右子树节点。
判断的条件:左子树节点为NULL,右子树节点为NULL。满足条件对其调用者返回1,然后调用者对返回的个数进行累加。

//第一种解法
size_t LeafSize1()
{
    return _LeafSize1(_root);
}
int _LeafSize1(Node* root)
{
    if (root == NULL)
    {
        return 0;
    }
    if (root->_leftNode == NULL&&root->_rightNode == NULL)
    {
        return 1;
    }
    return _LeafSize1(root->_leftNode) +_LeafSize1(root->_rightNode);
}

每找到一个满足条件的节点就对count进行++,再对根节点的左子树节点,右子树节点进行判断,直至整棵树的节点被访问。

//第二种解法
size_t LeafSize2()
{
    size_t count = 0;
    return _LeafSize2(_root, count);
}
size_t _LeafSize2(Node* root,size_t& count)
{
    if (root == NULL)
    {
        return 0;
    }
    if (root->_leftNode == NULL&&root->_rightNode == NULL)
    {
        ++count;
    }
    _LeafSize2(root->_leftNode,count);
    _LeafSize2(root->_rightNode,count);
    return count;
}

二叉树第K层节点

size_t GetKLevel(size_t k)
{
    return _GetKLevel(_root,k);
}
int _GetKLevel(Node* root,size_t k)
{
    //数为空时返回0
    if (root == NULL)
    {
        return 0;
    }
    //当是第一层节点时,只有根节点返回1
    if (k == 1)
    {
        return 1;
    }
    //当K大于1时,返回左子树第K-1层节点数加右子树第K-1层节点数
    return _GetKLevel(root->_leftNode, k-1) + _GetKLevel(root->_rightNode, k-1);
}

二叉树的查找

在二叉树中查找一个指定的数

  • 二叉树为空的时候,返回NULL;
  • 不为空时,对二叉树的左子树节点和右子树节点分别进行判断,找到的话返回节点。
Node* FindNode(const T& x)
{
    return _FindNode(_root,x);
}
Node* _FindNode(Node* root, const T& x)
{
    if (root == NULL)
    {
        return NULL;
    }
    if (root->_data == x)
    {
        return root;
    }
    if(root->_leftNode)
    {
        Node* ret = _FindNode(root->_leftNode, x);
        if (ret)
        {
            return ret;
        }
        else
        {
            return NULL;
        }
    }
    if(root->_rightNode)
    {
        Node* cur = _FindNode(root->_rightNode, x);
        if (cur)
        {
            return cur;
        }
        else
        {
            return NULL;
        }
    }
}

注:运用递归算法时,被调函数的参数在本函数中就是根节点,不再是左子树节点或右子树节点,这个问题需注意。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
二叉树是一种形结构,它的每个节点最多只有两个子节点。二叉树的遍历方式有三种:先序遍历、中序遍历和后序遍历。其中,先序遍历是指先访问根节点,然后访问左子,最后访问右子;中序遍历是指先访问左子,然后访问根节点,最后访问右子;后序遍历是指先访问左子,然后访问右子,最后访问根节点。 二叉树建立可以通过递归或非递归方式实现。递归方式建立二叉树的过程是:先读入一个节点的值,如果该节点的值不为空,则创建一个新节点,并将该节点的值赋给新节点;然后递归调用建立左子和右子的过程,直到读入的节点值为空为止。非递归方式建立二叉树的过程是:使用一个栈来存储节点,先读入根节点的值,创建一个新节点,并将该节点入栈;然后读入下一个节点的值,如果该节点的值不为空,则创建一个新节点,并将该节点入栈,并将该节点作为上一个节点的左子节点;如果该节点的值为空,则弹出栈顶节点,并将该节点作为上一个节点的右子节点。 二叉树的遍历算法可以通过递归或非递归方式实现。递归方式实现二叉树的遍历算法比较简单,只需要按照遍历顺序递归访问左子和右子即可。非递归方式实现二叉树的遍历算法需要使用栈来存储节点。先序遍历的非递归算法是:先将根节点入栈,然后弹出栈顶节点并访问该节点,将该节点的右子节点入栈,再将该节点的左子节点入栈,重复上述过程直到栈为空;中序遍历的非递归算法是:先将根节点入栈,然后将根节点的所有左子节点入栈,重复弹出栈顶节点并访问该节点,将该节点的右子节点入栈,重复上述过程直到栈为空;后序遍历的非递归算法是:先将根节点入栈,然后将根节点的所有左子节点入栈,重复弹出栈顶节点并访问该节点,如果该节点的右子节点不为空且未被访问过,则将该节点的右子节点入栈,否则访问该节点,重复上述过程直到栈为空。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值