线索化二叉树(先序,中序,后序)+线索化二叉树的遍历【java详解】

目录

线索化二叉树的基本介绍:

 举个栗子:

二叉树的中序线索化:

创建HeroNode类,表示节点信息:

编写中序线索化方法代码:

中序线索化遍历代码:

测试代码:

测试结果:

 二叉树的先序线索化:

编写先序线索化代码:

 先序线索化遍历代码:

测试结果:

二叉树前序和中序线索化完整代码:

二叉树的后续线索化:

定义一个PostTreadBinaryTree 来表示节点信息:

编写createBinaryTree方法来实现二叉树的创建:

编写后续线索化方法代码: 

后序线索化遍历:

代码详解:

 测试代码:

测试结果:

最后,后序线索化的详细代码,有需要可以自己查看:

小结:


写在之前:在学习线索化二叉树之前,要对二叉树的前中后序遍历有一定的了解,如果还不会的小伙伴可以看看我的这篇博客:二叉树-------前,中,后序遍历 + 前,中,后序查找+删除节点 (java详解)-CSDN博客

由于网上以及书上对线索化二叉树的前序和后序及其遍历介绍的较少,这里统一整理了一下,希望对各位有所帮助。欢迎点赞加关注支持博主~

------------------------------------------------------------------------------------------------------------------------------- 

线索化二叉树的基本介绍:

  • n个结点的二叉链表中含有n+1  【公式 2n-(n-1)=n+1】 个空指针域。利用二叉链表中的空指针域,存放指向该结点在某种遍历次序下的前驱和后继结点的指针(这种附加的指针称为"线索")
  • 这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded BinaryTree)。根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种
  • 一个结点的前一个结点,称为前驱结点
  • 一个结点的后一个结点,称为后继结点

 举个栗子:

将一颗普通的二叉树如下图所示(它是一个含有6个节点的二叉树,按照上述公式计算其空指针域为7【n+1】):

中序线索化后,得到如图所示的二叉树(中序线索化后):

 这实际上是一个将二叉树的指针域充分利用的过程(即充分利用各个节点的左右指针),那么,上述的过程究竟是如何实现的呢?看到这里,你想必还是一脸懵圈,别急,然我们再举个栗子(以中序线索化为例):

我们先将上述数字转化为一个数组,当然这个数组不是随便写的,是通过中序遍历得到的,这个数组是:8,3,10,1,14,6  ,接着我们只需要结合原图,将左右指针为空的节点进行连线,具体如下:

说明:数字8左右指针都为空,理应联两条线,但根据其中序遍历的结果,它的左边为空,所以上述图中数字8只连了一根线,对应到3节点。同理数字10连两根线对应3,1;数字14连2根线,对应1,6;6连一根线,对应空(null),实际在图中表示为不连线---》连线的根数是根据节点的左右指针个数决定的,如数字8,节点左右指针为空,连两条线(对应左右指针的方向),而数字6右指针为空,所以连一条线

实际线索化后的二叉树(通常null省略罢了 ):

 通过上面的一些描述,想必你对二叉树的线索化有了一定理解,那么我们接着开始进入正题:

二叉树的中序线索化:

说明:当线索化二叉树后,Node节点的属性left和right有如下情况:

1).left指向的是左子树,也可能是指向前驱节点,比如①节点left指向左子树,二⑩节点的left指向的就是前驱节点

2).right指向的是右子树,也可能是指向后继节点,比如①节点right指向左=右子树,二⑩节点的right指向的就是后继节点

同时,为了方便表示线索后的二叉树,我们这样定义:
1. 如果leftType == 0 表示指向的是左子树, 如果 1 则表示指向前驱结点
2. 如果rightType == 0 表示指向是右子树, 如果 1表示指向后继结点

创建HeroNode类,表示节点信息:


    //先创建HeroNode 结点
    class HeroNode {
        private int no;
        private String name;
        private HeroNode left; //默认null
        private HeroNode right; //默认null
        //说明
        //1. 如果leftType == 0 表示指向的是左子树, 如果 1 则表示指向前驱结点
        //2. 如果rightType == 0 表示指向是右子树, 如果 1表示指向后继结点
        private int leftType;
        private int rightType;


        public int getLeftType() {
            return leftType;
        }

        public void setLeftType(int leftType) {
            this.leftType = leftType;
        }

        public int getRightType() {
            return rightType;
        }

        public void setRightType(int rightType) {
            this.rightType = rightType;
        }

        public HeroNode(int no, String name) {
            this.no = no;
            this.name = name;
        }

        public int getNo() {
            return no;
        }

        public void setNo(int no) {
            this.no = no;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public HeroNode getLeft() {
            return left;
        }

        public void setLeft(HeroNode left) {
            this.left = left;
        }

        public HeroNode getRight() {
            return right;
        }

        public void setRight(HeroNode right) {
            this.right = right;
        }

        @Override
        public String toString() {
            return "HeroNode [no=" + no + ", name=" + name + "]";
        }
    }*/

通过上面的中序线索化构造的栗子,我们可以按照先

(一)先线索化左子树---》(二)线索化当前结点---》(三)在线索化右子树

编写中序线索化方法代码:

public void threadedNodes(HeroNode node) {

        //如果node==null, 不能线索化
        if (node == null) {
            return;
        }

        //(一)先线索化左子树
        threadedNodes(node.getLeft());
        //(二)线索化当前结点

        //处理当前结点的前驱结点
        //以8结点来理解
        //8结点的.left = null , 8结点的.leftType = 1
        if (node.getLeft() == null) {
            //让当前结点的左指针指向前驱结点
            node.setLeft(pre);
            //修改当前结点的左指针的类型,指向前驱结点
            node.setLeftType(1);
        }

        //处理后继结点
        if (pre != null && pre.getRight() == null) {
            //让前驱结点的右指针指向当前结点
            pre.setRight(node);
            //修改前驱结点的右指针类型
            pre.setRightType(1);
        }
        //!!! 每处理一个结点后,让当前结点是下一个结点的前驱结点
        pre = node;

        //(三)在线索化右子树
        threadedNodes(node.getRight());

    }

中序线索化遍历代码:

/遍历线索化二叉树的方法
    public void threadedList() {
        //定义一个变量,存储当前遍历的结点,从root开始
        HeroNode node = root;
        while (node != null) {
            //循环的找到leftType == 1的结点,第一个找到就是8结点
            //后面随着遍历而变化,因为当leftType==1时,说明该结点是按照线索化
            //处理后的有效结点
            while (node.getLeftType() == 0) {
                node = node.getLeft();
            }

            //打印当前这个结点
            System.out.println(node);
            //如果当前结点的右指针指向的是后继结点,就一直输出
            while (node.getRightType() == 1) {
                //获取到当前结点的后继结点
                node = node.getRight();
                System.out.println(node);
            }
            //替换这个遍历的结点
            node = node.getRight();

        }
    }

测试代码:

public class ThreadedBinaryTreeDemo {
    public static void main(String[] args) {
        //测试一把中序线索二叉树的功能
        HeroNode root = new HeroNode(1, "tom");
        HeroNode node2 = new HeroNode(3, "jack");
        HeroNode node3 = new HeroNode(6, "smith");
        HeroNode node4 = new HeroNode(8, "mary");
        HeroNode node5 = new HeroNode(10, "king");
        HeroNode node6 = new HeroNode(14, "dim");
        HeroNode node7 = new HeroNode(1, "xiao");


        //二叉树,后面我们要递归创建, 现在简单处理使用手动创建
        root.setLeft(node2);
        root.setRight(node3);
        node2.setLeft(node4);
        node2.setRight(node5);
        node3.setLeft(node6);

        //测试中序线索化
        ThreadedBinaryTree threadedBinaryTree = new ThreadedBinaryTree();
        threadedBinaryTree.setRoot(root);
        threadedBinaryTree.threadedNodes();

        //测试: 以10号节点测试
        HeroNode leftNode = node5.getLeft();
        HeroNode rightNode = node5.getRight();
        System.out.println("10号结点的前驱结点是 ="  + leftNode); //3
        System.out.println("10号结点的后继结点是="  + rightNode); //1

        //当线索化二叉树后,能在使用原来的遍历方法
        //threadedBinaryTree.infixOrder();
        System.out.println("使用线索化的方式遍历 线索化二叉树");
        threadedBinaryTree.threadedList(); // 8, 3, 10, 1, 14, 6

    }
}

 

接着我们测试一下就以节点⑩为例(如上图),线索化后其前驱节点为③,其后继节点为①

同时,遍历的结果与中序遍历保持一致,即 8,3,10,1,14,6

测试结果:

 二叉树的先序线索化:

按照中序线索化的方法,我给出线索化的图解:

 

 

HeroNode类与上面基本一致,不做过多说明

按照  线索化当前节点---》线索化左子树---》线索化右子树  过程进行

编写先序线索化代码:

  //前序线索化
    public void pretreadedNodes(HeroNode node){
        if(node == null){
            return ;
        }

        if(node.getLeft() == null){
            node.setLeft(pre);
            node.setLeftType(1);
        }
        if(pre != null && pre.getRight() == null){
            pre.setRight(node);
            pre.setRightType(1);
        }
        pre = node;

        if(node.getLeftType() == 0) {
            pretreadedNodes(node.getLeft());
        }
        if(node.getRightType() == 0) {
            pretreadedNodes(node.getRight());
        }
    }

 先序线索化遍历代码:

//遍历前序线索化二叉树
    public void pretreadedList(){
        HeroNode node = root;
        while(node != null){
            while(node.getLeftType() == 0){
                System.out.println(node);
                node = node.getLeft();
            }
            System.out.println(node);
            while(node.getRightType() == 1){
                node = node.getRight();
                System.out.println(node);
            }
            node = node.getRight();
        }
    }

 

接着我们测试一下就以节点⑩为例(如上图),线索化后其前驱节点为⑧,其后继节点为⑥

同时,先序线索化遍历的结果与先序遍历保持一致

测试结果:

二叉树前序和中序线索化完整代码:

//测试
public class ThreadedBinaryTreeDemo {

    public static void main(String[] args){
        HeroNode root = new HeroNode(1, "tom");
        HeroNode node2 = new HeroNode(3, "jack");
        HeroNode node3 = new HeroNode(6, "smith");
        HeroNode node4 = new HeroNode(8, "mary");
        HeroNode node5 = new HeroNode(10, "king");
        HeroNode node6 = new HeroNode(14, "dim");

        root.setLeft(node2);
        root.setRight(node3);
        node2.setLeft(node4);
        node2.setRight(node5);
        node3.setLeft(node6);

        TreadedBinaryTree treadedBinaryTree = new TreadedBinaryTree(root);
        //treadedBinaryTree.intreadedNodes();
        treadedBinaryTree.pretreadedNodes();

        HeroNode leftNode = node5.getLeft();
        HeroNode rightNode = node5.getRight();
        System.out.println("10号节点的前驱节点是:"+leftNode);
        System.out.println("10号节点的后继节点是:"+rightNode);

        System.out.println("使用线索化二叉树的遍历:");
        treadedBinaryTree.pretreadedList();
        //treadedBinaryTree.intreadedList();
        

    }
}

class TreadedBinaryTree{
   private HeroNode root;
    private HeroNode pre = null;

    public TreadedBinaryTree(HeroNode root) {
        this.root = root;
    }

    public void posttreadedNodes(){
        this.posttreadedNodes(root);
    }

    public void intreadedNodes(){
        this.intreadedNodes(root);
    }

    public void pretreadedNodes(){
        this.pretreadedNodes(root);
    }

    //遍历中序线索化二叉树
   public void intreadedList(){
        HeroNode node =root;
        while(node != null){
            while(node.getLeftType() == 0){
                node = node.getLeft();
            }
            System.out.println(node);

            while(node.getRightType() == 1){
                node = node.getRight();
                System.out.println(node);
            }
            node = node.getRight();
        }
   }
    //遍历前序线索化二叉树
    public void pretreadedList(){
        HeroNode node = root;
        while(node != null){
            while(node.getLeftType() == 0){
                System.out.println(node);
                node = node.getLeft();
            }
            System.out.println(node);
            while(node.getRightType() == 1){
                node = node.getRight();
                System.out.println(node);
            }
            node = node.getRight();
        }
    }
   //中序线索化
    public void intreadedNodes(HeroNode node){
        if(node == null){
            return ;
        }
        intreadedNodes(node.getLeft());

        if(node.getLeft() == null){
            node.setLeft(pre);
            node.setLeftType(1);
        }
        if(pre != null && pre.getRight() == null){
            pre.setRight(node);
            pre.setRightType(1);
        }
        pre = node;

        intreadedNodes(node.getRight());
    }

    //前序线索化
    public void pretreadedNodes(HeroNode node){
        if(node == null){
            return ;
        }

        if(node.getLeft() == null){
            node.setLeft(pre);
            node.setLeftType(1);
        }
        if(pre != null && pre.getRight() == null){
            pre.setRight(node);
            pre.setRightType(1);
        }
        pre = node;

        if(node.getLeftType() == 0) {
            pretreadedNodes(node.getLeft());
        }
        if(node.getRightType() == 0) {
            pretreadedNodes(node.getRight());
        }
    }
    //后续线索化二叉树
    public void posttreadedNodes(HeroNode node){
        if(node == null){
            return ;
        }

            posttreadedNodes(node.getLeft());

            posttreadedNodes(node.getRight());


        if(node.getLeft() == null){
            node.setLeft(pre);
            node.setLeftType(1);
        }
        if(pre != null && pre.getRight() == null){
            pre.setRight(node);
            pre.setRightType(1);
        }
        pre = node;

    }



}

class HeroNode{
    private int no;
    private String name;
    private HeroNode left;//默认null
    private HeroNode right;//默认null

    //说明
    //1. 如果leftType == 0 表示指向的是左子树, 如果 1 则表示指向前驱结点
    //2. 如果rightType == 0 表示指向是右子树, 如果 1表示指向后继结点
    private int leftType;
    private int rightType;


    public HeroNode() {
    }

    public HeroNode(int no, String name) {
        this.no = no;
        this.name = name;
    }

    /**
     * 获取
     * @return no
     */
    public int getNo() {
        return no;
    }

    /**
     * 设置
     * @param no
     */
    public void setNo(int no) {
        this.no = no;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return left
     */
    public HeroNode getLeft() {
        return left;
    }

    /**
     * 设置
     * @param left
     */
    public void setLeft(HeroNode left) {
        this.left = left;
    }

    /**
     * 获取
     * @return right
     */
    public HeroNode getRight() {
        return right;
    }

    /**
     * 设置
     * @param right
     */
    public void setRight(HeroNode right) {
        this.right = right;
    }

    /**
     * 获取
     * @return leftType
     */
    public int getLeftType() {
        return leftType;
    }

    /**
     * 设置
     * @param leftType
     */
    public void setLeftType(int leftType) {
        this.leftType = leftType;
    }

    /**
     * 获取
     * @return rightType
     */
    public int getRightType() {
        return rightType;
    }

    /**
     * 设置
     * @param rightType
     */
    public void setRightType(int rightType) {
        this.rightType = rightType;
    }

    public String toString() {
        return "HeroNode{no = " + no + ", name = " + name + "}";
    }
}

二叉树的后续线索化:

(后序相对前序与中序复杂,单独拎出来讲---》主要是遍历过程复杂)

按照上述中序线索化的过程,我给出后续线索化的图解:

 

定义一个PostTreadBinaryTree 来表示节点信息:

public class PostTreadBinaryTree {

    private Node preNode;   //线索化时记录前一个节点

    //节点存储结构
    static class Node {
        String data;        //数据域
        Node left;          //左指针域
        Node right;         //右指针域
        Node parent;        //父节点的指针(为了后序线索化使用)
        boolean isLeftThread = false;   //左指针域类型  false:指向子节点、true:前驱或后继线索
        boolean isRightThread = false;  //右指针域类型  false:指向子节点、true:前驱或后继线索

        Node(String data) {
            this.data = data;
        }
    }

编写createBinaryTree方法来实现二叉树的创建:

 static Node createBinaryTree(String[] array, int index) {
        Node node = null;

        if(index < array.length) {
            node = new Node(array[index]);
            node.left = createBinaryTree(array, index * 2 + 1);
            node.right = createBinaryTree(array, index * 2 + 2);

            //记录节点的父节点(后序线索化遍历时使用)
            if(node.left != null) {
                node.left.parent = node;
            }

            if(node.right != null) {
                node.right.parent = node;
            }
        }

        return node;
    }

编写后续线索化方法代码: 

void postThreadOrder(Node node) {
        if(node == null) {
            return;
        }

        //处理左子树
        postThreadOrder(node.left);
        //处理右子树
        postThreadOrder(node.right);

        //左指针为空,将左指针指向前驱节点
        if(node.left == null) {
            node.left = preNode;
            node.isLeftThread = true;
        }

        //前一个节点的后继节点指向当前节点
        if(preNode != null && preNode.right == null) {
            preNode.right = node;
            preNode.isRightThread = true;
        }
        preNode = node;
    }

后序线索化遍历:

后序遍历线索化二叉树是一种对二叉树进行线索化的方法,使得在遍历二叉树时可以更高效地找到前驱和后继节点。下面是后序遍历线索化二叉树的思路:

  1. 首先,定义一个辅助指针pre,用于记录当前节点的前驱节点。
  2. 对于二叉树的每个节点,按照后序遍历的顺序进行处理。
  3. 如果当前节点的左子树不为空,就将当前节点的左子树线索化。具体步骤如下:
    • 找到当前节点的左子树的最右节点,即左子树中最后一个被访问的节点。
    • 将该最右节点的右指针指向当前节点,并将其线索化标记设置为1,表示指向后继节点。
  4. 如果当前节点的右子树不为空,就将当前节点的右子树线索化。具体步骤如下:
    • 找到当前节点的右子树的最左节点,即右子树中第一个被访问的节点。
    • 将该最左节点的左指针指向当前节点,并将其线索化标记设置为1,表示指向前驱节点。
  5. 更新pre指针为当前节点,以便在下一次迭代时使用。
  6. 重复步骤2-5,直到遍历完整个二叉树。

这样,通过后序遍历线索化二叉树,我们可以在不使用递归或栈的情况下,高效地找到任意节点的前驱和后继节点。

代码详解:

 void postThreadList(Node root) {
        //1、找后序遍历方式开始的节点
        Node node = root;
        while(node != null && !node.isLeftThread) {
            node = node.left;
        }

        Node preNode = null;
        while(node != null) {
            //右节点是线索
            if(node.isRightThread) {
                System.out.print(node.data + ", ");
                preNode = node;
                node = node.right;

            } else {
                //如果上个处理的节点是当前节点的右节点
                if(node.right == preNode) {
                    System.out.print(node.data + ", ");
                    if(node == root) {
                        return;
                    }

                    preNode = node;
                    node = node.parent;

                } else {    //如果从左节点的进入则找到有子树的最左节点
                    node = node.right;
                    while(node != null && !node.isLeftThread) {
                        node = node.left;
                    }
                }
            }
        }
    }

 测试代码:

 public static void main(String[] args) {
        String[] array = {"1","3","6","8","10","14"};
        Node root = createBinaryTree(array, 0);

        PostTreadBinaryTree tree = new PostTreadBinaryTree();
        tree.postThreadOrder(root);
        System.out.println("后序按后继节点遍历线索二叉树结果:");
        tree.postThreadList(root);
    }

该测试结果(遍历测试结果)与后序遍历的结果 一致

测试结果:

最后,后序线索化的详细代码,有需要可以自己查看:

//后序线索化
public class PostTreadBinaryTree {

    private Node preNode;   //线索化时记录前一个节点

    //节点存储结构
    static class Node {
        String data;        //数据域
        Node left;          //左指针域
        Node right;         //右指针域
        Node parent;        //父节点的指针(为了后序线索化使用)
        boolean isLeftThread = false;   //左指针域类型  false:指向子节点、true:前驱或后继线索
        boolean isRightThread = false;  //右指针域类型  false:指向子节点、true:前驱或后继线索

        Node(String data) {
            this.data = data;
        }
    }

    /**
     * 通过数组构造一个二叉树(完全二叉树)
     * @param array
     * @param index
     * @return
     */
    static Node createBinaryTree(String[] array, int index) {
        Node node = null;

        if(index < array.length) {
            node = new Node(array[index]);
            node.left = createBinaryTree(array, index * 2 + 1);
            node.right = createBinaryTree(array, index * 2 + 2);

            //记录节点的父节点(后序线索化遍历时使用)
            if(node.left != null) {
                node.left.parent = node;
            }

            if(node.right != null) {
                node.right.parent = node;
            }
        }

        return node;
    }

    /**
     * 后序线索化二叉树
     * @param node  节点
     */
    void postThreadOrder(Node node) {
        if(node == null) {
            return;
        }

        //处理左子树
        postThreadOrder(node.left);
        //处理右子树
        postThreadOrder(node.right);

        //左指针为空,将左指针指向前驱节点
        if(node.left == null) {
            node.left = preNode;
            node.isLeftThread = true;
        }

        //前一个节点的后继节点指向当前节点
        if(preNode != null && preNode.right == null) {
            preNode.right = node;
            preNode.isRightThread = true;
        }
        preNode = node;
    }

    /**
     * 后续遍历线索二叉树,按照后继方式遍历(思路:后序遍历开始节点是最左节点)
     * @param
     */
    void postThreadList(Node root) {
        //1、找后序遍历方式开始的节点
        Node node = root;
        while(node != null && !node.isLeftThread) {
            node = node.left;
        }

        Node preNode = null;
        while(node != null) {
            //右节点是线索
            if(node.isRightThread) {
                System.out.print(node.data + ", ");
                preNode = node;
                node = node.right;

            } else {
                //如果上个处理的节点是当前节点的右节点
                if(node.right == preNode) {
                    System.out.print(node.data + ", ");
                    if(node == root) {
                        return;
                    }

                    preNode = node;
                    node = node.parent;

                } else {    //如果从左节点的进入则找到有子树的最左节点
                    node = node.right;
                    while(node != null && !node.isLeftThread) {
                        node = node.left;
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        String[] array = {"1","3","6","8","10","14"};
        Node root = createBinaryTree(array, 0);

        PostTreadBinaryTree tree = new PostTreadBinaryTree();
        tree.postThreadOrder(root);
        System.out.println("后序按后继节点遍历线索二叉树结果:");
        tree.postThreadList(root);
    }
}

小结:

1. 前序线索化二叉树遍历相对最容易理解,实现起来也比较简单。由于前序遍历的顺序是:根左右,所以从根节点开始,沿着左子树进行处理,当子节点的left指针类型是线索时,说明到了最左子节点,然后处理子节点的right指针指向的节点,可能是右子树,也可能是后继节点,无论是哪种类型继续按照上面的方式(先沿着左子树处理,找到子树的最左子节点,然后处理right指针指向),以此类推,直到节点的right指针为空,说明是最后一个,遍历完成。 
2. 中序线索化二叉树的网上相关介绍最多。中序遍历的顺序是:左根右,因此第一个节点一定是最左子节点,先找到最左子节点,依次沿着right指针指向进行处理(无论是指向子节点还是指向后继节点),直到节点的right指针为空,说明是最后一个,遍历完成。 
3. 后序遍历线索化二叉树最为复杂,通用的二叉树数节点存储结构不能够满足后序线索化,因此我们扩展了节点的数据结构,增加了父节点的指针。后序的遍历顺序是:左右根,先找到最左子节点,沿着right后继指针处理,当right不是后继指针时,并且上一个处理节点是当前节点的右节点,则处理当前节点的右子树,遍历终止条件是:当前节点是root节点,并且上一个处理的节点是root的right节点。

小结转载自:后序线索化二叉树(Java版)_线索二叉树的后序遍历-CSDN博客
 

博客到这里也是结束了,制作不易,喜欢的小伙伴可以点赞加关注支持下博主,这对我真的很重要~~

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/391558.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一起学量化之RSI指标

RSI指标 Relative Strength Index,相对强弱指数(RSI),是一个衡量资产过度买入或过度卖出状态的技术指标。 1. RSI的基本概念 当RSI超过70时,通常被认为是超买状态。当RSI低于30时,通常被认为是超卖状态。RSI超过80,被认为是严重超买状态。RSI低于20,被认为是严重超卖状…

微波炉维修笔记

微波主要是靠2.45GHz 左右的微波(12.2cm 波长)加热水分子实现食物加热 所有不要使用金属器皿进行加热&#xff0c;要么因为电磁屏蔽&#xff0c;起不到加热效果&#xff0c;要么火光四射 微波炉基本组成 借鉴姜师傅的视频 碰到不加热其它都正常的问题 1.检查高压电容 使用万…

第10章 JDBC

10.1 什么是JDBC JDBC的全称是Java数据库连接&#xff08;Java Database Connectivity&#xff09;&#xff0c;它是一套用于执行SQL语句的Java API。应用程序可通过这套API连接到关系型数据库&#xff0c;并使用SQL语句完成对数据库中数据的新增、删除、修改和查询等操作。 …

Trie 字典树的两种实现方式

Trie&#xff0c;又称字典树、单词查找树或键树&#xff0c;是一种树形结构&#xff0c;是一种哈希树的变种。典型应用是用于统计&#xff0c;排序和保存大量的字符串&#xff08;但不仅限于字符串&#xff09;&#xff0c;所以经常被搜索引擎系统用于文本词频统计。它的优点是…

github Two-factor authentication (2FA)is required for your GitHub account

问题 github 2FA认证 详细问题 笔者使用GitKraken&#xff0c;使用github登录&#xff0c;github要去 Two-factor authentication (2FA)is required for your GitHub account&#xff0c;即进行2FA认证 解决方案 解决方案一、 微信 → \rightarrow →搜索腾讯身份验证器…

内存块与内存池

&#xff08;1&#xff09;在运行过程中&#xff0c;MemoryPool内存池可能会有多个用来满足内存申请请求的内存块&#xff0c;这些内存块是从进程堆中开辟的一个较大的连续内存区域&#xff0c;它由一个MemoryBlock结构体和多个可供分配的内存单元组成&#xff0c;所有内存块组…

java 培训班预定管理系统Myeclipse开发mysql数据库web结构jsp编程servlet计算机网页项目

一、源码特点 java 培训班预定管理系统是一套完善的java web信息管理系统 采用serlvetdaobean&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xf…

java 宠物医院系统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目

一、源码特点 java 宠物医院系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

Excel如何把窗口冻结,在下拉滚动条的时候仍然可以看到前几行数据?

** 共分2个情况&#xff1a; ①&#xff1a; 冻结首行&#xff1a; 作用&#xff1a;只冻结第一行的数据窗口。在下拉滚动条时&#xff0c;首行不会动&#xff0c;其他数据行会动步骤如下&#xff1a;1、鼠标放在首行的最左边&#xff0c;然后左键点一下先选中整行2、然后&am…

OpenAI发布Sora技术报告深度解读!真的太强了!

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主、前后端开发、人工智能研究生。公粽号&#xff1a;洲与AI。 &#x1f388; 本文专栏&#xff1a;本文收录…

IP地址+子网掩码+CIDR学习笔记

目录 一、IP地址 1、表示方法&#xff1a; 2、特殊IP地址 二、子网掩码 1、判断网络位和主机位 2、子网划分 三、无分类编址CIDR 1、CIDR路由汇聚 汇聚规则&#xff1a; 汇聚ID&#xff1a; 2、最佳路由匹配原则 一、IP地址 1、表示方法&#xff1a; 机器中存放的…

UE Get节点和源码

文章目录 概要UE Get节点有哪些常见的应用场景相关源码 概要 UE Get节点在Unreal Engine的蓝图系统中用于获取变量的值。这个节点通常用于从变量中读取数据&#xff0c;以便在游戏的逻辑流程中使用。 要使用Get节点&#xff0c;你首先需要有一个已经定义的变量。然后&#xf…

电梯控制系列之电梯结构介绍

这篇博客介绍单部10层电梯的完整控制程序框架编写过程&#xff0c;编程语言&#xff1a;SCL&#xff0c;控制器型号&#xff1a;S7-1200PLC。本篇博客介绍和电梯控制相关的一些电梯结构介绍。本文只可作为学习参考资料&#xff0c;行业控制需要遵循电梯安全相关规范。 1、电梯…

【Linux系统化学习】缓冲区

目录 缓冲区 一个样例 现象解释 缓冲区存在的位置 缓冲区 在刚开始学习C语言的时候我们就听过缓冲区这个名词&#xff0c;很是晦涩难懂&#xff1b;在Linux下进程退出时也包含缓冲区&#xff0c;因此缓冲区到底是什么&#xff1f;有什么作用&#xff1f; 让我们先从一个小…

微服务—DSL基础语法与RestClient操作

本博客为个人学习笔记&#xff0c;学习网站&#xff1a;黑马程序员SpringCloud 2021教程 目录 DSL语法 索引库操作 mapping属性 创建索引库 字段拷贝 查询、删除、修改索引库 文档操作 新增文档 查询、删除文档 修改文档 全量修改 增量修改 DSL文档语法小结 Rest…

JWT登录验证前后端设计与实现笔记

设计内容 前端 配置全局前置路由守卫axios拦截器登录页面和主页 后端 JWT的封装登录接口中间件放行mysql数据库的连接 详细设计 路由设计 配置全局前置守卫&#xff0c;如果访问的是登录页面则放行&#xff0c;不是则进入判断是否有token&#xff0c;没有则拦截回到登录…

17-k8s控制器资源-job控制

job控制器&#xff1a;就是一次性任务的pod控制器&#xff0c;pod完成作业后不会重启&#xff0c;其重启策略是&#xff1a;Never 1&#xff0c;job控制器案例描述 启动一个pod&#xff0c;执行完成一个事件&#xff0c;然后pod关闭&#xff1b; 事件&#xff1a;计算π的值&a…

[java基础揉碎]类与对象

目录 类与对象的引出: 类与对象的概述: 类与对象在内存中的布局: 属性的注意细节: 类与对象在内存中创建的过程: 类与对象的引出: 例如这样一个问题: 如果用单独变量来解决, 就会有一个问题, 不利于数据的管理, 将所有猫的信息都给拆解了: 如果用数组来解决, 则会有 1)数…

第三百五十回

文章目录 1. 概要介绍2. 获取方法2.1 获取语言2.2 获取地址 3.示例代码3. 内容总结 我们在上一章回中介绍了"给geolocator插件提交问题"相关的内容&#xff0c;本章回中将介绍如何获取系统语言.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概要介绍 我们在本…

书生浦语-模型微调

大语言模型微调 指令微调的流程 LoRA(旁路分支微调) Xtuner微调框架 微调训练 作业 微调作业需要多训练几个epoch&#xff0c;这里训练了16个epoch