【数据结构】java实现二叉树

二叉树是一种常见的树状数据结构,它由一组节点组成,其中每个节点最多有两个子节点:一个左子节点和一个右子节点。二叉树的特性以及其在数学上的联系使其成为许多算法和数据结构中的重要概念。

二叉树的相关概念

  1. 根节点:二叉树的根节点是整个树的起点,它没有父节点。

  2. 子节点:每个节点可以有最多两个子节点,一个左子节点和一个右子节点。

  3. 叶子节点:叶子节点是没有子节点的节点,也称为终端节点。

  4. :节点的度表示该节点拥有的子节点个数。

  5. 深度:节点的深度表示从根节点到该节点的路径长度。

  6. 高度:二叉树的高度表示树中任意节点的最大深度。

  7. 父节点:一个节点的父节点是其直接上级节点。

  8. 祖先节点:一个节点的祖先节点是其在路径上的任意上级节点。

  9. 子孙节点:一个节点的子孙节点是其在路径上的任意下级节点。

  10. 节点的顺序:二叉树中节点的顺序分为前序遍历(根-左-右)、中序遍历(左-根-右)和后序遍历(左-右-根)。

二叉树的java实现

定义二叉树节点类

注意下面代码中使用到的栈和队列是用单链表模拟的,
如需使用代码请替换为Stack、LinkedList。

public class TreeNode<T> {
    private T data;
    private TreeNode leftChild;
    private TreeNode rightChild;
    public TreeNode(T data) {
        this.data = data;
    }

    public TreeNode() {
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public TreeNode getLeftChild() {
        return leftChild;
    }

    public void setLeftChild(TreeNode leftChild) {
        this.leftChild = leftChild;
    }

    public TreeNode getRightChild() {
        return rightChild;
    }

    public void setRightChild(TreeNode rightChild) {
        this.rightChild = rightChild;
    }
}

创建二叉树

public class BinaryTree<T> {
    private TreeNode<T> root;
    public BinaryTree(T data) {
        this.root = new TreeNode<>(data);
    }
    public BinaryTree() {}
    public BinaryTree(LinkListQueue<T> listQueue) {
        this.root = createBinaryTree(listQueue);
    }
    public TreeNode<T> getRoot() {
        return root;
    }
    //    层序遍历单链表队列创建二叉树方法
    public TreeNode createBinaryTree(LinkListQueue<T> listQueue) {
        if(listQueue==null||listQueue.isEmpty()){
            return null;
        }
        LinkListQueue<TreeNode> queue = new LinkListQueue<>();
        root = new TreeNode<>(listQueue.poll());
        queue.offer(root);
        while (!queue.isEmpty()){
            TreeNode poll = queue.poll();
            if(!listQueue.isEmpty()){
                poll.setLeftChild(new TreeNode<>(listQueue.poll()));
                queue.offer(poll.getLeftChild());
            }
            if(!listQueue.isEmpty()){
                poll.setRightChild(new TreeNode<>(listQueue.poll()));
                queue.offer(poll.getRightChild());
            }
        }
        return root;
    }
}

二叉树的常用操作和方法

  1. 遍历二叉树
    • 前序遍历
// 递归实现
public void preorderTraversal(TreeNode root){
    if(root==null){
        return;
    }
    System.out.print(root.getData()+" ");
    preorderTraversal(root.getLeftChild());
    preorderTraversal(root.getRightChild());
}
// 非递归实现,手动压栈
public void preorderTraversal1(TreeNode root){
    LinkListStack<TreeNode> stack = new LinkListStack<>();
    if (root!= null){
        stack.push(root);
        while (!stack.isEmpty()){
            root = stack.pop();
            System.out.print(root.getData() + " ");
            // 先把右子树压栈
            if (root.getRightChild() != null){
                stack.push(root.getRightChild());
            }
            // 再把左子树压栈
            if(root.getLeftChild() != null){
                stack.push(root.getLeftChild());
            }
        }
    }
    System.out.println();
}
  • 中序遍历
// 递归实现
public void inorderTraversal(TreeNode root){
    if(root==null){
        return;
    }
    inorderTraversal(root.getLeftChild());
    System.out.print(root.getData()+" ");
    inorderTraversal(root.getRightChild());
}
// 非递归实现,手动压栈
public void inorderTraversal1(TreeNode root){
    LinkListStack<TreeNode> stack = new LinkListStack<>();
    if (root != null){
        while (!stack.isEmpty() || root != null){
        	// 先把当前节点的子孙左子树全部压栈
            if (root != null) {
            	stack.push(root);
            	root = root.getLeftChild();
            } else {
            	// 打印完左子树再处理右子树
            	root = stack.pop();
            	System.out.print(root.getData() + " ");
            	root = root.getRightChild();
            }
        }
    }
    System.out.println();
}
  • 后序遍历
// 递归实现
public void postorderTraversal(TreeNode root){
    if(root==null){
        return;
    }
    postorderTraversal(root.getLeftChild());
    postorderTraversal(root.getRightChild());
    System.out.print(root.getData()+" ");
}
// 非递归实现,手动压栈
public void postorderTraversal1(TreeNode root){
    LinkListStack<TreeNode> stack1 = new LinkListStack<>();
    LinkListStack<TreeNode> stack2 = new LinkListStack<>();
    TreeNode node = root;
    if (root != null){
        stack1.push(node);
        while (!stack1.isEmpty()){
            node = stack1.pop();
            stack2.push(node);
            if(node.getLeftChild()!=null){
                stack1.push(node.getLeftChild());
            }
            if(node.getRightChild()!=null){
                stack1.push(node.getRightChild());
            }
        }
        while (!stack2.isEmpty()){
            System.out.print(stack2.pop().getData() + " ");
        }
    }
    System.out.println();
}
  • 层序遍历(广度优先)
public void sequenceTraversal(TreeNode root){
    LinkListQueue<TreeNode> queue = new LinkListQueue<>();
    TreeNode node = root;
    queue.offer(node);
    while (!queue.isEmpty()){
        node = queue.poll();
        System.out.print(node.getData()+" ");
        if(node.getLeftChild()!=null){
            queue.offer(node.getLeftChild());
        }
        if(node.getRightChild()!=null) {
            queue.offer(node.getRightChild());
        }
    }
}
  1. 求最深高度
//    求二叉树的高度
public int getHeight(TreeNode root) {
    int lefth, righth;
    if (root == null) {
        return 0;
    } else {
        lefth = getHeight(root.getLeftChild());
        righth = getHeight(root.getRightChild());
//            return Math.max(lefth,righth)+1;
        return 1 + (lefth > righth ? lefth : righth);
    }
}
  1. 求最大宽度
public int getWidth(TreeNode root) {
    if (root == null) {
        return 0;
    }
    LinkListQueue<TreeNode> queue = new LinkListQueue<>();
    TreeNode node = root;
    queue.offer(node);
    HashMap<TreeNode, Integer> map = new HashMap<>();
    map.put(node, 1);
    int curLevel = 1;   // 当前层级
    int curNodeLevel = 1;   // 当前节点层级
    int curLevelNodes = 0;  // 当前层级的节点数
    int max = Integer.MIN_VALUE;
    while (!queue.isEmpty()) {
        node = queue.poll();
        curNodeLevel = map.get(node);
        if (curNodeLevel == curLevel){
        	// 如果当前节点层级等于当前层级 当前层级节点数就+1
            curLevelNodes++;
        } else {
        	// 说明当前层级已经遍历完了 比较最大节点数 层级+1 当前层级节点数重置
            max = max > curLevelNodes? max : curLevelNodes;
            curLevel++;
            curLevelNodes = 1;
        }
        if (node.getLeftChild() != null) {
            map.put(node.getLeftChild(), curNodeLevel+1);
            queue.offer(node.getLeftChild());
        }
        if (node.getRightChild() != null) {
            map.put(node.getRightChild(), curNodeLevel+1);
            queue.offer(node.getRightChild());
        }
    }
    return max > curLevelNodes? max : curLevelNodes;
}
  1. 节点个数
public int numOfNodes(TreeNode root) {
    int c, l, r;
    if (root == null) {
        return 0;
    }
    c = 1;
    l = numOfNodes(root.getLeftChild());
    r = numOfNodes(root.getRightChild());
    return c + l + r;
}
  1. 删除节点
    这部分代码有一个bug就是如果待删除节点的左子树有左右子树 子树的子树又有左右子树的话就会丢失掉一颗左左左子树
public TreeNode deleteTreeNode(TreeNode root, T data) {
    if (root == null) {
        return null;
    }
    if (root.getData().equals(data)){
        if (root.getLeftChild() == null && root.getRightChild() == null) {
            // 如果待删除节点没有孩子就直接返回null
            return null;
        } else if (root.getLeftChild() != null) {
            // 如果待删除节点有左子树
            if (root.getLeftChild().getLeftChild() != null && root.getLeftChild().getRightChild() != null){
                root.getLeftChild().getLeftChild().setLeftChild(root.getLeftChild().getRightChild());
                root.getLeftChild().setRightChild(root.getRightChild());
            } else if (root.getLeftChild().getLeftChild() == null) {
                root.getLeftChild().setLeftChild(root.getLeftChild().getRightChild());
            }
            return root.getLeftChild();
        } else {
            // 如果待删除节点没有左子树那么右子树直接顶替该节点
            return root.getRightChild();
        }
    }
    // 向左遍历子树
    root.setLeftChild(deleteTreeNode(root.getLeftChild(), data));
    // 向右遍历子树
    root.setRightChild(deleteTreeNode(root.getRightChild(), data));
    return root;
}
  1. 判断是不是完全二叉树
public boolean isCompleteBinaryTree(TreeNode root){
    if(root==null) return true;
    LinkListQueue<TreeNode> queue = new LinkListQueue<>();
    // 是否遇到左左孩子不全的节点
    boolean decide = false;
    TreeNode left = null;
    TreeNode right = null;
    queue.offer(root);
    while (!queue.isEmpty()){
        root = queue.poll();
        left = root.getLeftChild();
        right = root.getRightChild();
        if ((left==null && right!=null) || (decide && (left!=null || right!=null))){
            // 有右无左或有左无右剩下不全是叶子节点,不是满二叉树
            return false;
        }
        if(left!=null){
            queue.offer(left);
        }
        if(right!=null){
            queue.offer(right);
        }
        if(left==null || right==null){
            decide = true;
        }
    }
    return true;
}
  1. 判断是不是搜素二叉树
public boolean isSearchBinaryTree(TreeNode root){
    if (root != null){
        int preValue = Integer.MIN_VALUE;
        LinkListStack<TreeNode> stack = new LinkListStack<>();
        while (!stack.isEmpty() || root!=null){
            if(root!=null){
                stack.push(root);
                root = root.getLeftChild();
            } else {
                root = stack.pop();
                if ((int)root.getData() <= preValue) {
                    return false;
                }else {
                    preValue = (int)root.getData();
                }
                root = root.getRightChild();
            }
        }
    }
    return true;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值