二叉树

1.简述

  二叉树是n(n>=0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树组成

  二叉树的定义

  • 每个节点最多有两个子节点的树称为二叉树。

  二叉树的特点

  • 每个节点最多有两个子树(注意:是最多有,而不是只有)。
  • 左子树和右子树是有次序的,不能任意颠倒。
  • 即使某个节点只有一个子树,也要区分是左子树还是右子树。

  二叉树的五种基本形态

  • 空二叉树。
  • 只有一个根节点。
  • 根节点只有左子树。
  • 根节点只有右子树。
  • 根节点既有左子树又有右子树。

  特殊的二叉树

  • 斜树:所有的节点都在一个方向(节点全在左边或右边)。
  • 满二叉树:所有叶子在同一层上。
  • 完全二叉树:若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。

  二叉树的性质

  • 在二叉树的第i层上至多有 2^{i - 1} 2i1 个结点。
  • 深度为k的二叉树至多有 2^k - 1 2k1 个节点。

2.二叉树的存储结构

  二叉树同样有链表存储和数组存储二种方式。

  使用数组存储时,数组arr[0]不存储任何结点。对于二叉树任意结点arr[i],其左子树为arr[2] ,右子树为arr[2 + 1]。如果是完全二叉树,那么其所有的结点都刚好可以存储在数组中,并且没有浪费任何存储空间。但如果不是完全二叉树,如上图所示,arr[5] 就浪费了。

3.二叉树的实现

(1)二叉树数组实现

public class Test {
    public static void main(String[] args) {
        ArrayBinaryTree<String> binTree = new ArrayBinaryTree<String>(5, "1");
        binTree.addLeft(0, "2");
        binTree.addRight(0, "3");
        binTree.addLeft(1, "4");
        binTree.addRight(1, "5");
        binTree.addLeft(2, "6");
        binTree.addRight(2, "7");
        System.out.println(binTree);
        System.out.println("====前序遍历====");
        binTree.preOrder(0);
        System.out.println();
        System.out.println("====中序遍历====");
        binTree.inOrder(0);
        System.out.println();
        System.out.println("====后序遍历====");
        binTree.postOrder(0);
        System.out.println();
    }
}

/**数组实现二叉树
 */
class ArrayBinaryTree<T>{
    private T[] data;//存储树的所有节点
    private int deep;//树的深度
    private int size;//数组大小
    private static final int DEFAULT_DEEP = 5; // 树的默认深度
    
    /**默认的深度来创建二叉树
     */
    @SuppressWarnings("unchecked")
    public ArrayBinaryTree() {
        this.deep = DEFAULT_DEEP;
        this.size = (int) Math.pow(2, deep) - 1;//返回第一个参数的第二个参数次幂的值
        this.data = (T[])new Object[size];
    }
    /**指定深度来创建二叉树
     */
    @SuppressWarnings("unchecked")
    public ArrayBinaryTree(int deep) {
        this.deep = deep;
        this.size = (int) Math.pow(2, deep) - 1;
        data = (T[])new Object[size];
    }
    /**指定深度,按照根节点创建二叉树
     */
    @SuppressWarnings("unchecked")
    public ArrayBinaryTree(int deep, T data) {
        this.deep = deep;
        this.size = (int) Math.pow(2, deep) - 1;
        this.data = (T[])new Object[size];
        this.data[0] = data;
    }
    
    /**指定节点添加左子节点。
     */
    public void addLeft(int index, T data){
        if (this.data[index] == null)
            throw new RuntimeException("根节点为空,无法添加子节点");
        expand(2 * index + 1);
        this.data[2 * index + 1] = data; //添加左子节点
    }
    
    /**指定节点添加右子节点。
     */
    public void addRight(int index, T data){
        if (this.data[index] == null)
            throw new RuntimeException("根节点为空,无法添加子节点");
        expand(2 * index + 2);
        this.data[2 * index + 2] = data; //添加右子节点
    }
    
    /**检测是否超出数组长度,是的话根据当前数组大小扩容2倍,但是当前位置不能超出扩容后的数组
     */
    private void expand(int index){
        if(index > this.size){
            int size = this.data.length * 2;
            if(size < index)
                throw new RuntimeException("数组越界,无法添加子节点");
            this.size = size;
            this.data = Arrays.copyOf(this.data, size);
        }
    }
    
    /** 二叉树的前序递归遍历
     */
    public void preOrder(int index) {
        if (this.data == null || this.data.length == 0 || this.data[index] == null)
            return;
        System.out.print(this.data[index]+"	");
        
        // 向左递归遍历
        if (2 * index + 1 < this.data.length)
            this.preOrder(2 * index + 1);
        
        // 向右递归遍历
        if (2 * index + 2 < this.data.length)
            this.preOrder(2 * index + 2);
    }
    
    /** 二叉树的中序递归遍历
     */
    public void inOrder(int index) {
        if (this.data == null || this.data.length == 0 || this.data[index] == null)
            return;
        // 遍历左子树
        if (2 * index + 1 < this.data.length)
            this.inOrder(2 * index + 1);
        
        System.out.print(this.data[index]+"	");
        
        // 遍历右子树
        if (2 * index + 2 < this.data.length)
            this.inOrder(2 * index + 2);
    }
    
    /** 二叉树的后序递归遍历
     */
    public void postOrder(int index) {
        if (this.data == null || this.data.length == 0 || this.data[index] == null)
            return;
        // 遍历左子树
        if (2 * index + 1 < this.data.length)
            this.inOrder(2 * index + 1);
        
        // 遍历右子树
        if (2 * index + 2 < this.data.length)
            this.inOrder(2 * index + 2);
        System.out.print(this.data[index]+"	");
    }
    
    /**打印数组
     */
    public String toString() {
        return Arrays.toString(this.data);
    }
}
View Code

(2)二叉树链表实现

public class Test {
    public static void main(String[] args) {
        Integer[] array = {1,2,3,4,5,6,7,8};
        BinaryTree<Integer> bt = new BinaryTree<Integer>(array);
        System.out.println("树的高度:"+ bt.height(bt.getRoot()));
        System.out.println("节点的个数:" + bt.size(bt.getRoot()));
        System.out.println("======递归先序遍历=====");
        bt.preOrder(bt.getRoot());
        System.out.println();
        System.out.println("======非递归先序遍历=====");
        bt.nonRecPreOrder(bt.getRoot());
        System.out.println(); 
        System.out.println("======递归中序遍历=====");
        bt.inOrder(bt.getRoot());
        System.out.println();
        System.out.println("======非递归中序遍历=====");
        bt.nonRecInOrder(bt.getRoot());
        System.out.println();
        System.out.println("======递归后序遍历=====");
        bt.postOrder(bt.getRoot());
        System.out.println();
        System.out.println("======非递归后序遍历=====");
        bt.nonRecPostOrder(bt.getRoot());
        System.out.println();
        System.out.println("======层次遍历=====");
        bt.levelOrder(bt.getRoot());
    }
}

class BinaryTree<E>{
    /**二叉树节点类
     */
    class Node<T>{
        /**构造一个新节点
         */
        public Node(){}
        public Node(T data) {
            this.data = data;
        }
        T data;            //节点数据
        Node<T> left;    //左节点
        Node<T> right;    //右节点
        public T getData() {
            return data;
        }
        public void setData(T data) {
            this.data = data;
        }
        public Node<T> getLeft() {
            return left;
        }
        public void setLeft(Node<T> left) {
            this.left = left;
        }
        public Node<T> getRight() {
            return right;
        }
        public void setRight(Node<T> right) {
            this.right = right;
        }
    }
    
    //二叉树的根节点    
    private Node<E> root;
    //二叉树节点的链式结构
    private List<Node<E>> nodeList = null;
    
    /**默认构造函数
     */
    public BinaryTree(){}
    /**创建根节点构造函数
     */
    public BinaryTree(Node<E> root){
        this.root = root;
    }
    /**数组转化为二叉树构造函数
     */
    public BinaryTree(E[] array){
        nodeList = new LinkedList<Node<E>>();
        //将数组中的元素依次转换为Node节点,存放于链表中
        for(int i=0; i< array.length; i++)
            nodeList.add(new Node<E>(array[i]));
        //对前(array.length / 2 - 1)个父节点,按照父节点与孩子节点的数字关系建立完全二叉树
        //对完全二叉树,按从上到下,从左到右的顺序依次编号0,1,2,3....N,则i>0的节点,其左孩子为(2*i+1),
        //其右孩子为(2*i+2)
        for(int j = 0; j < (array.length / 2 - 1); j++){
            //左孩子
            nodeList.get(j).setLeft(nodeList.get(2 * j + 1));
            //右孩子
            nodeList.get(j).setRight(nodeList.get(2 * j + 2));
        }
        //最后一个父节点:因为最后一个父节点可能没有右孩子,所以单独处理
        int index = array.length/2 -1;
        //左孩子
        nodeList.get(index).setLeft(nodeList.get(2 * index + 1));
        //右孩子:如果数组的长度为奇数才有右孩子
        if(array.length % 2 == 1)
            nodeList.get(index).setRight(nodeList.get(2 * index + 2));
        root = nodeList.get(0); //设置根节点
    }
    
    /**获取根节点
     */
    public Node<E> getRoot(){
        return root;
    }
    
    /**获取树的高度
     */
    public int height(Node<E> node){
        if(node == null){
            return 0;
        }else{
            int i = height(node.getLeft());
            int j = height(node.getRight());
            return (i < j) ? (j+1) : (i+1);
        }
    }
    
    /**获取节点的个数
     */
    public int size(Node<E> node){
        if(node == null){
            return 0;
        }else{
            return 1 + size(node.getLeft()) + size(node.getRight());
        }
    }
    
    /**递归实现先序遍历
     */
    public void preOrder(Node<E> node){
        if(node != null){
            System.out.print(node.getData() + " ");
            preOrder(node.getLeft());
            preOrder(node.getRight());
        }
    }
    
      /**非递归实现先序遍历
       */
    public void nonRecPreOrder(Node<E> node){
        Stack<Node<E>> nodeStack = new Stack<Node<E>>();
        Node<E> nodeTemp = node;//nodeTemp作为遍历指针
        while(nodeTemp != null || !nodeStack.isEmpty()){//当nodeTemp非空或栈非空时循环
            if(nodeTemp != null){//根指针非空,遍历左子树
                nodeStack.push(nodeTemp);//根指针进栈
                System.out.print(nodeStack.peek().getData() + " ");//根指针退栈,访问根节点
                nodeTemp = nodeTemp.getLeft();//每遇到非空二叉树先向左走
            }else{//再向右子树走
                nodeTemp = nodeStack.pop();
                nodeTemp = nodeTemp.getRight();
            }
        }
    }
    
    /**递归实现中序遍历
     */
    public void inOrder(Node<E> node){
        if(node != null){
            inOrder(node.getLeft());
            System.out.print(node.getData() + " ");
            inOrder(node.getRight());
        }
    }
 
    /**非递归实现中序遍历
     */
    public void nonRecInOrder(Node<E> node){
        Stack<Node<E>> nodeStack = new Stack<Node<E>>();
        Node<E> nodeTemp = node;//nodeTemp作为遍历指针
        while(nodeTemp != null || !nodeStack.isEmpty()){//当nodeTemp非空或栈非空时循环
            if(nodeTemp != null){//根指针非空,遍历左子树
                nodeStack.push(nodeTemp);//根指针进栈
                nodeTemp = nodeTemp.getLeft();//每遇到非空二叉树先向左走
            }else{
                nodeTemp = nodeStack.pop();//根指针退栈,访问根节点
                System.out.print(nodeTemp.getData() +" ");
                nodeTemp = nodeTemp.getRight();//再向右子树走
            }
        }
    }
 
    /**递归实现后序遍历
     */
    public void postOrder(Node<E> node){
        if(node != null){
            postOrder(node.getLeft());
            postOrder(node.getRight());
            System.out.print(node.getData() + " ");
        }
    }
 
    /**非递归实现后序遍历
     */
    public void nonRecPostOrder(Node<E> node){
        Stack<Node<E>> nodeStack = new Stack<Node<E>>();
        Node<E> nodeTemp = node;//nodeTemp作为遍历指针
        Node<E> preNode = null;//表示最近一次访问的节点
        while(nodeTemp != null || !nodeStack.isEmpty()){//当nodeTemp非空或栈非空时循环
            while(nodeTemp != null){//一直向左走,遍历左子树
                nodeStack.push(nodeTemp);
                nodeTemp = nodeTemp.getLeft();
            }
            nodeTemp = nodeStack.peek();
            if(nodeTemp.getRight()==null || nodeTemp.getRight() == preNode){//右子树为空或右子树已被访问时,该节点出栈
                nodeTemp = nodeStack.pop();
                System.out.print(nodeTemp.getData()+" ");
                preNode = nodeTemp;//将该节点赋值给最近一个访问节点
                nodeTemp = null;//此处很重要,将刚出栈节点设置为空,对应于while循环的条件之一,否则陷入死循环
            }else{
                nodeTemp = nodeTemp.getRight();//遍历右子树
            }
        }
    }
 
    /**层次遍历
     */
    public void levelOrder(Node<E> root){
        Queue<Node<E>> nodeQueue = new LinkedList<Node<E>>();
        Node<E> node = null;
        nodeQueue.add(root);//将根节点入队
        while(!nodeQueue.isEmpty()){  //队列不空循环
            node = nodeQueue.peek();
            System.out.print(node.getData()+" ");
            nodeQueue.poll();//队头元素出队
            if(node.getLeft() != null){//左子树不空,则左子树入队列
                nodeQueue.add(node.getLeft());
            }
            if(node.getRight() != null){//右子树不空,则右子树入队列
                nodeQueue.add(node.getRight());
            }
        }
    }
}
View Code

(3)二叉搜索树实现

public class Test {
    public static void main(String[] args) {
        Integer[] array = {1,2,3,4,5,6,7,8};
        BinaryTree<Integer> bt = new BinaryTree<Integer>(array);
        System.out.println("获取树的指定元素:"+ bt.find(bt.getRoot(), 7));
        System.out.println("树的最大元素:"+ bt.findMax(bt.getRoot()));
        System.out.println("树的最小元素:"+ bt.findMin(bt.getRoot()));
        System.out.println("树的高度:"+ bt.height(bt.getRoot()));
        System.out.println("节点的个数:" + bt.size(bt.getRoot()));
        System.out.println("删除指定元素:" + bt.delete(bt.getRoot(), 7));
        System.out.println("======递归先序遍历=====");
        bt.preOrder(bt.getRoot());
        System.out.println();
        System.out.println("======非递归先序遍历=====");
        bt.nonRecPreOrder(bt.getRoot());
        System.out.println(); 
        System.out.println("======递归中序遍历=====");
        bt.inOrder(bt.getRoot());
        System.out.println();
        System.out.println("======非递归中序遍历=====");
        bt.nonRecInOrder(bt.getRoot());
        System.out.println();
        System.out.println("======递归后序遍历=====");
        bt.postOrder(bt.getRoot());
        System.out.println();
        System.out.println("======非递归后序遍历=====");
        bt.nonRecPostOrder(bt.getRoot());
        System.out.println();
        System.out.println("======层次遍历=====");
        bt.levelOrder(bt.getRoot());
    }
}

class BinaryTree<E extends Comparable<E>>{
    /**二叉树节点类
     */
    class Node<T extends Comparable<T>>{
        /**构造一个新节点
         */
        public Node(){}
        public Node(T data) {
            this.data = data;
        }
        T data;            //节点数据
        Node<T> left;    //左节点
        Node<T> right;    //右节点
        public T getData() {
            return data;
        }
        public void setData(T data) {
            this.data = data;
        }
        public Node<T> getLeft() {
            return left;
        }
        public void setLeft(Node<T> left) {
            this.left = left;
        }
        public Node<T> getRight() {
            return right;
        }
        public void setRight(Node<T> right) {
            this.right = right;
        }
    }
    
    //二叉树的根节点    
    private Node<E> root;
    
    /**默认构造函数
     */
    public BinaryTree(){}
    /**创建根节点构造函数
     */
    public BinaryTree(Node<E> root){
        this.root = root;
    }
    /**数组转化为二叉树构造函数
     */
    public BinaryTree(E[] array){
        //将数组中的元素依次转换为Node节点
        for(int i=0; i< array.length; i++)
            insert(array[i]);
    }
    
    /**判断节点是否为空
     */
    private boolean isEmpty() {
        return root == null;
    }
    
    /**元素比较方法
     */
    private int compare(Node<E> node, E value) {
        return value.compareTo(node.getData());
    }
    
    /**插入元素到输中
     */
    void insert(E value) {
        if (value == null) {
            return;
        }
        root = insert(root, value);
    }
    
    /**插入元素到指定节点(递归实现)
     */
    private Node<E> insert(Node<E> node, E value) {
        if (node == null) {//节点为空,则创建节点
            return new Node<>(value);
        } else {
            if (compare(node, value) < 0)//插入的元素值小于当前节点的值,则向左节点添加
                node.setLeft(insert(node.getLeft(), value));
            else if (compare(node, value) > 0)//插入的元素值大于当前节点的值,则向右节点添加
                node.setRight(insert(node.getRight(), value));
        }
        return node;
    }
    
    /**获取根节点
     */
    public Node<E> getRoot(){
        return root;
    }
    
    /**获取指定元素(递归实现)
     */
    public Node<E> find(Node<E> node, E value) {
        if(node == null)return null;
        if (compare(node, value) < 0)
            return find(node.getLeft(), value);
        else if (compare(node, value) > 0)
            return find(node.getRight(), value);
        else
            return node;
    }
    
    /**获取指定元素(非递归实现)
     */
    public Node<E> findIter(E value) {
        Node<E> current = root;
        while (current != null) {
            if (compare(current, value) < 0)
                current = current.getLeft();
            else if (compare(current, value) > 0)
                current = current.getRight();
            else
                return current;
        }
        return null;
    }
    
    /**获取最大元素(递归实现)
     */
    public E findMax(Node<E> node) {
        Node<E> temp = node;
        while (temp.getRight() != null)
            temp = temp.getRight();
        return temp.getData();
    }
    
    /**获取最小元素(递归实现)
     */
    public E findMin(Node<E> node) {
        Node<E> temp = node;
        while (temp.getLeft() != null)
            temp = temp.getLeft();
        return temp.getData();
    }
    
    /**获取树的高度(递归实现)
     */
    public int height(Node<E> node){
        if(node == null){
            return 0;
        }else{
            int i = height(node.getLeft());
            int j = height(node.getRight());
            return (i < j) ? (j+1) : (i+1);
        }
    }
    
    /**获取节点的个数
     */
    public int size(Node<E> node){
        if(node == null){
            return 0;
        }else{
            return 1 + size(node.getLeft()) + size(node.getRight());
        }
    }
    
    /**从树中删除指定元素
     */
    public Node<E> delete(Node<E> node, E value) {
        if (node == null)return null;
        if (compare(node, value) < 0)
            node.setLeft(delete(node.getLeft(), value));
        else if (compare(node, value) > 0)
            node.setRight(delete(node.getRight(), value));
        else{
            if (node.getLeft() != null && node.getRight() != null) {
                E temp = findMin(node.getRight());
                node.setData(temp);
                node.setRight(delete(node, temp));
            } else {
                if (node.getLeft() != null)
                    node = node.getLeft();
                else
                    node = node.getRight();
            }
        }
        return node;
    }
    
    /**递归实现先序遍历
     */
    public void preOrder(Node<E> node){
        if(node != null){
            System.out.print(node.getData() + " ");
            preOrder(node.getLeft());
            preOrder(node.getRight());
        }
    }
    
      /**非递归实现先序遍历
       */
    public void nonRecPreOrder(Node<E> node){
        Stack<Node<E>> nodeStack = new Stack<Node<E>>();
        Node<E> nodeTemp = node;//nodeTemp作为遍历指针
        while(nodeTemp != null || !nodeStack.isEmpty()){//当nodeTemp非空或栈非空时循环
            if(nodeTemp != null){//根指针非空,遍历左子树
                nodeStack.push(nodeTemp);//根指针进栈
                System.out.print(nodeStack.peek().getData() + " ");//根指针退栈,访问根节点
                nodeTemp = nodeTemp.getLeft();//每遇到非空二叉树先向左走
            }else{//再向右子树走
                nodeTemp = nodeStack.pop();
                nodeTemp = nodeTemp.getRight();
            }
        }
    }
    
    /**递归实现中序遍历
     */
    public void inOrder(Node<E> node){
        if(node != null){
            inOrder(node.getLeft());
            System.out.print(node.getData() + " ");
            inOrder(node.getRight());
        }
    }
 
    /**非递归实现中序遍历
     */
    public void nonRecInOrder(Node<E> node){
        Stack<Node<E>> nodeStack = new Stack<Node<E>>();
        Node<E> nodeTemp = node;//nodeTemp作为遍历指针
        while(nodeTemp != null || !nodeStack.isEmpty()){//当nodeTemp非空或栈非空时循环
            if(nodeTemp != null){//根指针非空,遍历左子树
                nodeStack.push(nodeTemp);//根指针进栈
                nodeTemp = nodeTemp.getLeft();//每遇到非空二叉树先向左走
            }else{
                nodeTemp = nodeStack.pop();//根指针退栈,访问根节点
                System.out.print(nodeTemp.getData() +" ");
                nodeTemp = nodeTemp.getRight();//再向右子树走
            }
        }
    }
 
    /**递归实现后序遍历
     */
    public void postOrder(Node<E> node){
        if(node != null){
            postOrder(node.getLeft());
            postOrder(node.getRight());
            System.out.print(node.getData() + " ");
        }
    }
 
    /**非递归实现后序遍历
     */
    public void nonRecPostOrder(Node<E> node){
        Stack<Node<E>> nodeStack = new Stack<Node<E>>();
        Node<E> nodeTemp = node;//nodeTemp作为遍历指针
        Node<E> preNode = null;//表示最近一次访问的节点
        while(nodeTemp != null || !nodeStack.isEmpty()){//当nodeTemp非空或栈非空时循环
            while(nodeTemp != null){//一直向左走,遍历左子树
                nodeStack.push(nodeTemp);
                nodeTemp = nodeTemp.getLeft();
            }
            nodeTemp = nodeStack.peek();
            if(nodeTemp.getRight()==null || nodeTemp.getRight() == preNode){//右子树为空或右子树已被访问时,该节点出栈
                nodeTemp = nodeStack.pop();
                System.out.print(nodeTemp.getData()+" ");
                preNode = nodeTemp;//将该节点赋值给最近一个访问节点
                nodeTemp = null;//此处很重要,将刚出栈节点设置为空,对应于while循环的条件之一,否则陷入死循环
            }else{
                nodeTemp = nodeTemp.getRight();//遍历右子树
            }
        }
    }
 
    /**层次遍历
     */
    public void levelOrder(Node<E> root){
        Queue<Node<E>> nodeQueue = new LinkedList<Node<E>>();
        Node<E> node = null;
        nodeQueue.add(root);//将根节点入队
        while(!nodeQueue.isEmpty()){  //队列不空循环
            node = nodeQueue.peek();
            System.out.print(node.getData()+" ");
            nodeQueue.poll();//队头元素出队
            if(node.getLeft() != null){//左子树不空,则左子树入队列
                nodeQueue.add(node.getLeft());
            }
            if(node.getRight() != null){//右子树不空,则右子树入队列
                nodeQueue.add(node.getRight());
            }
        }
    }
}
View Code
原文地址:https://www.cnblogs.com/bl123/p/14191863.html