数据结构_树&普通二叉树

>>数据结构_树

1、树简单介绍

1.1概述及图示

树是一种一对多的数据结构,非线性数据结构,下图就是一颗普通的树。
在这里插入图片描述

1.2常用术语

  • 根节点 就是上图中的粉红节点,它是一颗树的根
  • 父节点 就是一个节点的前驱节点 一个节点只有一个父节点比如5 6 7的父节点是2号节点 8号节点的父节点是3号节点
  • 子节点 就是一个节点的后继节点,一个节点的后继节点可以有多个,比如2号节点的子节点是5 6 7
  • 叶子节点 没有子节点的节点成为叶子节点如上图中的5 6 7 8 9 10
  • 子树 子树就是一个节点的子节点构成的数,比如根节点的一颗最左子树就是2作为根节点构成的树
  • 节点的度 一个节点拥有子树的数目成为节点的度
  • 树的高度 即数的层数,如上图所示,有三层,所以树的高度是3
  • 森林,多颗子树构成森林,最简单的,一颗树去掉根节点剩余的所有子树就构成森林,比如上图删除根节点1,剩下了三颗新的树,这三颗树就构成了森林

2、二叉树

2.1概述

树结构中使用最多的就是二叉树,二叉树就是一颗树的每一个节点最多有两个子节点, 且这两个节点有左右之分,分别称为左节点和右节点
在这里插入图片描述

2.2满二叉树

满二叉树首先是一颗二叉树,并且满足 所有的叶子节点都在最后一层,并且节点总数 sum = 2 ^ n -1n是二叉树的层数

如下图所示,一共有三层,节点总数为2^3-1 = 7,满足上面的条件,且所有的叶子结点都在最后一层,所有下图就是一颗满二叉树

满二叉树的每一层的节点数是 2 ^ (k-1) k是第几层
在这里插入图片描述

2.3完全二叉树

完全二叉树也是一颗二叉树它的叶子节点都分布在最后两层,且倒数第二层的节点数必须是 2 ^ (k-1) ,即倒数第二层的节点数必须是满的,并且最后一层的节点从左边开始连续

所以满二叉树一定是完全二叉树,完全二叉树不一定是满二叉树
在这里插入图片描述

3、二叉树的遍历

3.1代码定义二叉树节点

public class TreeNode {
    
    
	
    //左子节点
    public TreeNode left;
    //右子节点
    public TreeNode right;
    //data域
    public int val;
    
    public TreeNode() {
    
    }
    
    public TreeNode(int val) {
    
    
        this.val = val;
    }
    public TreeNode(TreeNode left, TreeNode right, int val) {
    
    
        this.left = left;
        this.right = right;
        this.val = val;
    }
}

3.2前序遍历(DLR)

力扣143.二叉树的前序遍历

3.2.1概述图示DLR

所谓的前序遍历,也叫先根遍历,即先遍历获取根节点的值,然后遍历获取左子节点的值,最后遍历获取右子节点的值,即(data->left->right)
在这里插入图片描述

3.2.2递归写法

class Solution {
    
    
    //用一个集合保存保存节点的值
    List<Integer> res = new ArrayList();
    public List<Integer> preorderTraversal(TreeNode root) {
    
    
             dlr(root);
             return res;
    }
    
    public void dlr(TreeNode root){
    
    
        if(root == null) return; 
         //先保存根节点的值
         res.add(root.val);
         //保存左节点的值
         dlr(root.left);
         //保存右节点的值
         dlr(root.right);      
    }    
}

3.2.3迭代写法

根据上面的图示可以发现,前序遍历会先一直访问左子树,当左子树为空时(遍历到最后一层时),依次向上访问父节点的右节点,所以我们可以先用一个栈保存左节点,当遍历到最后一层时,取出栈顶元素(就是父节点),使其出栈然后访问其右节点即可。

具体的过程(以上图的二叉树为例):

①  先将 1号节点的值存入集合  
  然后将1号节点入栈
 
②  2 4 8 重复①的过程 

此时集合中的值 1 2 4 8
栈中(TreeNode类型)   
	  8
      4
      2 
      1

--------------
③ 由于8号节点的left是null,所以停止本次查找,此时8号节点(栈顶元素)就是父节点,然后使其出栈,遍历它的右节点,由于它没有右节点,此时栈顶元素时4号节点,然后遍历4号节点的右节点,是9
,将9存入集合并将9号节点入栈,因为9号节点没有left,使其出栈,遍历其右节点为null,然后此时栈顶时2号节点,使其出栈遍历其右节点,。。。。

代码

class Solution {
    
    
    public List<Integer> preorderTraversal(TreeNode root) {
    
    
           List<Integer> res = new ArrayList();
           Stack<TreeNode> stk = new Stack();        
            while(root != null || !stk.isEmpty()){
    
    
                //一直访问左节点
                while(root != null){
    
    
                    res.add(root.val);
                    stk.push(root);
                    root = root.left;
                }
                //此时栈顶元素就是父节点 访问其右节点
                root = stk.pop().right;                
            }
        return res;
    }
}

3.3中序遍历(LDR)

力扣94.二叉树的中序遍历

3.3.1概述

中序遍历即先输出左子节点的值,然后输出父节点的值,最后输出右子节点的值,类似先序遍历

3.3.2递归写法

class Solution {
    
      
    List<Integer> res = new ArrayList();    
    public List<Integer> inorderTraversal(TreeNode root) {
    
    
           if(root==null) return res;             
           inorderTraversal(root.left);
           res.add(root.val);
           inorderTraversal(root.right);         
           return res;        
    }
}

3.3.3迭代写法

也是借助栈,先一直遍历左节点将其入栈,然后从下向上输出值然后遍历右节点即可

class Solution {
    
        
    public List<Integer> inorderTraversal(TreeNode root) {
    
    
            List<Integer> res = new ArrayList();
            Stack<TreeNode> stk = new Stack();
            while(root != null || !stk.isEmpty()){
    
    
                while(root != null){
    
    
                    stk.push(root);                       
                    root = root.left;                    
                }
                TreeNode node = stk.pop();
                res.add(node.val);
                root = node.right;                
            }
        return res;  
    } 
}

3.4后序遍历(LRD)

力扣145.二叉树的后续遍历

递归写法

class Solution {
    
    
    List<Integer> res = new ArrayList();
    public List<Integer> postorderTraversal(TreeNode root) {
    
    
        if(root == null) return res;
        postorderTraversal(root.left);
        postorderTraversal(root.right);
        res.add(root.val);
        return res;
    }
}

迭代写法

后序遍历是LRD 我们只需要前序遍历DRL,然后结果反转即可

class Solution {
    
    
    public List<Integer> postorderTraversal(TreeNode root) {
    
    
        List<Integer> res = new ArrayList();
        Stack<TreeNode> stack = new Stack();
        while (root != null || !stack.isEmpty()) {
    
    
            while (root != null) {
    
    
                stack.push(root);
                res.add(root.val);
                root = root.right;
            }
            root = stack.pop().left;
        }
        //反转
        Collections.reverse(res);
        return res;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_46312987/article/details/119959183
今日推荐