X16数据结构部分07

简单二叉树的创建及增删改查

package du;

/**
 * @author 404小恐龙
 * @version 1.8
 * @date 2021/10/18 16:57
 */
public class m09 {
    public static void main(String[] args) {
        /*
        创建树和根节点
        并将根节点赋给树
         */
        BinaryTree binaryTree = new BinaryTree();
        BinaryTreeNode root = new BinaryTreeNode(1);
        binaryTree.setRoot(root);
        /*
        创建根节点的左子树和右子树
        加入树节点中
         */
        BinaryTreeNode rootLeftChild = new BinaryTreeNode(2);
        BinaryTreeNode rootRightChild = new BinaryTreeNode(3);
        root.setLeftNode(rootLeftChild);
        root.setRightNode(rootRightChild);
        /*
        第2层左右节点分别创建2个子节点
         */
        rootLeftChild.setLeftNode(new BinaryTreeNode(4));
        rootLeftChild.setRightNode(new BinaryTreeNode(5));
        rootRightChild.setLeftNode(new BinaryTreeNode(7));
        rootRightChild.setRightNode(new BinaryTreeNode(8));
        /*
        二叉树遍历方式
            前序遍历    root -> left -> right
            中序遍历    left -> root -> right
            后序遍历    left -> right -> root
         */
        binaryTree.preorderTraversal();
        binaryTree.inorderTraversal();
        /*
        前序查找算法实现
         */
        BinaryTreeNode treeNode = binaryTree.preorderLookup(5);
        System.out.println(treeNode.toString());
        // BinaryTreeNode{value=5, leftNode=null, rightNode=null}
        /*
        删除树的子节点
         */

    }
}

/**
 * BinaryTreeNode
 *
 * @author stack frame
 */
class BinaryTreeNode {
    int value;
    BinaryTreeNode leftNode;
    BinaryTreeNode rightNode;

    public BinaryTreeNode(int value){
        this.value = value;
    }

    public void setLeftNode(BinaryTreeNode leftNode) {
        this.leftNode = leftNode;
    }

    public void setRightNode(BinaryTreeNode rightNode) {
        this.rightNode = rightNode;
    }

    /**
     * 前序遍历
     */
    public void preorderTraversal() {
        System.out.print(value + " "); // 1 2 4 5 3 7 8
        if (leftNode != null) {
            leftNode.preorderTraversal();
        }
        if (rightNode != null) {
            rightNode.preorderTraversal();
        }
    }

    /**
     * 中序遍历
     */
    public void inorderTraversal() {
        if (leftNode != null) {
            leftNode.preorderTraversal();
        }
        System.out.print(value + " "); // 2 4 5 1 3 7 8
        if (rightNode != null) {
            rightNode.preorderTraversal();
        }
    }

    /**
     * 前序查找
     * @param i 需要查找节点的值
     * @return 值对应树的节点对象
     */
    public BinaryTreeNode preorderLookup(int i) {
        BinaryTreeNode targetNode = null;
        /*
        先查找根节点
         */
        if (this.value == i) {
            return this;
        }else {
            if (leftNode != null) {
                targetNode = leftNode.preorderLookup(i);
            }
            if (targetNode != null) {
                /*
                程序运行到此处
                说明目标节点已经在左子树中查到了
                直接返回即可
                 */
                return targetNode;
            }
            if (rightNode != null) {
                targetNode = rightNode.preorderLookup(i);
            }
            if (targetNode != null) {
                /*
                程序运行到此处
                说明目标节点已经在左子树中查到了
                直接返回即可
                 */
                return targetNode;
            }
        }
        return targetNode;
    }

    @Override
    public String toString() {
        return "BinaryTreeNode{" +
                "value=" + value +
                ", leftNode=" + leftNode +
                ", rightNode=" + rightNode +
                '}';
    }

    /**
     * 删除子节点
     * @param i 需要删除的节点值
     */
    public void deleteNode(int i) {
        /*
        删除方法简单
        这里就不写了
        后续会有二叉排序树的删除方法
        过程很复杂的
        做好心理准备
         */
    }
}

/**
 * BinaryTree
 *
 * @author stack frame
 */
class BinaryTree {
    BinaryTreeNode root;

    public BinaryTreeNode getRoot(){
        return root;
    }

    public void setRoot(BinaryTreeNode root) {
        this.root = root;
    }

    public void preorderTraversal() {
        root.preorderTraversal();
    }

    public void inorderTraversal() {
        root.inorderTraversal();
    }

    public BinaryTreeNode preorderLookup(int i) {
        return root.preorderLookup(i);
    }

    public void deleteNode(int i) {
        if (root.value == i) {
            root = null;
        }else {
            root.deleteNode(i);
        }
    }
}
		/*
		补充说明
        顺序存储的二叉树概述
        通常情况只考虑完全二叉树
            需要了解的知识
            存储结构是数组
        	索引为0的位置是根节点
        	索引为1和2的位置是左子树和右子树
        	之后就是2的幂次方1组1层之类的了
        	
            如果从上往下层级划分节点
            就是根节点是0
            对应左子树节点是1
            右子树节点是2
            依次往下
            第n个节点的左子节点  2n + 1
            第n个节点的右子节点  2n + 2
            第n个节点的父节点    (n - 1) / 2
         */

堆排序

public class m13 {
    public static void main(String[] args) {

    }

    public static void heapSort(int[] array) {
        int tmp = 0;
        /*
        程序开始调用堆排序方法
        第一次排序返回{4,9,8,5,6}
        此时i已经写死
        开发中i会被算法计算出来
        所以我们忽略这条调用语句
        完成最终代码
         */
        // adjectBigTopPile(array,1,array.length);
        for (int i = array.length; i >= 0; i--) {
            /*
            程序运行到此处
            由于采用递归调用的原因
            for循环会一直按左子树往下查找
            一直查到最后一个非叶子节点
            然后依次往上进行查找
             */
            adjectBigTopPile(array,i,array.length);
        }
        /*
        程序运行到此处
        说明第1轮堆排序已经结束
        此时堆顶为最大元素
        程序输出{9,6,8,5,4}
        此时将堆顶与末尾交换位置
         */
        for (int j = array.length - 1; j > 0; j--) {
            tmp = array[j];
            array[j] = array[0];
            array[0] = tmp;
            /*
            程序运行到此处
            此时4和9已经未完成交换
            元素9已经在最终位置
            剩余4个元素重新进行调整
            所以说堆排序的扫描范围是不断缩小的

            注意
            下面这个调用语句执行完后
            for循环才能继续执行
             */
            adjectBigTopPile(array,0,j);
        }
    }

    /**
     * 调整当前父元素大于左子树和右子树
     * @param array 堆对应的数组
     * @param i 对应的非叶子节点调整成大顶堆的二叉树对应数组索引位置
     *          若i = 1,则调整最左下角的堆
     *          数组变为{4,9,8,5,6}
     *          调整1整趟完毕后就是{9,6,8,5,4}
     * @param length 表示多少个元素需要调整 逐渐递减 最大值首先被去掉
     */
    public static void adjectBigTopPile(int[] array,int i,int length) {
        /*
        程序开始运行
        i默认指向最后一个非叶子节点
         */
        int tmp = array[i];
        for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {
            if (k + 1 < length && array[k] < array[k + 1]) {
                /*
                程序运行到此处
                说明当前数组左子节点相邻位置对应的
                右子节点比当前左子节点大
                需要调换位置
                k指针指向右字节带你
                 */
                k++;
            }
            if (array[k] > tmp) {
                /*
                程序运行到此处
                说明当前左子节点或右子节点
                大于当前父节点
                需要调换位置
                此时k指向的元素是3者中最大的元素
                然后让i指向k
                继续循环比较
                 */
                array[i] = array[k];
                i = k;
            }else {
                /*
                程序运行到此处
                说明最大值就是在父节点
                直接进行下一轮比较
                比较之前
                当前i指向的值就是父节点并且是3者中最大的值
                下一次比较的时候
                i对应的会是父节点的左子节点
                与右子节点和父节点进行比较和交换
                 */
                break;
            }
        }
        /*
        程序运行到此处
        此时整个数组的最大值已经被放在索引为0的位置
        也就是二叉树的根节点位置
        此时程序绝对没有执行else语句
        需要将之前指向的较小节点覆盖掉
        左子树或者右子树
         */
        array[i] = tmp;
    }
}

线索二叉树代码实现

/**
 * BinaryTree
 *
 * @author stack frame
 */
class BinaryTree {
    BinaryTreeNode root;
    BinaryTreeNode tmp;

    public BinaryTreeNode getRoot() {
        return root;
    }

    public void setRoot(BinaryTreeNode root) {
        this.root = root;
    }

    public void preorderTraversal() {
        root.preorderTraversal();
    }

    public void inorderTraversal() {
        root.inorderTraversal();
    }

    public BinaryTreeNode preorderLookup(int i) {
        return root.preorderLookup(i);
    }

    public void deleteNode(int i) {
        if (root.value == i) {
            root = null;
        } else {
            root.deleteNode(i);
        }
    }

    public void threadNode(){
        threadNode(root);
    }

    /**
     * 中序线索化二叉树
     * @param node 根节点
     */
    public void threadNode(BinaryTreeNode node) {
        /*
        程序运行到此处
        需要设置递归出口
         */
        if (node == null) {
            return;
        }
        /*
        递归处理左子树和右子树
         */
        threadNode(node.leftNode);
        if (node.leftNode == null) {
            /*
            程序运行到此处
            说明该节点左指针为空
            需要改变指针类型
            并指向该节点的前驱节点
            前驱节点每次调用该方法都会换掉
             */
            node.leftNode = tmp;
            node.leftType = 1;
            tmp = node;
        }
        /*
        程序运行到此处
        需要判断当前节点的前驱节点是否为空
        如果不做处理
        会报空指针异常java.lang.NullPointerException
         */
        if (tmp != null && tmp.rightNode == null) {
            /*
            程序运行到此处
            说明当前节点的前一个节点为空
            右指针需要指向当前节点
             */
            tmp.rightNode = node;
            tmp.rightType = 1;
        }
        threadNode(node.rightNode);
    }
}
/*
    线索二叉树概述
        类似于双向链表二叉树
        如果这个节点的左右指针
        有空的情况
        可以让这个空的指针域
        指向前一个节点

        中序遍历二叉树的时候
        空的左子树指向前驱节点
        空的右子树指向后继节点

        需要找变量来标识
        比如0 1
        左指针和右指针

        所以需要在TreeNode类里面加入
        int类型的标识指针leftType和rightType

        为了体现封装思想
        需要写一个方法
        中序线索化二叉树
     */

遍历线索二叉树

/**
     * 遍历线索二叉树
     */
    public void trailBinaryTreeTraversal () {
        BinaryTreeNode treeNode = root;
        if (treeNode != null) {
            while (treeNode.leftType == 0) {
                /*
                程序第1次运行到此处
                说明查找当前节点为根节点
                接着循环往后找
                 */
                treeNode = treeNode.leftNode;
            }
            /*
            程序运行到此处
            说明能找到最左下角的节点
            打印该节点
             */
            System.out.println(treeNode);
            /*
            程序运行到此处
            需要查找后继节点是否为空
            第一个被查找的节点仍然是最左下角的节点
            右指针指向父节点
             */
            while (treeNode.rightType == 1) {
                treeNode = treeNode.rightNode;
                System.out.println(treeNode);
            }
            /*
            程序运行到此处
            说明遇到了不等于1的节点
            这时候直接让这个节点指向下一个节点
            如果是第1次执行这个代码
            当前treeNode指向的就是最左下角的父节点
             */
            treeNode = treeNode.rightNode;
        }
    }

总目录

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

muskfans

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值