二叉查找树(Binary Search Tree)Java语言实现

一、二叉查找树

二叉查找树(Binary Search Tree),也称为二叉搜索树、有序二叉树(Ordered Binary Tree)或排序二叉树(Sorted Binary Tree)。

是指一棵空树或者具有下列性质的二叉树:

  1. 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
  2. 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
  3. 任意节点的左、右子树也分别为二叉查找树;

下图即为一个二叉查找树:
在这里插入图片描述

二叉查找树相比于其他数据结构的优势在于查找、插入的时间复杂度较低,为O(log⁡n)。

二叉查找树的左子树结点值小于根结点值小于右子树结点值特点,使得其中序遍历的结果始终为顺序的。

二、二叉查找树的操作

1. 二叉搜索树的查找

根据二叉搜索树的特性依次比较val与各个节点值的大小,从而查找与val相等的节点。

在二叉查找树b中查找val的过程为:
step1. 若b是空树,则搜索失败:
step 2. 若val等于b的根节点的数据域之值,则查找成功;
step 3. 若val小于b的根节点的数据域之值,则搜索左子树;若val小于b的根节点的数据域之值,则搜索右子树

例1:查找关键字为30的结点
(1)首先从根节点19开始,发现19 小于 30,所以对以50作为根节点的右子树进行下一轮搜索;
(2)然后以此右子树为基准继续查找,发现50 大于 30,所以对以26作为根节点的左子树进行下一轮搜索;
(3)然后以此左子树为基准继续查找,发现26 小于 30,所以对以30作为根节点的右子树进行下一轮搜索;
(4)最后以此右子树为基准继续查找,发现30 等于 30,查找成功。
在这里插入图片描述
例2:查找关键字为12的结点
(1)首先从根节点19开始,发现19 大于 12,所以对以13作为根节点的左子树进行下一轮搜索;
(2)然后以此左子树为基准继续查找,发现11 小于 30,但是11是叶子结点,即它没有右子树,所以判断出该二叉排序树中没有值为12的节点,搜索失败。

在这里插入图片描述
示例代码如下:

    public void get(int val) {TreeNode currentNode = root;TreeNode findTreeNode = new TreeNode();while (currentNode != null) {if (currentNode.val > val) { // 当前节点比将要插入的值大currentNode = currentNode.left; // 去根节点左子树中继续寻找} else if (currentNode.val < val) { // 当前节点比将要插入的值小currentNode = currentNode.right; // 去根节点右子树中继续寻找} else if (currentNode.val == val)  {findTreeNode = currentNode; //相等,则currentNode是要寻找的节点。System.out.println(findTreeNode.val + " has been found!");return;}}System.out.println("Error! " + val + " does not exist!");}

2.在二叉搜索树中插入节点

要插入节点,必须先找到插入的位置。由于二叉搜索树的特殊性,待插入的节点需要从根节点开始进行比较。小于根节点则与根节点左子树比较,反之则与右子树比较,直到左子树为空或右子树为空,则插入到相应为空的位置。

在比较的过程中要注意保存父节点的信息及待插入的位置是父节点的左子树还是右子树。

将val插入到二叉搜索树r的具体流程如下:
step1.若二叉搜索树r是空树,则将val所指节点作为根节点插入;
step2.若val等于二叉搜索树r的根节点的值,则返回“val已经存在于该二叉搜索树中”;
step3.若val小于二叉搜索树r的根节点的值,则将左子树作为下一轮的根节点并返回step1;若val大于二叉搜索树的根节点的值,则将左子树作为下一轮的根节点并返回step1。(新插入节点总是叶子节点)

例:插入关键字为12的结点(新插入的节点一定是叶子结点)
在这里插入图片描述

    public void insert(int val) {TreeNode treeNode = new TreeNode();treeNode.val = val;if (root == null) { // 如果根节点为空,说明是个空树root = treeNode;System.out.println(val + " has been inserted into the binary tree!");} else {TreeNode currentNode = root; // 要插入位置的节点,初始为root,从根节点依次寻找TreeNode parentNode = null; // 要插入位置的父节点while (currentNode != null) {parentNode = currentNode;if (currentNode.val > val) { // 当前节点比将要插入的值大currentNode = currentNode.left; // 与根节点左子树比较if (currentNode == null) { // 若左节点为空 则直接插入即可parentNode.left = treeNode;System.out.println(val + " has been inserted into the binary tree!");break;}	} else if (currentNode.val < val) { // 当前节点比将要插入的值小currentNode = currentNode.right; // 与根节点右子树比较if (currentNode == null) { // 若右节点为空 则直接插入即可parentNode.right = treeNode;System.out.println(val + " has been inserted into the binary tree!");break;}} else {System.out.println(val + " repeats!");break;}}}}

3.二叉查找树的构造(根据数组的元素创建二叉查找树)

按照二叉树插入节点的规则,依次将数组中每个元素作为节点插入到二叉树中,即可完成二叉树的构造。
例1:按照序列str={50, 66, 60, 26, 21, 30, 70, 68}建立二叉查找树
在这里插入图片描述
例2:按照序列str={50, 26, 21, 30, 66, 60, 70, 68}建立二叉查找树
在这里插入图片描述
例3:按照序列str={26, 21, 30, 50, 60, 66, 68, 70}建立二叉查找树在这里插入图片描述
由构造后的结果可以观察到,例1与例2构造出了相同的二叉排序树,而例3构造出了与前两者不同的二叉排序树。

结论:不同的关键字序列可能得到同款二叉排序树,也可能得到不同款二叉排序树

    public void createTree(int[] nums) {root = new TreeNode(nums[0]); // 数组第一个为根节点for (int i = 1; i < nums.length; i++) { // 从第二个元素开始迭代TreeNode treeNode = new TreeNode();treeNode.val = nums[i];            TreeNode currentNode = root; // 要插入位置的节点,初始为root,从根节点依次寻找TreeNode parentNode = null; // 要插入位置的父节点while (currentNode != null) {parentNode = currentNode;if (currentNode.val > nums[i]) { // 当前节点比将要插入的值大currentNode = currentNode.left; // 与根节点左子树比较if (currentNode == null) { // 若左节点为空 则直接插入即可parentNode.left = treeNode;System.out.println(nums[i] + " has been inserted into the binary tree!");break;}} else if (currentNode.val < nums[i]) { // 当前节点比将要插入的值小currentNode = currentNode.right; // 与根节点右子树比较if (currentNode == null) { // 若右节点为空 则直接插入即可parentNode.right = treeNode;System.out.println(nums[i] + " has been inserted into the binary tree!");break;}} else {System.out.println(nums[i]+" repeats!");break;}}            }}

4.删除与val值相同的节点

由于是二叉搜索树,删除与val值相等的“z”节点共三种情况

情况1: z节点是叶子节点,由于删去叶子结点不破坏整棵树的结构,则只需修改其双亲结点的指针即可,即直接删除currentNode节点。
在这里插入图片描述

情况2: z节点有一个叶子节点(可能是左子节点leftNode或者右子节点rightNode),此时只要令左子节点leftNode或右子节点rightNode直接成为z的双亲结点的左子树即可,作此修改也不破坏二叉查找树的特性。
在这里插入图片描述

情况3: z节点有两个叶子节点(左子节点leftNode和右子节点rightNode),在删去z之后,为保持其它元素之间的相对位置不变,可按中序遍历保持有序进行调整。
具体方案为:则令z的直接后继(或直接前驱)节点p替代z,然后从二叉排序树中删去这个直接后继(或直接前驱),这样就转换成了第一或第二种情况。

  • z的后继:z的右子树中最左下结点(该节点一定没有左子树)
  • z的前驱 :z的左子树中最右下结点(该节点一定没有右子树)

例:删除值为50的节点z。
方法一:删除直接后继
在这里插入图片描述

方法二:删除直接前驱
在这里插入图片描述

    public void remove(int val) {TreeNode currentNode = root;TreeNode parentNode = null; // 要插入位置的父节点boolean isLeftChild = false; // 判断是父节点的左子树还是右子树TreeNode findTreeNode = new TreeNode();//寻找删除的节点while (currentNode != null && currentNode.val != val) {parentNode = currentNode;if (currentNode.val > val) { // 当前节点比将要插入的值大currentNode = currentNode.left; // 去根节点左子树中继续寻找isLeftChild = true;} else if (currentNode.val < val) { // 当前节点比将要插入的值小currentNode = currentNode.right; // 去根节点右子树中继续寻找isLeftChild = false;}}findTreeNode = currentNode;//    	System.out.println(currentNode.val + " has been find!");// 1 如果该节点是叶子节点,只用将其叶子节点删掉即可。if (currentNode.left == null && currentNode.right == null) {if (currentNode == root) { // 是根节点,即该树只有一个节点currentNode = null;} else if (isLeftChild) { // 是其父节点的左子树节点parentNode.left = null;} else if (!isLeftChild) { // 是其父节点的右子树节点parentNode.right = null;}} else if(currentNode.left != null && currentNode.right == null) {// 2 该节点有一个叶子节点,叶子结点为左节点if (currentNode == root) { // 是根节点,即该树只有一个节点currentNode = currentNode.left;} else if (isLeftChild) { // 是其父节点的左子树节点parentNode.left = currentNode.left;} else if (!isLeftChild) { // 是其父节点的右子树节点parentNode.right = currentNode.left;}} else if(currentNode.left == null && currentNode.right != null) {	// 2 该节点有一个叶子节点,叶子结点为右节点if (currentNode == root) { // 是根节点,即该树只有一个节点currentNode = currentNode.right;} else if (isLeftChild) { // 是其父节点的左子树节点parentNode.left = currentNode.right;} else if (!isLeftChild) { // 是其父节点的右子树节点parentNode.right = currentNode.right;}} else {// 3 该节点有两个叶子节点//删除节点用左子树中最大值结点(前驱节点)代替,或右子树最小值节点(后继节点)代替// 寻找右子树最小值节点,即后继节点TreeNode successorNode = currentNode; // 后继节点TreeNode successorParent  = currentNode; // 后继节点的父节点TreeNode rightCurrentNode  = currentNode.right; // 先进入当前节点的右子树while (rightCurrentNode != null) {successorParent = successorNode;successorNode = rightCurrentNode;rightCurrentNode = rightCurrentNode.left; // 寻找右子树的左子树(寻找最小值)}//successorNode的左子树成为其父节点的右子树// 然后其右子树更新指向currentNode的右子树if(successorNode != currentNode.right) {successorParent.left = successorNode.right;successorNode.right = currentNode.right;}// 开始删除if (currentNode == root) { // 是根节点,即该树只有一个节点currentNode = successorNode;} else if (isLeftChild) { // 是其父节点的左子树节点parentNode.left = successorNode;} else if (!isLeftChild) { // 是其父节点的右子树节点parentNode.right = successorNode;}successorNode.left = currentNode.left; // 更新左节点}System.out.println(findTreeNode.val + " has been removed!");}

三、二叉搜索树操作的完整代码(包含测试)

import java.util.LinkedList;
import java.util.Queue;public class BinarySortTree {// Definition for a binary tree node.public class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) {this.val = val;}TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}}TreeNode root; // 新建根节点/** 根据数组的元素直接创建二叉树*/public void createTree(int[] nums) {root = new TreeNode(nums[0]); // 数组第一个为根节点for (int i = 1; i < nums.length; i++) { // 从第二个元素开始迭代TreeNode treeNode = new TreeNode();treeNode.val = nums[i];            TreeNode currentNode = root; // 要插入位置的节点,初始为root,从根节点依次寻找TreeNode parentNode = null; // 要插入位置的父节点while (currentNode != null) {parentNode = currentNode;if (currentNode.val > nums[i]) { // 当前节点比将要插入的值大currentNode = currentNode.left; // 与根节点左子树比较if (currentNode == null) { // 若左节点为空 则直接插入即可parentNode.left = treeNode;System.out.println(nums[i] + " has been inserted into the binary tree!");break;}} else if (currentNode.val < nums[i]) { // 当前节点比将要插入的值小currentNode = currentNode.right; // 与根节点右子树比较if (currentNode == null) { // 若右节点为空 则直接插入即可parentNode.right = treeNode;System.out.println(nums[i] + " has been inserted into the binary tree!");break;}} else {System.out.println(nums[i]+" repeats!");break;}}            }}/*** 在二叉树中插入节点* 要插入节点,必须先找到插入的位置。* 由于二叉搜索树的特殊性,待插入的节点需要从根节点开始进行比较* 小于根节点则与根节点左子树比较,反之则与右子树比较,直到左子树为空或右子树为空* 则插入到相应为空的位置* 在比较的过程中要注意保存父节点的信息及待插入的位置是父节点的左子树还是右子树* @param val*/public void insert(int val) {TreeNode treeNode = new TreeNode();treeNode.val = val;if (root == null) { // 如果根节点为空,说明是个空树root = treeNode;System.out.println(val + " has been inserted into the binary tree!");} else {TreeNode currentNode = root; // 要插入位置的节点,初始为root,从根节点依次寻找TreeNode parentNode = null; // 要插入位置的父节点while (currentNode != null) {parentNode = currentNode;if (currentNode.val > val) { // 当前节点比将要插入的值大currentNode = currentNode.left; // 与根节点左子树比较if (currentNode == null) { // 若左节点为空 则直接插入即可parentNode.left = treeNode;System.out.println(val + " has been inserted into the binary tree!");break;}	} else if (currentNode.val < val) { // 当前节点比将要插入的值小currentNode = currentNode.right; // 与根节点右子树比较if (currentNode == null) { // 若右节点为空 则直接插入即可parentNode.right = treeNode;System.out.println(val + " has been inserted into the binary tree!");break;}} else {System.out.println(val + " repeats!");break;}}}}// 查找与val数值相等的节点public void get(int val) {TreeNode currentNode = root;TreeNode findTreeNode = new TreeNode();while (currentNode != null) {if (currentNode.val > val) { // 当前节点比将要插入的值大currentNode = currentNode.left; // 去根节点左子树中继续寻找} else if (currentNode.val < val) { // 当前节点比将要插入的值小currentNode = currentNode.right; // 去根节点右子树中继续寻找} else if (currentNode.val == val)  {findTreeNode = currentNode; //相等,则currentNode是要寻找的节点。System.out.println(findTreeNode.val + " has been found!");return;}}System.out.println("Error! " + val + " does not exist!");}/*** 删除与val值相同的节点* 删除共三种情况* 1 该节点是叶子节点* 2 该节点有一个叶子节点* 3 该节点有两个叶子节点* @param val*/public void remove(int val) {TreeNode currentNode = root;TreeNode parentNode = null; // 要插入位置的父节点boolean isLeftChild = false; // 判断是父节点的左子树还是右子树TreeNode findTreeNode = new TreeNode();//寻找删除的节点while (currentNode != null && currentNode.val != val) {parentNode = currentNode;if (currentNode.val > val) { // 当前节点比将要插入的值大currentNode = currentNode.left; // 去根节点左子树中继续寻找isLeftChild = true;} else if (currentNode.val < val) { // 当前节点比将要插入的值小currentNode = currentNode.right; // 去根节点右子树中继续寻找isLeftChild = false;}}findTreeNode = currentNode;//    	System.out.println(currentNode.val + " has been find!");// 1 如果该节点是叶子节点,只用将其叶子节点删掉即可。if (currentNode.left == null && currentNode.right == null) {if (currentNode == root) { // 是根节点,即该树只有一个节点currentNode = null;} else if (isLeftChild) { // 是其父节点的左子树节点parentNode.left = null;} else if (!isLeftChild) { // 是其父节点的右子树节点parentNode.right = null;}} else if(currentNode.left != null && currentNode.right == null) {// 2 该节点有一个叶子节点,叶子结点为左节点if (currentNode == root) { // 是根节点,即该树只有一个节点currentNode = currentNode.left;} else if (isLeftChild) { // 是其父节点的左子树节点parentNode.left = currentNode.left;} else if (!isLeftChild) { // 是其父节点的右子树节点parentNode.right = currentNode.left;}} else if(currentNode.left == null && currentNode.right != null) {	// 2 该节点有一个叶子节点,叶子结点为右节点if (currentNode == root) { // 是根节点,即该树只有一个节点currentNode = currentNode.right;} else if (isLeftChild) { // 是其父节点的左子树节点parentNode.left = currentNode.right;} else if (!isLeftChild) { // 是其父节点的右子树节点parentNode.right = currentNode.right;}} else {// 3 该节点有两个叶子节点//删除节点用左子树中最大值结点(前驱节点)代替,或右子树最小值节点(后继节点)代替// 寻找右子树最小值节点,即后继节点TreeNode successorNode = currentNode; // 后继节点TreeNode successorParent  = currentNode; // 后继节点的父节点TreeNode rightCurrentNode  = currentNode.right; // 先进入当前节点的右子树while (rightCurrentNode != null) {successorParent = successorNode;successorNode = rightCurrentNode;rightCurrentNode = rightCurrentNode.left; // 寻找右子树的左子树(寻找最小值)}//successorNode的左子树成为其父节点的右子树// 然后其右子树更新指向currentNode的右子树if(successorNode != currentNode.right) {successorParent.left = successorNode.right;successorNode.right = currentNode.right;}// 开始删除if (currentNode == root) { // 是根节点,即该树只有一个节点currentNode = successorNode;} else if (isLeftChild) { // 是其父节点的左子树节点parentNode.left = successorNode;} else if (!isLeftChild) { // 是其父节点的右子树节点parentNode.right = successorNode;}successorNode.left = currentNode.left; // 更新左节点}System.out.println(findTreeNode.val + " has been removed!");}// 树的先序遍历public void preOrderTraversal (TreeNode root) {if (root == null) {return;}System.out.print(root.val + " "); //先输出当前节点(初始的时候是root节点)preOrderTraversal(root.left); // 如果左子节点不为空,则递归继续前序遍历preOrderTraversal(root.right); // 如果右子节点不为空,则递归继续前序遍历}// 树的中序遍历public void inOrderTraversa (TreeNode root) {if (root == null) {return;}inOrderTraversa(root.left); // 如果当前节点的左子节点不为空,则递归中序遍历System.out.print(root.val + " "); // 输出当前节点inOrderTraversa(root.right); // 如果当前的右子节点不为空,则递归中序遍历		}// 树的后序遍历public void postOrderTraversal (TreeNode root) {if (root == null) {return;}postOrderTraversal(root.left); // 如果当前节点的左子节点不为空,则递归后序遍历postOrderTraversal(root.right); // 如果当前节点的右子节点不为空,则递归后序遍历System.out.print(root.val + " "); // 输出当前节点		}// 广度优先遍历,即树的层次遍历,借用队列实现public void levelOrderTraversal(TreeNode root) {if(root == null) {return;}    	Queue<TreeNode> queue = new LinkedList<TreeNode>(); // 存放每层操作的根节点queue.offer(root);        while (!queue.isEmpty()) {int queueSize = queue.size();for (int i = 0; i < queueSize; i++) { // 用for循换可以隔离开每一层的遍历TreeNode rootNode = queue.poll(); // 开始操作后将其从队列移除System.out.print(rootNode.val + " ");if (rootNode.left != null) {TreeNode leftNode = rootNode.left; // 左节点存入队列,下一层遍历它就成了新根节点	            queue.offer(leftNode);}if (rootNode.right != null) {TreeNode rightNode = rootNode.right; // 右节点存入队列,下一层遍历它就成了新根节点queue.offer(rightNode);}}}}public static void main(String[] args) {BinarySortTree binarySortTree = new BinarySortTree();binarySortTree.createTree(new int[]{7, 1, 5, 9, 3, 0, 2, 6, 8});binarySortTree.insert(4);binarySortTree.get(5);System.out.print("先序遍历:");binarySortTree.preOrderTraversal(binarySortTree.root);System.out.println();System.out.print("中序遍历:");binarySortTree.inOrderTraversa(binarySortTree.root);System.out.println();System.out.print("后序遍历:");binarySortTree.postOrderTraversal(binarySortTree.root);System.out.println();System.out.print("层次遍历:");binarySortTree.levelOrderTraversal(binarySortTree.root);System.out.println();binarySortTree.remove(3);System.out.print("先序遍历:");binarySortTree.preOrderTraversal(binarySortTree.root);System.out.println();System.out.print("中序遍历:");binarySortTree.inOrderTraversa(binarySortTree.root);System.out.println();System.out.print("后序遍历:");binarySortTree.postOrderTraversal(binarySortTree.root);System.out.println();System.out.print("层次遍历:");binarySortTree.levelOrderTraversal(binarySortTree.root);System.out.println();}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android 无Bug版 多语言设计方案!

出海业务为什么要做多语言&#xff1f; 1.市场扩大与本地化需求&#xff1a; 通过支持多种语言&#xff0c;出海项目可以触及更广泛的国际用户群体&#xff0c;进而扩大其市场份额。 本地化是吸引国际用户的重要策略之一&#xff0c;而语言本地化是其中的核心。使用用户的母语…

NFT Insider #151:The Sandbox 推出 Alpha 第4季;腾讯或将收购育碧

市场数据 加密艺术及收藏品新闻 Beeple 将于 11 月在南京德基美术馆举办个人首展 著名数字艺术家 Beeple 近日在X平台发布视频&#xff0c;宣布将于 2024 年 11 月 14 日在南京德基美术馆举办个人首次展览&#xff0c;名为《Beeple&#xff1a;来自合成未来的故事》。该展览将…

【计算机网络】详谈TCP协议确认应答机制捎带应答机制超时重传机制连接管理机制流量管理机制滑动窗口拥塞控制延迟应答

一、TCP 协议段格式 1.1、4位首部长度 4位首部长度的基本单位是4字节&#xff0c;也就是说如果4位首部长度填6&#xff0c;那报头长度就是24字节。报头长度的取值范围为[0,60]字节&#xff0c;也就是说选项的最大长度为40字节。 二、确认应答机制 发送数据和发送应答&#x…

vue3 在store的index.js

导入vuex&#xff0c;在store的index.js创建store对象 在main.js挂载store import store from ./storenew Vue ({/* 将store对象实例挂载到vue实例中 所有组件就可以直接从store中获取全局数据了*/ store, render: h > h(App) }).$mount(#app) 在store中的index.js进行声明…

Chainbase :链原生的 Web3 AI 基建设施

“随着 Chainbase 在生态系统和市场方面的进一步拓展&#xff0c;其作为链原生 Web3 AI 基建设施的价值将愈发显著。” 算法、算力和数据是 AI 技术的三大核心要素。实际上&#xff0c;几乎所有的 AI 大模型都在不断革新算法&#xff0c;以确保模型能够跟上行业的发展趋势&…

react实现实时计时的最简方式

js中时间的处理&#xff0c;不借助于moment/dayjs这样的工具库&#xff0c;原生获取格式化的时间&#xff0c;最简单的实现方式可以参考下面这样。 实现效果 代码实现 封装hooks import { useState, useEffect } from "react";export function useCountTime() {c…

手动nginx平滑升级

一、下载nginx安装包 wget http://nginx.org/download/nginx-1.24.0.tar.gz 二、解压缩 tar -zxf nginx-1.24.0.tar.gz 三、进入解压缩后文件 3.1 cd /usr/local/nginx/sbin 预编译 进入如下命令 ./configure -prefix/usr/local/nginx --with-http_ssl_module --with…

免费设计元素下载,设计师必备,建议收藏!

设计师找设计素材、免抠元素&#xff0c;背景图等等&#xff0c;就上这6个网站&#xff0c;免费下载&#xff01; 1、菜鸟图库 免抠图片素材-免抠图片模板免费下载 - 菜鸟图库 这是一个专门为新手设计师提供免费设计素材的网站&#xff0c;站内有非常多设计素材&#xff0c;其…

为什么说期限提醒系统是项目申报的必备工具?

在项目申报的征程中&#xff0c;时间就是生命&#xff0c;时机决定成败。然而&#xff0c;当前项目申报时间管理却面临着诸多棘手的问题&#xff0c;这也让期限提醒系统成为了必不可少的必备工具。那么&#xff0c;它究竟为何如此关键&#xff1f; 目前项目申报时间管理方面面临…

uniapp 锁屏显示插件 Ba-LockShow(可让vue直接具备锁屏显示能力)

简介 Ba-LockShow 是一款可以直接使uniapp的vue界面在锁屏页展示的插件。 支持使vue直接具备锁屏显示能力支持设置锁屏显示和不显示支持唤醒屏幕 截图展示&#xff08;仅参考&#xff09; 支持定制、本地包、源码等&#xff0c;有建议和需要&#xff0c;请点击文章结尾“Unia…

世界空间到观察空间的矩阵

1&#xff09;世界空间到观察空间的矩阵 2&#xff09;Addressable在不同工程中如何实现打包和加载 3&#xff09;如何设计角色在下蹲时允许跳跃 4&#xff09;如何实时编辑玩家的近裁剪面距离 这是第403篇UWA技术知识分享的推送&#xff0c;精选了UWA社区的热门话题&#xff0…

算法系列之十二:多边形区域填充算法--扫描线填充算法(有序边表法)

二、扫描线算法&#xff08;Scan-Line Filling&#xff09; 扫描线算法适合对矢量图形进行区域填充&#xff0c;只需要直到多边形区域的几何位置&#xff0c;不需要指定种子点&#xff0c;适合计算机自动进行图形处理的场合使用&#xff0c;比如电脑游戏和三维CAD软件的渲染等等…

智能优化算法-蛇优化算法(SO)(附源码)

目录 1.内容介绍 2.部分代码 3.实验结果 4.内容获取 1.内容介绍 蛇优化算法 (Snake Optimization Algorithm, SO) 是一种基于群体智能的元启发式优化算法&#xff0c;它模拟了蛇的捕食行为、运动模式和社会互动&#xff0c;用于解决复杂的优化问题。 SO的工作机制主要包括&a…

二分类-多机器学习模型算法实现对比

准备数据 import pandas as pd import numpy as np import matplotlib.pyplot as plt from sklearn.preprocessing import StandardScaler from sklearn.preprocessing import OneHotEncoder from sklearn.preprocessing import PolynomialFeatures from sklearn.compose impo…

每日一刷——10.14——括号匹配(手写栈来实现)

栈与队列题目 第一题 题目 问题描述】设计一个算法判别一个算术表达式的圆括号是否正确配对 【输入形式】一个以为结尾的算术表达式 【输出形式】若配对&#xff0c;则输出圆括号的对数&#xff1b;否则输出no 【样例输入】 (ab)/(cd) 【样例输出】 2 【样例说明】共有两对括…

学习Redisson实现分布式锁

官网&#xff1a;https://redisson.org/ 官方文档&#xff1a;https://redisson.org/docs/getting-started/ 官方中文文档&#xff1a;https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95 1、引入依赖 <!--redisson--> <dependency><groupId>or…

【软件工程】数据流图DFD

文章目录 数据流图DFD概述一、数据流图的基本元素二、数据流图的绘制步骤三、数据流图的分层设计四、数据流图的绘制原则五、数据流图的应用 一个完整的数据流包含哪些要素从图中找出所有数据流1. **理解数据流图的结构**2. **识别外部实体**3. **追踪数据流**4. **记录数据流*…

SAP S/4 HANA 销售返利

目录 1 简介 2 后台配置 3 主数据 4 业务操作 4.1 场景 1 - 返利应计 4.2 场景 2 - 最终结算 1 简介 在过去 SAP ECC 把“返利”功能集成在了 SD 模块当中&#xff0c;而 SAP S/4 HANA 把“返利”集成在了结算管理功能模块当中。究其原因&#xff0c;主要是 ECC “返利”…

笔记-stm32移植ucos

文章目录 一、UCOS的基础知识1.1 前后台系统:1.2 RTOS系统可剥夺型内核:前后台系统和RTOS系统 1.3 UCOS系统简介学习方法 二、ucossii移植Step1&#xff1a;在工程中建立存放UCOSS代码的文件夹UCOSIIStep2:向CORE文件夹添加文件Step3:向Config文件夹添加文件Step4:向port文件夹…

本地拉取Docker镜像打包导入远程服务器

起因是因为使用远程服务器拉取镜像时&#xff0c;由于网络问题一直拉不成功&#xff0c;使用国内镜像由于更新不及时&#xff0c;国内镜像没有最新的 docker 镜像。最后使用本地的计算机&#xff0c;通过代理下载最新的镜像后打包成 tar&#xff0c; 然后上传到远程服务器进行导…