如何写一颗二叉树(递归)【菜鸟学习日记】

老规矩,开篇点题,今天写了二叉树,整理总结一下

要写二叉树,先画出一颗来
这里写图片描述

二叉树我是用链表来实现的
1、每一个节点包含数据,左指针和右指针,分别指向左孩子和右孩子

这里写图片描述

//创建节点类型
//节点中有数据,有指针
template<class T>
struct  BinaryTreeNode
{
    T _data;//数据
    BinaryTreeNode<T> *_left;//左孩子
    BinaryTreeNode<T> *_right;//右孩子

    //初始化
    BinaryTreeNode(const T&x)
        :_data(x)
        , _left(NULL)
        , _right(NULL)
    {}
};
2、然后开始创建一个二叉树类

并创建树的各个节点

思路:

这里写图片描述
‘#’是我们这里用到的标识符(invalid),用来标记的,当然也可以用其它的,当遇到#就代表为空,没有节点了

从根节点开始按前序的顺序遍历创建(这里的遍历用了递归的方法)

这里写图片描述

class BinaryTree
{
    typedef BinaryTreeNode<T> Node;
public:
    BinaryTree(T* a,size_t n,const T&invalid)
    {
        size_t index = 0;
        _root = GreateTree(a, n, invalid, index);
    }

    Node* GreateTree(T* a, size_t n, const T&invalid,size_t &index)
    {
        //根->左子树->右字树
        Node* root = NULL;
        if (a[index] != invalid)
        {
            root = new Node(a[index]);//创建根节点
            root->_left = GreateTree(a, n, invalid, ++index);//左树
            root->_right = GreateTree(a, n, invalid, ++index);//右树
        }

        return root;
    }
protected:
    Node* _root;//根节点
};
3、创建好一棵树,就可以实现它的其它接口了

前序、种序、后续遍历,遍历其实就是
打印的顺序不同

有一点要注意的是,因为我们遍历时要有根节点参数,但类外拿不到树的根节点,所以再写一些要用根节点的接口时,要有一个无参类型的函数,在类的内部再将根节点传参访问
//前序遍历
    void PrevOrder()
    {
        PrevOrder(_root);
    }
    //根->左->右
    void PrevOrder(Node* root)
    {
        //为空树,返回
        if (root == NULL)
        {
            return;
        }
        //不为空树
        cout << root->_data <<" ";
        PrevOrder(root->_left);
        PrevOrder(root->_right);

    }
    //中序
    void MidOrder()
    {
        MidOrder(_root);
    }
    //左->根->右
    void MidOrder(Node* root)
    {
        if (root == NULL)
        {
            return;
        }
        MidOrder(root->_left);
        cout << root->_data <<" ";
        MidOrder(root->_right);

    }
    //后序
    void PostOrder()
    {
        PostOrder(_root);
    }
    //左->右->根
    void PostOrder(Node* root)
    {
        if (root == NULL)
        {
            return;
        }
        PostOrder(root->_left);
        PostOrder(root->_right);
        cout << root->_data <<" ";

    }
//测试一下
void TestBinaryTree()
{
    int arr[] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, '#', '#'};
    BinaryTree<int> t(arr, sizeof(arr) / sizeof(int), '#');

    cout << "前序:";
    t.PrevOrder();
    cout << endl;

    cout << "中序:";
    t.MidOrder();
    cout << endl;

    cout << "后序:";
    t.PostOrder();
    cout << endl;
}

这里写图片描述

还有一种层序遍历
层序遍历与前面三种实现的方法不太一样,层序的遍历要借助一个队列来实现

这里写图片描述

先将根节点入队列,然后将其左右孩子入队列,将队头Pop;

每次将队头的左右孩子入队,Pop队头,就可以实现层序遍历了
   //层序
    void LevelOrder()
    {
        LevelOrder(_root);
    }
    void LevelOrder(Node* root)
    {
        if (root == NULL)
        {
            return;
        }
        //借助栈来实现
        //栈里放指向节点的指针
        queue<Node*> q;
        q.push(root);
        while (!q.empty())
        {
            //打印队头,入栈对头的左右孩子再队尾,出队头
            Node* front = q.front();//取队头
            cout << front->_data << " ";
            if (front->_left != NULL)
            {
                q.push(front->_left);
            }
            if (front->_right != NULL)
            {
                q.push(front->_right);
            }
            q.pop();
        }   
    }

这里写图片描述


实现了四种遍历的接口,接下来该实现计算节点的几种接口了,还有计算深度的接口
  • 计算节点总数
  • 计算叶子节点数
  • 计算第K层的节点数
  • 树的深度

计算节点的总数

可以有两种思路
  1. 遍历,计数
  2. 将其转化为子问题,节点总数=左子树+右子树+根

实现一下:

//节点总数
    //方法一:遍历
    //size_t Size()
    //{
    //  size_t size = 0;//计数
    //  Size(_root,size);
    //  return size;
    //}

    //size_t Size(Node* root,size_t &size)
    //{
    //  if (root == NULL)
    //  {
    //      return 0;
    //  }
    //遍历计数
    //  size++;
    //  Size(root->_left, size);
    //  Size(root->_right, size);
    //  return size;
    //}

    //方法二:转化为子问题
    size_t Size()
    {
         return Size(_root);
    }

    size_t Size(Node* root)
    {
        if (root == NULL)
        {
            return 0;
        }
        //左子树+右子树+根
        return Size(root->_left) + Size(root->_right)+1;
    }

这里写图片描述

计算叶子节点数

这个问题也是跟上一个问题一样两种思路,遍历或者转化为子问题

    //方法一:遍历
    //size_t LeafSize()//叶子节点数
    //{
    //  size_t size = 0;
    //  LeafSize(_root,size);
    //  return size;
    //}
    //size_t LeafSize(Node* root,size_t &size)
    //{
    //  if (root == NULL)
    //  {
    //      return 0;
    //  }
    //  if (root->_left == NULL&&root->_right == NULL)
    //  {
    //      size++;
    //  }   
    //  LeafSize(root->_left,size);
    //  LeafSize(root->_right,size);
    //  return size;
    //}

    //方法二:子问题
    size_t LeafSize()//叶子节点数
    {
        return LeafSize(_root);
    }
    size_t LeafSize(Node* root)
    {
        if (root == NULL)
        {
            return 0;
        }
        //是叶子节点,返回1
        if (root->_left == NULL&&root->_right == NULL)
        {
            return 1;
        }
        //不是叶子节点,再向下递归
        return LeafSize(root->_left)+LeafSize(root->_right);
    }

计算第K层的节点数

这里写图片描述
这里我们虽然要求的是第k层的节点数,但是我们无法直接到达第k层,我们依然要从根节点开始逐层进入,直到k==1,我们就到达了我们要求的那层了,也就是我们递归结束的标志

然后,再来将问题转化为子问题,第k层的节点数=第k-1层的左子树+右子树节点
这里要注意的是,参数不能用k的引用,因为如果用了引用,当

我们访问完左子树时,k已经被修改,再访问右子树时,会出错

    size_t GetKLevel(size_t k)//第k层节点数
    {
        return _GetKLevel(_root,k);
    }
    size_t _GetKLevel(Node* root,size_t k)//这里注意不能用k的引用
    {
        assert(k > 0);
        if (root == NULL)
        {
            return 0;
        }
        //k==1
        if (k == 1)
        {
            return 1;
        }
        //k>1,第k层的节点数=第k-1层的左子树+右子树节点
        if (k > 1)
        {
            return _GetKLevel(root->_left, k - 1) + _GetKLevel(root->_right, k - 1);
        }
    }

树的深度

这里写图片描述

这个问题也同样转化为子问题解决
思路:树的深度=左右子树深度大的+1,每一个子树都是如此,递归就行了

当递归到叶子时,返回1
这里写图片描述

//深度
    size_t Depth()
    {
        return Depth(_root);
    }
    size_t Depth(Node* root)
    {
        if (root == NULL)
        {
            return 0;
        }
        //为最底层叶子时,返回1
        if (root->_left == NULL&&root->_right == NULL)
        {
            return 1;
        }
        //否则,返回左右子树大的+1
        return Depth(root->_left) > Depth(root->_right) ?
            Depth(root->_left) + 1 : Depth(root->_right) + 1;
    }

测试一下这颗新树:
这里写图片描述


总结:其实写二叉树,主要就是用了递归的思想
还有就是将一个问题转化为子问去解决
  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,下面是使用Python编写一个二叉树的非递归遍历的示例代码: ```python class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right class Solution: def inorderTraversal(self, root: TreeNode) -> List[int]: stack = [] result = [] node = root while node or stack: while node: stack.append(node) node = node.left node = stack.pop() result.append(node.val) node = node.right return result ``` 上面的代码实现了一个二叉树的中序遍历。它使用了一个栈来记录遍历过程中的节点,以及一个结果列表来记录遍历结果。遍历过程中,我们先将根节点和所有左子节点入栈,然后逐个弹出栈顶节点,将其值加入结果列表,并将右子节点入栈。当栈为空时,遍历结束。我们可以将上面的代码稍作修改,来实现二叉树的前序遍历和后序遍历。 ### 回答2: 二叉树的非递归遍历可以使用栈来实现。具体步骤如下: 1. 首先定义一个栈,用于存储待遍历的节点。 2. 将二叉树的根节点压入栈中。 3. 循环执行以下操作,直到栈为空: a. 弹出栈顶节点,并打印该节点的值。 b. 如果该节点的右子节点不为空,则将右子节点压入栈中。 c. 如果该节点的左子节点不为空,则将左子节点压入栈中。 4. 遍历结束。 下面是用Python编写的代码示例: ```python class Node: def __init__(self, value): self.value = value self.left = None self.right = None def non_recursive_traversal(root): if not root: return stack = [] current = root while stack or current: while current: stack.append(current) current = current.left current = stack.pop() print(current.value) current = current.right # 构建一个二叉树用于测试 root = Node(1) root.left = Node(2) root.right = Node(3) root.left.left = Node(4) root.left.right = Node(5) root.right.left = Node(6) root.right.right = Node(7) print("非递归遍历结果:") non_recursive_traversal(root) ``` 以上代码中,首先定义了一个`Node`类用于表示二叉树的节点。然后通过`non_recursive_traversal`函数实现了二叉树的非递归遍历。最后通过构建一个二叉树,调用该函数进行遍历并打印结果。 ### 回答3: 二叉树的非递归遍历可以使用栈数据结构来实现。下面是用Python一个二叉树的先序遍历的非递归遍历的示例代码。 ```python # 定义二叉树节点类 class TreeNode: def __init__(self, value): self.val = value self.left = None self.right = None # 定义二叉树递归先序遍历函数 def preorderTraversal(root): if not root: return [] stack = [] result = [] node = root while node or stack: while node: result.append(node.val) # 先访问当前节点的值 stack.append(node) # 入栈 node = node.left # 遍历左子树 node = stack.pop() # 出栈 node = node.right # 遍历右子树 return result ``` 使用示例: ```python # 创建二叉树 root = TreeNode(1) root.left = TreeNode(2) root.right = TreeNode(3) root.left.left = TreeNode(4) root.left.right = TreeNode(5) # 调用非递归遍历函数 result = preorderTraversal(root) print(result) # 输出:[1, 2, 4, 5, 3] ``` 该示例代码实现了二叉树的非递归先序遍历。类似地,可以根据需要修改代码实现其他遍历方式,如中序遍历和后序遍历。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值