二叉树之二叉链表

本文利用java语言模拟二叉树的二叉链表的实现,下面先对二叉树的相关概念作简单介绍:
二叉树:每个结点至多有两颗子树,且子树有左右之分,其次序不能任意颠倒; 基本形态:空、仅有根结点、左子树为空、右子树为空、左右子树均非空;
完全二叉树父子结点序号关系:
* 如果i=1,则结点i为根结点,否则其双亲结点为[i/2];
* 如果2i > n,则结点i无左孩子,否则其左孩子结点为2i;
* 如果2i+1 > n,则结点i无右孩子,否则右孩子结点为2i+1;
二叉链表:结点包含数据域和左右指针(引用)域的链表;

下面主要给出二叉链表的实现:

1. 二叉链表的结点

package org.sky.tree;

/**
 * 二叉链表结点
 * 
 * @author sky
 *
 * @param <E>
 */
public class BinaryTreeNode<E> {
    E element;
    BinaryTreeNode<E> leftChild;
    BinaryTreeNode<E> rightChild;


    public BinaryTreeNode() {
        super();
        this.element = null;
        this.leftChild = null;
        this.rightChild = null;
    }

    public BinaryTreeNode(E element) {
        super();
        this.element = element;
        this.leftChild = null;
        this.rightChild = null;
    }

    public BinaryTreeNode(E element, BinaryTreeNode<E> leftChild,
            BinaryTreeNode<E> rightChild) {
        super();
        this.element = element;
        this.leftChild = leftChild;
        this.rightChild = rightChild;
    }

    public E getElement() {
        return element;
    }
    public void setElement(E element) {
        this.element = element;
    }
    public BinaryTreeNode<E> getLeftChild() {
        return leftChild;
    }
    public void setLeftChild(BinaryTreeNode<E> leftChild) {
        this.leftChild = leftChild;
    }
    public BinaryTreeNode<E> getRightChild() {
        return rightChild;
    }
    public void setRightChild(BinaryTreeNode<E> rightChild) {
        this.rightChild = rightChild;
    }   

    public boolean isLeaf() {
        if (this.leftChild == null && this.rightChild == null) {
            return true;
        }
        return false;
    }
}

2. 二叉链表实现

package org.sky.tree;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Scanner;
import java.util.Stack;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 二叉链表实现
 * 
 * @author sky
 *
 * @param <E>
 */
public class BinaryTree<E> {
    private BinaryTreeNode<E> root;

    public BinaryTree() {
        super();
        this.root = new BinaryTreeNode<E>();
    }

    public boolean isEmpty() {
        if (root == null) {
            return true;
        }
        return false;
    }

    public BinaryTreeNode<E> getRoot() {
        return root;
    }   

    /**
     * 将输入的数据随机分配在二叉树的结点,以生成随机二叉树
     * @param node
     * @param element
     */
    public void createTreeRandomly(BinaryTreeNode<E> node, E element){
        if(root == null){
            root = new BinaryTreeNode<E>();
        }else{
            if(Math.random() > 0.5){
                if(node.leftChild == null){
                    node.leftChild = new BinaryTreeNode<E>(element);
                }else{
                    createTreeRandomly(node.leftChild,element);
                }
            }else{
                if(node.rightChild == null){
                    node.rightChild = new BinaryTreeNode<E>(element);
                }else{
                    createTreeRandomly(node.rightChild,element);
                }
            }
        }
    }

    /**
     * 根据传入的集合创建完全二叉树
     * 此处利用了完全二叉树父结点和子结点间的关系:如果i=1,则结点i为根结点,否则其双亲结点为[i/2];
     *                              如果2i > n,则结点i无左孩子,否则其左孩子结点为2i;
     *                              如果2i+1 > n,则结点i无右孩子,否则右孩子结点为2i+1;
     * @param c
     */
    private BinaryTreeNode<E> node = null;
    public void createCompleteBinaryTree(Collection<? extends E> c){
        if(c != null && c.size() > 0){
            List<BinaryTreeNode<E>> treeList = new LinkedList<BinaryTreeNode<E>>();
            for(Object o : c){              
                BinaryTreeNode<E> binaryTreeNode = new BinaryTreeNode<E>((E)o);
                treeList.add(binaryTreeNode);
            }

            LinkedBlockingDeque<BinaryTreeNode<E>> queue = new LinkedBlockingDeque<BinaryTreeNode<E>>();
            //对前treeList.size()/2 - 1个父节点按照父节点与孩子节点的数字关系建立二叉树 
            for(int parentIndex =  0; parentIndex < treeList.size()/2; parentIndex++){              
                if(parentIndex == 0){
                    root = treeList.get(parentIndex);
                    //左子树
                    root.leftChild = treeList.get(parentIndex*2 + 1);
                    queue.add(root.leftChild);
                    //右子树
                    root.rightChild = treeList.get(parentIndex*2 +2);
                    queue.add(root.rightChild);
                }else{
                    if(!queue.isEmpty() && parentIndex*2+1 < treeList.size()){
                        node = (BinaryTreeNode<E>) queue.poll();
                        if(parentIndex*2+1 < treeList.size()){
                            //左子树
                            node.leftChild = treeList.get(parentIndex*2 + 1);
                            queue.add(node.leftChild);
                        }
                        if(parentIndex*2+2 < treeList.size()){
                            //右子树
                            node.rightChild = treeList.get(parentIndex*2 + 2);
                            queue.add(node.rightChild);
                        }
                    }else{
                        return ;
                    };
                }
            }           
        }
    }

    /**
     * 先序遍历创建二叉树,其中输入的‘#’代表空结点;
     * 例如输入input.txt:- + a # # * # # / e # # f # #;
     * @param inputFile
     */
    public void preOrderCreateBinaryTree(String inputFile){
        Scanner scanner = null;
        try{
            scanner = new Scanner(inputFile);
        }catch(Exception  e){
            e.printStackTrace();
        }
        this.root = preOrderCreateBinaryTree(root, scanner);
    }   
    public BinaryTreeNode<E> preOrderCreateBinaryTree(BinaryTreeNode<E> node, Scanner scanner){
        String temp = scanner.next();
        if(temp.trim().equals("#")){
            return null;
        }else{
            node = new BinaryTreeNode<E>((E)temp);
            node.setLeftChild(preOrderCreateBinaryTree(node.getLeftChild(), scanner));
            node.setRightChild(preOrderCreateBinaryTree(node.getRightChild(), scanner));
            return node;
        }
    }

    /**
     * 递推:知道第一个,推出下一个,直到达到目的。
     * 递归:要知道第一个,需要先知道下一个,直到一个已知的,再反回来,得到上一个,直到第一个。
     */

    /**
     * 递归求二叉树结点个数
     * @param root
     * @return 二叉树结点个数
     */
    public int getNodeNumber(BinaryTreeNode<E> root){
        if(root == null){
            return 0;
        }else{
            return getNodeNumber(root.leftChild) + getNodeNumber(root.rightChild) + 1;
        }
    }

    /**
     * 递归求二叉树的深度
     * @param root
     * @return 二叉树的深度
     */
    public int getDepth(BinaryTreeNode<E> root){
        if(root == null){
            return 0;
        }else{
            int depthLeft = getDepth(root.leftChild);   //左子树深度
            int depthRight = getDepth(root.rightChild); //右子树深度
            return depthLeft > depthRight ? (depthLeft+1) : (depthRight+1);
        }
    }

    /**
     * 递归求二叉树第k层的结点个数
     * @param root
     * @param k
     * @return 第k层的结点个数
     */
    public int getKthLevelNodeNumber(BinaryTreeNode<E> root, int k){
        if(root == null || k < 1){
            return 0;
        }
        if(k == 1){
            return 1;
        }
        int leftNumber = getKthLevelNodeNumber(root.leftChild, k-1);
        int rightNumber = getKthLevelNodeNumber(root.rightChild,k-1);
        return (leftNumber + rightNumber);
    }

    /**
     * 递归求二叉树的叶子结点数
     * @param root
     * @return
     */
    public int getLeafNodeNumber(BinaryTreeNode<E> root){
        if(root == null){
            return 0;
        }
        if(root.leftChild == null && root.rightChild == null){
            return 1;
        }
        int leftNumber = getLeafNodeNumber(root.leftChild);
        int rightNumber = getLeafNodeNumber(root.rightChild);
        return (leftNumber + rightNumber);
    }

    /**
     * 判定两个二叉树结构是否相同
     * 递归解法:
     * (1)如果两棵二叉树都为空,返回真
     * (2)如果两棵二叉树一棵为空,另一棵不为空,返回假
     * (3)如果两棵二叉树都不为空,如果对应的左子树和右子树都同构返回真,其他返回假
     * @param root1
     * @param root2
     * @return 结构相同时,返回true;
     */
    public boolean strutureComp(BinaryTreeNode<E> root1, BinaryTreeNode<E> root2){
        if(root1 == null && root2 == null){
            return true;
        }else if(root1 == null || root2 == null){
            return false;
        }
        boolean leftResult = strutureComp(root1.leftChild, root2.leftChild);
        boolean rightResult = strutureComp(root1.rightChild, root2.rightChild);
        return (leftResult && rightResult);
    }

    /**
     * 递归插入结点
     * @param root
     * @param element
     * @return 二叉树
     */
    public BinaryTreeNode<E> insert(BinaryTreeNode<E> root, E element){
        BinaryTreeNode<E> pointer = new BinaryTreeNode<E>(element);
        if(root == null){
            root = pointer;
        }else if(root.leftChild == null){
            root.leftChild = insert(root.leftChild, element);
        }else if(root.rightChild == null){
            root.rightChild = insert(root.rightChild, element);
        }
        return root;
    }

    /**
     * 求二叉树中特定子结点的父结点
     * @param root
     * @param childNode
     * @return 存在父结点时,返回父结点;否则,返回null
     */
    public BinaryTreeNode<E> getParent(BinaryTreeNode<E> root, BinaryTreeNode<E> childNode){
        if(root == null){
            return null;
        }
        if(root.leftChild == childNode || root.rightChild == childNode){
            return root;
        }
        if(getParent(root.leftChild, childNode) != null){
            return getParent(root.leftChild, childNode);
        }else{
            return getParent(root.rightChild, childNode);
        }
    }

    /**
     * 递归删除二叉树,释放相应的存储空间
     * @param root
     */
    public void destoryBinaryTree(BinaryTreeNode<E> root){
        if(root != null){
            destoryBinaryTree(root.leftChild);
            destoryBinaryTree(root.rightChild);
            root = null;
        }
    }

    /**
     * 层序遍历(广度优先遍历)
     * @param root
     */
    public void levelOrder(BinaryTreeNode<E> root){
        Queue<BinaryTreeNode<E>> queue = new LinkedBlockingQueue<BinaryTreeNode<E>>();
        BinaryTreeNode<E> pointer = root;
        /**
         * 当前结点非空时,放入队首
         */
        if(pointer != null){
            queue.add(pointer);
        }

         /*
         * 队列不为空时,先访问中间节点,访问完成后弹出队首节点;然后是左节点,再是右节点;
         */
        while(!queue.isEmpty()){
            pointer = queue.peek();   
            visit(pointer);
            queue.remove();
            if(pointer.leftChild != null){
                queue.add(pointer);
            }
            if(pointer.rightChild != null){
                queue.add(pointer);
            }

        }
    }

    /**
     * 递归先序遍历二叉树
     * @param root
     */
    public void preOrder(BinaryTreeNode<E> root){
        if (root == null){
            return;
        }              
        visit(root);
        preOrder(root.leftChild);
        preOrder(root.rightChild);
    }

    /**
     * 非递归先序遍历二叉树
     * @param root
     */
    public void nPreOrder(BinaryTreeNode<E> root){
        Stack<BinaryTreeNode<E>> stack = new Stack<BinaryTreeNode<E>>();
        BinaryTreeNode<E> pointer = root;
        while(!stack.isEmpty() || pointer != null){
            if(pointer != null){
                visit(pointer);
                if(pointer.rightChild != null){
                    stack.push(pointer.rightChild);
                }
                pointer = pointer.leftChild;
            }else{
                pointer = stack.pop();
            }
        }
    }

    /**
     * 递归中序遍历
     * @param root
     */
    public void inOrder(BinaryTreeNode<E> root){
        if (root == null){
            return;
        }   
        inOrder(root.leftChild);
        visit(root);
        inOrder(root.rightChild);
    }

    /**
     * 非递归中序遍历1
     * @param root
     */
    public void nInOrder(BinaryTreeNode<E> root){
        Stack<BinaryTreeNode<E>> stack = new Stack<BinaryTreeNode<E>>();
        BinaryTreeNode<E> pointer = root;
        while(pointer != null || !stack.isEmpty()){
            if(pointer != null){
                stack.push(pointer);
                pointer = pointer.leftChild;
            }else{
                pointer = stack.pop();
                visit(pointer);
                pointer = pointer.rightChild;               
            }
        }
    }

    /**
     * 非递归中序遍历2
     * @param root
     */
    public void nInOrders(BinaryTreeNode<E> root){
        Stack<BinaryTreeNode<E>> stack = new Stack<BinaryTreeNode<E>>();
        BinaryTreeNode<E> pointer = root;
        stack.push(pointer);
        while(!stack.isEmpty()){
            while(pointer != null){
                stack.push(pointer.leftChild);
                pointer = pointer.leftChild;
            }
            stack.pop();
            if(!stack.isEmpty()){
                pointer = stack.pop();
                visit(pointer);
                pointer = pointer.rightChild;
                stack.push(pointer);
            }
        }
    }

    /**
     * 递归后序遍历
     * @param root
     */
    public void postOrder(BinaryTreeNode<E> root){
        if (root == null){
            return;
        }   
        postOrder(root.leftChild);
        postOrder(root.rightChild);
        visit(root);
    }

    /**
     * 非递归后序遍历
     * @param root
     */
    public void nPostOrder(BinaryTreeNode<E> root){
        Stack<BinaryTreeNode<E>> stack = new Stack<BinaryTreeNode<E>>(); //初始化栈,用于保存带访问的节点
        BinaryTreeNode<E> pointer = root;                                //保存根节点
        BinaryTreeNode<E> preNode = root;                                //保存前一个被访问的节点
        while(!stack.isEmpty() || pointer != null){
            //若当前节点不空,就一直进栈,然后继续向左走
            while(pointer.leftChild != null){
                stack.push(pointer);
                pointer = pointer.leftChild;
            }
             /*
             * 当前节点为空时,分两种情况:
             * 1、当前节点移动到栈顶处,然后访问栈顶元素的右节点
             * 2、当前节点移动到栈顶,但是栈顶元素没有右节点,这就需要弹出栈顶元素,再对此元素访问;
             * 然后再对新的栈顶元素进行判断即可
             */
            while((pointer != null && pointer.rightChild == null) || pointer.rightChild == preNode){
                visit(pointer);
                preNode = pointer;
                if(stack.isEmpty()){
                    return;
                }
                pointer = stack.pop();
            }
            stack.push(pointer);
            pointer = pointer.rightChild;
        }
    }

    /**
     * 访问当前结点
     * @param current
     */
    public void visit(BinaryTreeNode<E> current){
        if(current != null && current.element != null){
            System.out.println(current.element);
        }else{
            System.out.println("null");
        }
    }
}

3. 参考文献

1. java创建二叉树并递归遍历二叉树
2. java实现二叉树相关代码—–数据结构
3. Java实现二叉树的创建、递归/非递归遍历
4. Java实现二叉树的创建和遍历操作(有更新)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值