数据结构二叉树相关操作(java方式实现)

一:二叉树相关操作

1:构造一个二叉树

2:二叉树前序遍历(递归)

3:二叉树中序遍历(递归)

4:二叉树后续遍历(递归)

5:二叉树前序遍历(非递归)

6:二叉树中序遍历(非递归)

7:二叉树后序遍历(非递归)

二:代码实现

2.1:节点结构

    /**
     * 节点类
     */
    private static class BinaryNode{
        private int value;
        private BinaryNode leftNode;
        private BinaryNode rightNode;

        public BinaryNode(int value) {
            this(value, null, null);
        }

        public BinaryNode(int value, BinaryNode leftNode, BinaryNode rightNode) {
            this.value = value;
            this.leftNode = leftNode;
            this.rightNode = rightNode;
        }
    }

2.2:构造一个二叉树

/**
     * 构造二叉树
     * @param datas 二叉树中各节点的值
     * @param nodeList 二叉树中的各节点
     * 可以讲的点:
     *    1:先构造节点信息(把数据加到节点当中),节点信息保存到数组中
     *    2:为父节点添加相应的子节点
     *      2.1:节点个数和父节点的关系 2倍关系 
     *      2.2:最后一个父节点需要特殊处理,奇数的话,有右孩子,偶数的话没有右孩子
     * 
     */
    public void createBinaryTree(int[] datas, List<BinaryNode> nodeList){
        //为各节点添加数据域
        BinaryNode binaryNode = null;
        for(int i = 0; i < datas.length; i++){
            binaryNode = new BinaryNode(datas[i]);
            nodeList.add(binaryNode);
        }

        /**
         * 说明:
         *  1、为各个父节点添加相应的子节点,按照层序的方式添加子节点
         *  2、将二叉树按照完全二叉树编号,根节点的编号为1,若某节点i有左孩子,则其左孩子的编号为2i
         *     若某节点有右孩子,则其右孩子的编号为(2i + 1)
         *  3、二叉树中若有n个节点,那么父节点的个数为(n/2)
         *  4、二叉树中若节点的个数为奇数,那么最后一个父节点有右子节点
         *     若节点的个数为偶数,那么最后一个父节点只有左子节点,没有右子节点
         *  5、list中节点的下标从0开始,因此编号为i的节点存储到下标为(i - 1)的位置
         */
        //nodeList.size() / 2 - 1,减1的原因是,最后一个父节点可能没有右子节点,所以需要单独处理
        for(int i = 0; i < nodeList.size() / 2 - 1; i++){
            //加1的原因是,list从0开始编号
            nodeList.get(i).leftNode = nodeList.get(i * 2 +1);
            nodeList.get(i).rightNode = nodeList.get(i * 2 + 1 + 1);
        }

        //单独处理最后一个父节点
        int lastNode = nodeList.size() / 2 - 1;
        nodeList.get(lastNode).leftNode = nodeList.get(lastNode * 2 + 1);
        //二叉树中节点的总个数为奇数,此时最后一个父节点有右子节点
        if(nodeList.size() % 2 != 0){
            nodeList.get(lastNode).rightNode = nodeList.get(lastNode * 2 + 1 + 1);
        }
    }

2.3:前序遍历二叉树(递归)

    /**
     * 前序递归遍历二叉树
     * 根左右
     */
    public void preTraverse(BinaryNode rootNode){
        //递归遍历结束条件
        if(rootNode == null){
            return;
        }else{
            //访问根节点rootNode的数据域
            System.out.print(rootNode.value + ", ");
            //前序递归调用rootNode的左子树
            preTraverse(rootNode.leftNode);
            //前序递归调用rootNode的右子树
            preTraverse(rootNode.rightNode);
        }
    }

2.4:中序遍历(递归)

    /**
     * 中序递归遍历二叉树
     * 左根右
     */
    public void inTraverse(BinaryNode rootNode){
        if(rootNode == null){
            return;
        }else{
            inTraverse(rootNode.leftNode);
            System.out.print(rootNode.value + ", ");
            inTraverse(rootNode.rightNode);
        }
    }

2.5:后序遍历(递归)

  /**
     * 后序递归调用二叉树
     * 左右跟
     */
    public void postTraverse(BinaryNode rootNode){
        if(rootNode == null){
            return;
        }else{
            postTraverse(rootNode.leftNode);
            postTraverse(rootNode.rightNode);
            System.out.print(rootNode.value + ", ");
        }
    }

2.6:层序遍历(从上到下)

/**
	 * 层序遍历节点 
	 * 思路 
	 *    1:用一个数组当成一个队列
	 *    2:两个下标front控制出队,和rear控制入队  
	 */
	private void levelTraverse(BinaryNode rootNode, int nodeSize) {
		// 使用顺序队列
		BinaryNode[] nodes = new BinaryNode[nodeSize];
		int front = -1, rear = -1;
		// 二叉树为空,直接结束
		if (rootNode == null) {
			return;
		}
		// 根节点入队列
		nodes[++rear] = rootNode;
		BinaryNode tempNode = null;
		// 当队列非空时
		while (front != rear) {
			// 出队
			tempNode = nodes[++front];
			System.out.print(tempNode.value + ", ");
			// 将当前节点的左节点入队列
			if (tempNode.leftNode != null) {
				nodes[++rear] = tempNode.leftNode;
			}
			// 将当前节点的右节点入队列
			if (tempNode.rightNode != null) {
				nodes[++rear] = tempNode.rightNode;
			}
		}
	}

2.7:前序遍历(非递归)

/**
     * 前序非递归遍历二叉树
     * 1:根左右
     * 步骤: 
     *     1:我们用栈来存储二叉树信息
     *     2:根节点入栈,输出根节点到值,将节点左孩子循环入栈,输出,
     *     3:栈顶元素为最左节点,出栈
     */
    public void preTraverseByLoop(BinaryNode rootNode){
        Stack<BinaryNode> nodeStack = new Stack<BinaryNode>();

        //若根节点和栈均为空,则整个二叉树遍历结束
        while(rootNode != null || !nodeStack.isEmpty()){
            while(rootNode != null){
                System.out.print(rootNode.value + ", ");
                //将根节点入栈,以便通过它找到这个树的右子树
                nodeStack.push(rootNode);
                //准备遍历根节点的左子树
                rootNode = rootNode.leftNode;
            }
            //此时根节点为空,但是栈非空,将根节点弹出,并遍历根节点的左子树
            if(!nodeStack.isEmpty()){
                rootNode = nodeStack.pop();
                rootNode = rootNode.rightNode;
            }
        }
    }
	

2.8:中序非递归方式实现

  /**
     * 中序非递归遍历二叉树
     * 左根有
     * 步骤:
     *  1:我们用一个栈来解决,左子树一直入栈完毕
     *  2:输出栈顶元素 ,最后访问右字数
     * 
     */
    public void inTraverseByLoop(BinaryNode rootNode){
        Stack<BinaryNode> nodeStack = new Stack<BinaryNode>();
        while(rootNode != null || !nodeStack.isEmpty()){
            while(rootNode != null){
                nodeStack.push(rootNode);
                rootNode = rootNode.leftNode;
            }
            if(!nodeStack.isEmpty()){
                //遍历过程中,不能立即访问,只有当它的左子树遍历完毕,才从栈中弹出并访问
                rootNode = nodeStack.pop();
                System.out.print(rootNode.value + ", ");
                rootNode = rootNode.rightNode;
            }
        }
    }

2.9: 后序遍历非实现

 /**
     * 后序非递归遍历二叉树
     */
    public void postTraverseByLoop(BinaryNode rootNode){
        Stack<BinaryNode> nodeStack = new Stack<BinaryNode>();
        BinaryNode pre = rootNode;
        while(rootNode != null || !nodeStack.isEmpty()){
            while(rootNode != null){
                nodeStack.push(rootNode);
                rootNode = rootNode.leftNode;
            }
            if(!nodeStack.isEmpty()){
                BinaryNode tempNode = nodeStack.peek().rightNode;
                if(tempNode == null || tempNode == pre){
                    rootNode = nodeStack.pop();
                    System.out.print(rootNode.value + ", ");
                    pre = rootNode;
                    rootNode = null;
                }else{
                    rootNode = tempNode;
                }
            }
        }
    }

三: 源代码下载







 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值