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

news2025/1/17 3:18:05

一、二叉查找树

二叉查找树(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.coloradmin.cn/o/2214484.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity DOTS中的Archetype与Chunk

Unity DOTS中的Archetype与Chunk 在Unity中&#xff0c;archetype&#xff08;原型&#xff09;用来表示一个world里具有相同component类型组合的entity。也就是说&#xff0c;相同component类型的entity在Unity内部会存储到一起&#xff0c;共享同一个archetype。 使用这样的设…

JAVA毕业设计191—基于Java+Springboot+vue的电子产品商城管理系统(源代码+数据库)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootvue的电子产品商城管理系统(源代码数据库)191 一、系统介绍 本项目前后端不分离&#xff0c;分为用户、管理员两种角色 1、用户&#xff1a; 注册、登录、商品…

C++在vscode中的code runner配置/环境配置

C在vscode中快捷运行&#xff08;code runner&#xff09; 一、配置tasks.json 在vscode中创建文件夹或打开文件夹&#xff0c;会发现文件夹下多了一个.vscode文件夹&#xff0c;在该文件夹下创建tasks.json文件&#xff0c;并添加一下内容 {"version": "2.0…

弘景光电:以创新为翼,翱翔光学科技新蓝海

在科技日新月异的今天&#xff0c;光学镜头及模组作为智能设备的核心组件&#xff0c;其重要性日益凸显。广东弘景光电科技股份有限公司&#xff08;以下简称“弘景光电”&#xff09;正是在这一领域中&#xff0c;凭借其卓越的研发实力和市场洞察力&#xff0c;即将在创业板上…

工具篇:(二)MacOS 下载 MySQL 并进行配置连接,使用 VSCode 创建 Node 项目-亲测有效

MacOS 下载 MySQL 并进行配置连接&#xff0c;使用 VSCode 创建 Node 项目 我们将介绍如何在 macOS 上下载和配置 MySQL 数据库&#xff0c;并使用 VSCode 创建一个 Node.js 项目进行测试。通过这些步骤&#xff0c;您将能够顺利地设置开发环境并进行基本的数据操作。 一、删…

【国际学术会议之都,IEEE出版】第四届计算机科学、电子信息工程和智能控制技术国际会议(CEI 2024,2024年11月8-10日)

第四届计算机科学、电子信息工程和智能控制技术国际会议&#xff08;CEI 2024&#xff09; 2024 4th International Conference on Computer Science, Electronic Information Engineering and Intelligent Control Technology 官方信息 会议官网&#xff1a;www.ic-cei.org …

AFSim仿真系统 --- 系统简解_10处理器 (Processors)

处理器 (Processors) 处理器提供了为特定平台定义行为的能力。 大多数处理器由用户使用 AFSIM 脚本语言定义。 以下是一些预定义的处理器类型&#xff1a; WSF_DIRECTION_FINDER_PROCESSORWSF_TRACK_PROCESSORWSF_MESSAGE_PROCESSORWSF_GUIDANCE_COMPUTERWSF_IMAGE_PROCESS…

Android11 USB Camera会出现预览绿屏问题

目录 一、问题描述 二、问题原因 三、解决方法 一、问题描述 DDR容量是4G及以上的机器&#xff0c;USB Camera会出现预览绿屏问题。 串口中会刷如下log: 二、问题原因 RGA2使用超过4G内存会异常&#xff0c;导致USB Camera调用rga相关操作报错&#xff0c;从而预览绿屏 三…

深度学习基础—神经风格迁移

1.什么是神经风格迁移 神经风格迁移就是将一张图片的风格迁移到另一张图片上&#xff0c;生成具有第一张图片风格的新的图片。新图片的主体还是第二张图片&#xff0c;但是风格是第一张图片的。 如下两组图片都是神经风格迁移的例子&#xff1a; 将绘画的风格迁移到真实建筑图片…

树型名称前面插入图片

需求&#xff1a; 搜索树、树型要显示连线&#xff0c;还有名称前带图片 ui组件&#xff1a;https://devui.design/components/zh-cn/overview 直接上代码 [checkable] false 表示取消复选框 <div class"p-sm"><div class"row"><d-sea…

软件开发----Java基础每日刷题(转载于牛客)

1. 对抽象类的描述正确的是() A 抽象类的方法都是抽象方法 B 一个类可以继承多个抽象类 C 抽象类不能有构造方法 D 抽象类不能被实例化 正确答案&#xff1a;D 解析&#xff1a; A.抽象类可以有非抽象的方法&#xff0c;而接口中的方…

Flythings学习(三)界面交互

文章目录 1 界面切换1.1 打开界面1.2 关闭界面 2 界面活动周期2.1 打开不存在页面的活动流程2.2 打开已存在界面&#xff08;被隐藏的界面&#xff09;2.3 关闭界面的流程 1 界面切换 界面切换的相关函数如下 1.1 打开界面 如果需要打开一个界面&#xff0c;在其他界面的控件…

WebSocket状态码及异常报错1006

文章目录 1.WebSocket协议简介2.WebSocket状态码的作用&#xff1a;3.WebSocket状态码1006详解1.问题原因2.解决方案 1.WebSocket协议简介 WebSocket协议是一种基于TCP的协议&#xff0c;它通过在浏览器和服务器之间建立一条持久的双向通信通道&#xff0c;实现了实时的数据传…

【论文阅读】SAM 2: 分割一切图像和视频

导言 继SAM模型发布以来&#xff0c;Meta公司于2024年8月发布第二个图像分割大模型SAM2。相较于第一代SAM模型&#xff0c;论文提出了第二代“分割任意物体模型” (SAM 2)&#xff0c;旨在解决视频中的可提示视觉分割任务&#xff08;Promptable Visual Segmentation, PVS&…

TVS常规过压保护

一、前言 上一篇文章 TVS选型-CSDN博客https://blog.csdn.net/qq_39543984/article/details/142825929?spm=1001.2014.3001.5501我们介绍了如何通过理论计算选择合适的TVS,TVS主要是防止瞬间过压,因为他的名字就叫瞬态二极管(Transient Voltage Suppressor)。本文就通过理…

自动化检查网页的TDK,python+selenium自动化测试web的网页源代码中的title,Description,Keywords

首先&#xff0c;TDK是什么&#xff1f;对于新手小白来说&#xff0c;可能是懵逼的&#xff0c;所以这里给出一个官方的解说‌网页的TDK是指标题&#xff08;Title&#xff09;、描述&#xff08;Description&#xff09;和关键词&#xff08;Keywords&#xff09;的集合‌。这…

智慧船舶物联网实训室建设方案

第一章 建设背景 随着全球海洋经济的蓬勃发展与智能化技术的日新月异&#xff0c;数字船舶物联网&#xff08;Internet of Things for Maritime, IoT-Maritime&#xff09;与人工智能&#xff08;Artificial Intelligence, AI&#xff09;的结合已成为推动航运业转型升级的关键…

企业资源枯竭时,数字化转型能否带来新资源?

​在商业竞争激烈的当下&#xff0c;企业发展依赖各类资源。然而&#xff0c;资源可能面临枯竭&#xff0c;如原材料短缺、市场份额下降、人才流失等。此时&#xff0c;数字化转型成为企业突破困境的重要途径&#xff0c;那么它能否带来新资源呢&#xff1f; 先看企业资源分类。…

C++,STL 031(24.10.14)

内容 stack容器&#xff08;栈&#xff09;的常用接口。 代码 #include <iostream> #include <stack> // 注意包含stack容器&#xff08;栈&#xff09;的头文件using namespace std;void test01() {stack<int> s1; // here01&#xff0c;默认构造stack<…

5g工业路由器最新案例:高原气象站网络升级项目

背景&#xff1a; 某省气象局决定在高原地区升级其气象观测网络&#xff0c;以提高天气预报的准确性和及时性&#xff0c;同时为气候变化研究提供更可靠的数据支持。该项目面临以下挑战&#xff1a; 需要在高原广袤且地形复杂的区域部署大量自动气象站&#xff0c;要求网络覆…