java之二叉树

       相比于链表需要逐个遍历节点,二叉树在查询节点时会更加方便,二叉树是平衡树的话,那么有有两个分支,遍历数据时会更快,当然这是理想状态下,二叉树也可以写成链表状,就看如何构建了。对于二叉树的学习要知道一些基本概念,比如节点和根节点以及子节点和叶子节点(度为零的节点)的概念,以及二叉树和某个节点的深度和高度的概念,以及度的概念。常见的二叉树有排序树,红黑树,字典树,哈夫曼树,其中哈夫曼树是设计压缩软件的关键,这篇文章我们先看一下排序树以及最基本的三序遍历,即前、中、后三序遍历(递归/非递归),根据访问根节点root的顺序确定是前中还是后序遍历,层序遍历是根据层数进行逐个遍历。

       首先创建Tree类来表示二叉树类,然后创建内部类TreeNode来表示二叉树的节点。同时两个类中写出对应的属性,在Tree类中写上添加节点的方法addNode,在这个方法中有一点值得一提,在做链表或者二叉树题目时,我们都通常把root节点转移至一个curr节点,这里可以认为root就是curr。这样避免最后找不到root,因为在方法中curr要不断迭代,curr可以改变,为了方便解决问题,但是不能使root发生改变。

附上此时的递归方法的前中后遍历方法和Tree类以及TreeNode类的代码

package com.ms.binarytree0724;

public class Tree {
    public TreeNode root;//树的根节点

    //接下来按照
    public void addNode(TreeNode node) {
        if (root == null) {
            root = node;
        } else {
            TreeNode curr = root;//可以认为这就是链表中的一个节点,也只是一个节点。
            while (true) {
                if (node.data < curr.data) {
                    if (curr.left == null) {
                        curr.left = node;
                        break;
                    }
                    curr = curr.left;
                }
                if (node.data > curr.data) {
                    if (node.data > curr.data) {
                        if (curr.right == null) {
                            curr.right = node;
                            break;
                        }
                        curr = curr.right;
                    }
                }
            }
        }
    }

    //递归前序遍历
    public void printTreeq(TreeNode root) {
        if (root != null) {
            System.out.print(root.data+" ");
            printTreeq(root.left);
            printTreeq(root.right);
        }
    }

    //递归中序遍历
    public void printTreez(TreeNode root){
        if (root!=null){
            printTreez(root.left);
            System.out.print(root.data+" ");
            printTreez(root.right);
        }
    }

    //递归后续遍历
    public void printTreeh(TreeNode root){
        if (root!=null){
            printTreeh(root.left);
            printTreeh(root.right);
            System.out.print(root.data+" ");
        }
    }


    public static void main(String[] args) {
        int[] a = {7,6,8,9,3,4,2,1};
        Tree tree = new Tree();
        for (int i =0;i<a.length;i++){
            TreeNode node = new TreeNode(a[i]);
            tree.addNode(node);
        }
        tree.printTreeq(tree.root);
    }

















}


//递归中序遍历


//递归后续遍历


//二叉树的基本概念:左子树,右子树,父节点,子节点,树的深度(从上到下的所有节点数-1)

    //(二叉)树的(每个)节点  类
    class TreeNode {
        public int data;
        public TreeNode left;
        public TreeNode right;

        public TreeNode(int data){
            this.data=data;
        }
    }

接着就开始写出非递归的前中后遍历方法。以及在实现层序遍历时我们使用队列Queue。值得一提的是,LinkedList实现了Queue,所以LinkedList可以当做Queue来使用。附上总体代码

package com.ms.binarytree0724;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class Tree {
    public TreeNode root;//树的根节点

    //接下来按照
    public void addNode(TreeNode node) {
        if (root == null) {
            root = node;
        } else {
            TreeNode curr = root;//可以认为这就是链表中的一个节点,也只是一个节点。
            while (true) {
                if (node.data < curr.data) {
                    if (curr.left == null) {
                        curr.left = node;
                        break;
                    }
                    curr = curr.left;
                }
                if (node.data > curr.data) {
                    if (node.data > curr.data) {
                        if (curr.right == null) {
                            curr.right = node;
                            break;
                        }
                        curr = curr.right;
                    }
                }
            }
        }
    }

    //递归前序遍历
    public void printTreeq(TreeNode root) {
        if (root != null) {
            System.out.print(root.data+" ");
            printTreeq(root.left);
            printTreeq(root.right);
        }
    }

    //递归中序遍历
    public void printTreez(TreeNode root){
        if (root!=null){
            printTreez(root.left);
            System.out.print(root.data+" ");
            printTreez(root.right);
        }
    }

    //递归后续遍历
    public void printTreeh(TreeNode root){
        if (root!=null){
            printTreeh(root.left);
            printTreeh(root.right);
            System.out.print(root.data+" ");
        }
    }


    public static void main(String[] args) {
        int[] a = {7,6,8,9,3,4,2,1};
        Tree tree = new Tree();
        for (int i =0;i<a.length;i++){
            TreeNode node = new TreeNode(a[i]);
            tree.addNode(node);
        }
        //tree.printTreeq(tree.root);
    }
//非递归前序遍历
    public void preOrder(TreeNode root){
        if(root==null) return;
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);//先把root放到栈中,否则进不了循环,同时保证循环迭代中的名称代号相同,千言万语一句话,root只能读不能写
        while(!stack.isEmpty()){
            TreeNode node = stack.pop();
            System.out.print(node.data+" ");//第一次循环时就输出了root节点的值
            if(node.right!=null) stack.push(node.right); //if语句的简便写法
            if(node.left!=null) stack.push(node.left);
        }
    }

//非递归中序遍历    这个方法的关键是我们要先找到最左节点,然后遍历完左节点后再输出root,然后再是右节点
    public void midOrder(TreeNode root) {
        if (root == null) return;
        Stack<TreeNode> stack = new Stack<>();
        TreeNode curr = root;
        while(!stack.isEmpty()||curr!=null){
            while(curr!=null){
                stack.push(curr);
                curr=curr.left;
            }TreeNode node =stack.pop();
            if (node.right!=null) curr = node.right;
        }
    }

//非递归后续遍历   这个考虑把先序改一下,变成根 左 右 的存放顺序,然后统一放到一个新stack中再集体打印即可。
    public void postOrder(TreeNode root){
        if(root ==null) return;
        Stack<TreeNode> stack = new Stack<>();
        Stack<TreeNode> stack2 = new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = stack.pop();
            stack2.push(node);
            if (node.left!=null) stack.push(node.left);
            if (node.right!=null) stack.push(node.right);
        }
        while(!stack2.isEmpty()){
            TreeNode node1 =stack2.pop();
            System.out.println(node1.data);
        }


    }
//层序遍历
    public void bfs(TreeNode root){
        if (root==null) return;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while(!queue.isEmpty()){
            TreeNode node = queue.poll();
            System.out.println(node.data);
            if (node.left!=null) queue.add(node.left);
            if (node.right!=null) queue.add(node.right);
        }



    }

}



//二叉树的基本概念:左子树,右子树,父节点,子节点,树的深度(从上到下的所有节点数-1)

    //(二叉)树的(每个)节点  类
    class TreeNode {
        public int data;
        public TreeNode left;
        public TreeNode right;

        public TreeNode(int data){
            this.data=data;
        }
    }

最后附上二叉树的一些基础知识

节点的度: 一个节点含有的子树的个数称为该节点的度,或者正常情况下可以说是该节点含有的子节点即可。如上图,T 节点的度为4
树的度: 一颗树中,最大的节点的度称为树的度。如上图,该树的度为4
叶子节点或终端节点: 度为0的节点称为叶子节点。T4、T11、T21、T22、T31、T32、T33为叶子节点
父节点: 若一个节点含有子节点,则这个节点称为其子节点的父节点。如上图,T 节点是 T4 节点的父节点
子节点: 一个节点含有的子树的根节点称为该节点的子节点。如上图,T4 节点是 T 节点的子节点
根节点: 一颗树中,没有双亲节点的节点称为根节点。如上图,T 节点为根节点
节点的层次: 从根开始定义,根为第1层,根的子节点为第二层,以此类推。如上图,该树有3层
节点的深度: 某节点层次是第几层,则它的深度是多少。如上图,T 节点深度为1,T1 节点深度为2
树的高度: 树中节点的最大层次。如上图,树的高度为3
非终端节点或分支节点: 度不为0的节点。如上图,T、T1、T2、T3 为分支节点
兄弟节点: 父亲节点相同的节点互称为兄弟节点。如上图,T1、T2、T3、T4 互称为兄弟节点
堂兄弟节点: 双亲在同一层次的节点互称为堂兄弟节点。如上图,T11、T21 互称为堂兄弟节点
节点的祖先: 从根节点到该节点所经过分支上的所有节点都称为该节点的祖先。如上图,T、T1 节点都为 T11 节点的祖先
子孙: 以某节点为根的子树中,任意节点都称为该节点的子孙。如上图,该树中除 T 节点其它节点都是 T 节点的子孙
森林: 由 m(m>=0)棵互不相交的树的集合称为森林。
 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值