Java数据结构二叉树

本文详细介绍了二叉树的概念,包括其结构特征、特殊类型的二叉树(满二叉树和完全二叉树)、性质、存储方式(顺序和链式),以及前序、中序和后序遍历方法。还探讨了如何计算节点数、叶子结点数、二叉树的高度和判断是否为完全二叉树的方法。
摘要由CSDN通过智能技术生成

概念

一棵二叉树是结点的一个有限集合,该集合:
1. 或者为空
2. 或者是由一个根节点加上两棵别称为左子树和右子树的二叉树组成。

从上图可以看出:
1. 二叉树不存在度大于2的结点
2. 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树
注意:对于任意的二叉树都是由以下几种情况复合而成的:

大自然的奇观:

两种特殊的二叉树
 

1. 满二叉树:
如果每层的结点数都达到最大值,则这棵二叉树就是满二叉树。也就是说,如果一棵
二叉树的层数为K,且结点总数是 ,则它就是满二叉树。

2. 完全二叉树:
从上到下,从左到右依次。

要注意的是满二叉树是一种特殊的完全二叉树。
 

二叉树的性质

3. 对任何一棵二叉树, 如果其叶结点个数为 n0, 度为2的非叶结点个数为 n2,则有n0=n2+1
度为0的节点会比度为2的节点多一个

5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0开始编号,则对于序号为i的结点有:
若i>0,双亲序号:(i-1)/2;i=0,i为根结点编号,否则无双亲结点
若2i+1<n,左孩子序号:2i+1,否则无左孩子
若2i+2<n,右孩子序号:2i+2,否则无右孩子

1. 某二叉树共有 399 个结点,其中有 199 个度为 2 的结点,则该二叉树中的叶子结点数为( )
A 不存在这样的二叉树
B 200
C 198
D 199


2.在具有 2n 个结点的完全二叉树中,叶子结点个数为( )
A n
B n+1
C n-1
D n/2


3.一个具有767个节点的完全二叉树,其叶子节点个数为()
A 383
B 384
C 385
D 386


4.一棵完全二叉树的节点数为531个,那么这棵树的高度为( )
A 11
B 10
C 8
D 12


答案:
1.B
2.A
3.B
4.B

二叉树的存储
 

二叉树的存储结构分为:顺序存储和类似于链表的链式存储
顺序存储在下节介绍。
二叉树的链式存储是通过一个一个的节点引用起来的,常见的表示方式有二叉和三叉表示方式,具体如下:

// 孩子表示法
class Node {

int val;
Node left;
// 数据域
// 左孩子的引用,常常代表左孩子为根的整棵左子树
Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
}
// 孩子双亲表示法
class Node {
int val;
Node left;
// 数据域
// 左孩子的引用,常常代表左孩子为根的整棵左子树

Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
Node parent; // 当前节点的根节点
}

孩子双亲表示法后序在平衡树位置介绍,本文采用孩子表示法来构建二叉树。

二叉树的基本操作

二叉树的遍历

下面主要分析前序递归遍历,中序与后序图解类似,可自己动手绘制。

前序遍历结果:1 2 3 4 5 6
中序遍历结果:3 2 1 5 4 6
后序遍历结果:3 1 5 6 4 1


层序遍历

前置说明
 

在学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。由于现在大家对二叉树结构掌握还不够深入,为了降低大家学习成本,此处手动快速创建一棵简单的二叉树,快速进入二叉树操作学习,等二叉树结构了解的差不多时,我们反过头再来研究二叉树真正的创建方式。

public class TestBinaryTree {
    static class TreeNode {
        public char val;
        public TreeNode left;
        public TreeNode right;

        public TreeNode(char val) {
            this.val = val;
        }
    }

    public TreeNode createTree() {
        TreeNode A = new TreeNode('A');
        TreeNode B = new TreeNode('B');
        TreeNode C = new TreeNode('C');
        TreeNode D = new TreeNode('D');
        TreeNode E = new TreeNode('E');
        TreeNode F = new TreeNode('F');
        TreeNode G = new TreeNode('G');
        TreeNode H = new TreeNode('H');

        A.left = B;
        A.right = C;
        B.left = D;
        B.right = E;
        C.left = F;
        C.right = G;
        E.right = H;

        return A;
    }

    // 前序遍历
    void preOrder(TreeNode root) {
        if (root == null) {
            return;
        }
        System.out.print(root.val + " ");
        //递归遍历左子树
        preOrder(root.left);
        //递归遍历右子树
        preOrder(root.right);
    }

    // 中序遍历
    void inOrder(TreeNode root) {
        if (root == null) {
            return;
        }
        inOrder(root.left);
        System.out.print(root.val + " ");
        inOrder(root.right);
    }

    // 后序遍历
    void postOrder(TreeNode root) {
        if (root == null) {
            return;
        }
        postOrder(root.left);
        postOrder(root.right);
        System.out.print(root.val + " ");
    }

}
public class Test {
    public static void main(String[] args) {
        TestBinaryTree testBinaryTree=new TestBinaryTree();
        TestBinaryTree.TreeNode root=testBinaryTree.createTree();

        testBinaryTree.preOrder(root);
        System.out.println();

        testBinaryTree.inOrder(root);
        System.out.println();

        testBinaryTree.postOrder(root);
        System.out.println();
    }
}


注意:上述代码并不是创建二叉树的方式,真正创建二叉树方式后序详解重点讲解。

1.某完全二叉树按层次输出(同一层从左到右)的序列为 ABCDEFGH 。该完全二叉树的前序序列为()
A: ABDHECFG    B: ABCDEFGH    C: HDBEAFCG    D: HDEBFGCA


2.二叉树的先序遍历和中序遍历如下:先序遍历:EFHIGJK;中序遍历:HFIEJKG.则二叉树根结点为()
A: E    B: F    C: G    D: H

上难度:画出这棵树 并且求出后序遍历


3.设一课二叉树的中序遍历序列:badce,后序遍历序列:bdeca,则二叉树前序遍历序列为()
A: adbce    B: decab    C: debac    D: abcde


4.某二叉树的后序遍历序列与中序遍历序列相同,均为 ABCDEF ,则按层次输出(同一层从左到右)的序列为()
A: FEDCBA    B: CBAFED    C: DEFCBA    D: ABCDEF


【参考答案】 1.A    2.A    3.D    4.A

二叉树的基本操作

    //子问题思路
    //获取树中节点的个数(左子树节点个数+右子树节点个数+1=整棵树的节点个数)
    public int size(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int ret = size(root.left) + size(root.right) + 1;
        return ret;
    }

    public static int nodeSize;

    //遍历思路
    public void size2(TreeNode root) {
        if (root == null) {
            return;
        }
        nodeSize++;
        size2(root.left);
        size2(root.right);
    }

    // 获取叶子节点的个数
    //子问题的思路(整颗树的叶子节点个数=左子树的叶子节点+右子树的叶子节点)
    int getLeafNodeCount(TreeNode root) {
        if (root == null) {
            return 0;
        }
        if (root.left == null && root.right == null) {
            return 1;
        }
        return getLeafNodeCount(root.right) + getLeafNodeCount(root.right);
    }

    //遍历思路:以某种方式遍历这棵树,只要发现是叶子就++
    public int leafSize;

    public void getLeafNodeCount2(TreeNode root) {
        if (root == null) {
            return;
        }
        if (root.left == null && root.right == null) {
            leafSize++;
        }
        getLeafNodeCount(root.left);
        getLeafNodeCount(root.right);
    }

    // 获取第K层节点的个数
    int getKLevelNodeCount(TreeNode root, int k) {
        if (root == null) {
            return 0;
        }
        if (k == 1) {
            return 1;
        }
        return getKLevelNodeCount(root.left, k - 1) + getKLevelNodeCount(root.right, k - 1);
    }

    // 获取二叉树的高度(整棵树的高度=Math.max(左树高度+右树高度)+1)
    int getHeight(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);
        return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
    }

    // 检测值为value的元素是否存在
    TreeNode find(TreeNode root, int val) {
        if (root == null) {
            return null;
        }
        if (root.val == val) {
            return root;
        }
        TreeNode ret = find(root.left, val);
        if (ret != null) {
            return ret;
        }
        ret = find(root.right, val);
        if (ret != null) {
            return ret;
        }
        return null;
    }

    //层序遍历
    void levelOrder(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        if (root == null) {
            return;
        }
        queue.offer(root);
        while (!queue.isEmpty()) {
            TreeNode cur = queue.poll();
            System.out.print(cur.val + " ");
            if (cur.left != null) {
                queue.offer(cur.left);
            }
            if (cur.right != null) {
                queue.offer(cur.right);
            }
        }
        System.out.println();
    }

    // 判断一棵树是不是完全二叉树
    boolean isCompleteTree(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        if (root == null) return true;
        queue.offer(root);

        while (!queue.isEmpty()) {
            TreeNode cur = queue.poll();
            if (cur == null) {
                break;
            }
            queue.offer(cur.left);
            queue.offer(cur.right);
        }
        while (!queue.isEmpty()) {
            TreeNode node = queue.peek();
            if (node != null) {
                return false;
            } else {
                queue.poll();
            }
        }
        return true;
    }
}

二叉树是一种常见的数据结构,它由节点组成,每个节点最多有两个子节点:左子节点和右子节点。以下是一个简单的Java实现二叉树的例子: ```java // 定义二叉树节点类 class TreeNode { int val; TreeNode left; TreeNode right; public TreeNode(int val) { this.val = val; this.left = null; this.right = null; } } // 构建二叉树 public class BinaryTree { TreeNode root; public BinaryTree(int val) { this.root = new TreeNode(val); } // 插入节点 public void insert(int val) { TreeNode newNode = new TreeNode(val); if (root == null) { root = newNode; } else { TreeNode current = root; TreeNode parent; while (true) { parent = current; if (val < current.val) { current = current.left; if (current == null) { parent.left = newNode; return; } } else { current = current.right; if (current == null) { parent.right = newNode; return; } } } } } // 先序遍历 public void preOrderTraversal(TreeNode node) { if (node != null) { System.out.print(node.val + " "); preOrderTraversal(node.left); preOrderTraversal(node.right); } } // 中序遍历 public void inOrderTraversal(TreeNode node) { if (node != null) { inOrderTraversal(node.left); System.out.print(node.val + " "); inOrderTraversal(node.right); } } // 后序遍历 public void postOrderTraversal(TreeNode node) { if (node != null) { postOrderTraversal(node.left); postOrderTraversal(node.right); System.out.print(node.val + " "); } } } // 创建二叉树并进行遍历 public class Main { public static void main(String[] args) { BinaryTree binaryTree = new BinaryTree(5); binaryTree.insert(3); binaryTree.insert(7); binaryTree.insert(2); binaryTree.insert(4); binaryTree.insert(6); binaryTree.insert(8); System.out.println("先序遍历结果:"); binaryTree.preOrderTraversal(binaryTree.root); System.out.println(); System.out.println("中序遍历结果:"); binaryTree.inOrderTraversal(binaryTree.root); System.out.println(); System.out.println("后序遍历结果:"); binaryTree.postOrderTraversal(binaryTree.root); System.out.println(); } } ``` 这个例子展示了如何构建一个二叉树,并对其进行先序、中序和后序遍历。你可以根据需要修改节点的值和插入顺序来构建不同的二叉树
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值