二叉树的相关操作(java)

二叉树的相关操作主要包括四种遍历方式(先序,中序,后序)、求二叉树的高度、统计结点个数等等,其中遍历主要有递归和非递归两种实现。

  • 先创建结点类
package btree;

/**
* @author lijing
* @date 2019-03-29-10:24
* @discroption 定义二叉链表的结点类
*/
public class Node {
   Object value; //结点值
   Node leftChild;//左子树的引用
   Node rightChild;//右子树的引用

   public Node() {
   }

   public Node(Object value) {
       this.value = value;
   }

   public Node(Object value, Node leftChild, Node rightChild) {
       this.value = value;
       this.leftChild = leftChild;
       this.rightChild = rightChild;
   }

   @Override
   public String toString() {
       return "Node{" +
               "value=" + value +
               ", leftChild=" + leftChild +
               ", rightChild=" + rightChild +
               '}';
   }
}

  • 二叉树接口
package btree;

/**
* 二叉树接口
* @author Administrator
*
*/
public interface BinaryTree {
   /**
    * 是否空树
    * @return
    */
   public boolean isEmpty();
   /**
    * 树结点数量
    * @return
    */
   public int size();

   /**
    * 获取二叉树的高度
    * @return
    */
   public int getHeight();
   /**
    * 查询指定值的结点
    * @param value
    * @return
    */
   public Node findKey(Object value); // 查找
   /**
    * 前序递归遍历
    */
   public void preOrderTraverse();
   /**
    * 中序遍历递归操作
    */
   public void inOrderTraverse();
   /**
    * 后序遍历递归操作
    */
   public  void postOrderTraverse();
   /**
    * 中序遍历非递归操作
    */
   public void inOrderByStack();
   /**
    *   前序遍历非递归操作
    */
   public  void preOrderByStack();
   /**
    * 后序遍历非递归操作
    */
   public  void postOrderByStack();

   /**
    * 按照层次遍历二叉树
    */
   public void levelOrderByStack();
}
  • 二叉树实现类
package btree;


import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

/**
* @author lijing
* @date 2019-03-29-10:35
* @discroption 二叉树实现类
*/

public class LinkedBinaryTree implements BinaryTree {

  private Node root;//根节点

  public LinkedBinaryTree(Node root) {
      this.root = root;
  }

  public LinkedBinaryTree() {
  }

  @Override
  public boolean isEmpty() {
      //根结点为空说明二叉树为空
      return root == null;
  }

  @Override
  public int size() {
      return this.getSize(this.root);
  }

  private int getSize(Node root) {
      if (root == null) {
          //递归结束条件:根结点为空(这里的根结点是每次访问时的根节点,并不是this.root)
          return 0;
      } else {
          //先得到左子树的元素个数
          int nl = this.getSize(root.leftChild);
          //在得到右子树的元素个数
          int nr = this.getSize(root.rightChild);
          //将左子树和右子树的元素个数相加,再加上根结点
          return nl + nr + 1;
      }
  }

  @Override
  public int getHeight() {
      return this.getHeight(this.root);
  }

  private int getHeight(Node root) {
      if (root == null) {
          //递归结束条件:根结点为空
          return 0;
      } else {
          //先得到左子树的高度
          int nl = this.getHeight(root.leftChild);
          //再得到右子树的高度
          int nr = this.getHeight(root.rightChild);
          //取左右子树中高度比较大的一个,再加上根结点
          return nl > nr ? nl + 1 : nr + 1;
      }
  }

  @Override
  public Node findKey(Object value) {
      return findKey(this.root, value);
  }

  private Node findKey(Node root, Object value) {
      if (root == null) {
          //如果root为空,就直接返回null(递归结束条件)
          return null;
      } else if (root.value.equals(value)) {
          //如果找到value就返回root结点(递归结束条件)
          return root;
      } else {
          //否则就分别查找左子树和右子树
          Node lkey = findKey(root.leftChild, value);
          Node rkey = findKey(root.rightChild, value);
          //如果lkey非空就返回lkey,否则就返回rkey,(包含lkey和rkey都为空的情况,返回null)
          return lkey != null ? lkey : rkey;
      }
  }

  @Override
  public void preOrderTraverse() {
      System.out.print("前序遍历:");
      this.preOrderTraverse(this.root);
      System.out.println();
  }

  private void preOrderTraverse(Node root) {
      if (root != null) {
          //递归结束条件:根结点为空
          //遍历顺序:先输出元素,再遍历左右子树
          System.out.print(root.value + " ");
          this.preOrderTraverse(root.leftChild);
          this.preOrderTraverse(root.rightChild);
      }
  }

  @Override
  public void inOrderTraverse() {
      System.out.print("中序遍历:");
      this.inOrderTraverse(this.root);
      System.out.println();
  }

  private void inOrderTraverse(Node root) {
      if (root != null) {
          //递归结束条件:根结点为空
          //遍历顺序:先遍历左子树,再打印元素,再遍历右子树
          this.inOrderTraverse(root.leftChild);
          System.out.print(root.value + " ");
          this.inOrderTraverse(root.rightChild);
      }
  }

  @Override
  public void postOrderTraverse() {
      System.out.print("后序遍历:");
      this.postOrderTraverse(this.root);
      System.out.println();
  }

  private void postOrderTraverse(Node root) {
      if (root != null) {
          //递归结束条件:根结点为空
          //遍历顺序:先遍历走右子树,再打印元素
          this.postOrderTraverse(root.leftChild);
          this.postOrderTraverse(root.rightChild);
          System.out.print(root.value + " ");
      }
  }

  @Override
  public void inOrderByStack() {
      System.out.print("非递归中序遍历:");
      //创建栈
      Deque<Node> stack = new LinkedList<>();
      Node current = this.root;
      while (current != null || !stack.isEmpty()) {
          //将根结点以及每棵子树的根结点放入栈中,直到遇到一颗没有左孩子的子树为止
          while (current != null) {
              stack.push(current);
              current = current.leftChild;
          }

          //判断如果栈不空,就将栈顶元素取出(此时栈顶元素一定是没有左孩子的)
          //打印结点,然后将当前结点指向右孩子
          if (!stack.isEmpty()) {
              current = stack.pop();
              System.out.print(current.value + " ");
              current = current.rightChild;
          }
      }
      System.out.println();
  }

  @Override
  public void preOrderByStack() {
      System.out.print("非递归前序遍历:");
      //创建栈
      Deque<Node> stack = new LinkedList<>();
      Node current = this.root;
      while (current != null || !stack.isEmpty()) {
          //先输出根结点的值,再将结点放入栈中,知道放入结点的右孩子为空
          while (current != null) {
              System.out.print(current.value + " ");
              stack.push(current);
              current = current.leftChild;
          }
          // 如果栈不空,就让当前结点指向右孩子,经过上面的操作之后,栈顶元素一定是没有左孩子并且被打印过的,
          // 所以只需要处理右孩子即可,如果右孩子不为空则会在下一轮操作中入栈。
          if (!stack.isEmpty()) {
              current = stack.pop().rightChild;
          }
      }
      System.out.println();
  }

  @Override
  public void postOrderByStack() {
      System.out.print("非递归后序遍历:");
      //创建栈
      Deque<Node> stack = new LinkedList<>();
      Node current = this.root;//当前结点
      Node last = null;//指向当前结点的上一个
      while (current != null || !stack.isEmpty()) {
          while (current != null) {
              stack.push(current);
              current = current.leftChild;
          }
          current = stack.peek();//取栈顶元素
          if (current.rightChild == null || current.rightChild == last) {
              //如果没有右孩子或者右孩子被访问过,就访问该结点
              Node node = stack.pop();
              System.out.print(node.value + " ");
              last = current;
              current = null;
          } else {
              //把当前结点设为当前结点的右孩子
              current = current.rightChild;
          }
      }
      System.out.println();
  }

  @Override
  public void levelOrderByStack() {
      System.out.print("层次遍历:");
      //创建队列
      Queue<Node> queue = new LinkedList<>();
      if (root != null) {
          queue.add(this.root);
      }
      while (!queue.isEmpty()) {
          //如果队列非空,就取出队列顶部元素,并将左右孩子入队
          Node node = queue.poll();
          System.out.print(node.value + " ");
          if (node.leftChild != null) {
              queue.add(node.leftChild);
          }
          if (node.rightChild != null) {
              queue.add(node.rightChild);
          }
      }
      System.out.println();
  }
}
  • 测试类
    测试所用到的二叉树如图所示:
    在这里插入图片描述
package btree;

/**
* @author lijing
* @date 2019-03-29-10:26
* @discroption 二叉树测试类
*/
public class Test {
  public static void main(String[] args) {

      //region Description 创建一棵二叉树
      Node node7 = new Node(7);
      Node node6 = new Node(6, null, node7);
      Node node5 = new Node(3);
      Node node4 = new Node(5);
      Node node2 = new Node(4, null, node4);
      Node node3 = new Node(2, node5, node6);
      Node node1 = new Node(1, node2, node3);
      //endregion

      LinkedBinaryTree btree = new LinkedBinaryTree(node1);
      System.out.println("判断是否为空:" + btree.isEmpty());
      btree.preOrderTraverse();
      btree.inOrderTraverse();
      btree.postOrderTraverse();
      System.out.println("二叉树的高度:" + btree.getHeight());
      System.out.println("二叉树的叶子数:" + btree.size());
      System.out.println("找到值为6的结点:" + btree.findKey(6));
      btree.levelOrderByStack();
      btree.inOrderByStack();
      btree.preOrderByStack();
      btree.postOrderByStack();
  }
}
  • 运行结果
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值