数据结构——用Java实现二分搜索树

目录

一、树

二、二分搜索树

1.二叉树

2.二分搜索树

三、代码实现

1.树的构建

2.获取树中结点的个数

3.添加元素

4.查找元素

(1)查找元素是否存在

(2)查找最小元素

(3)查找最大元素

5.二分搜索树的遍历

(1)前序遍历:

(2)中序遍历:

(3)后序遍历:

(4)层序遍历:

6.删除操作

(1)删除最小元素

(2)删除最大元素

(3)删除任意元素

(4)删除根节点


一、树

        树结构本身是一种天然的组织结构

        是一个高效的查询内容的结构

二、二分搜索树

1.二叉树

特点:1.只有唯一的一个根节点

           2.每个结点最多有两个孩子

           3.每个结点最多有一个父亲

           4.二叉树具有天然的递归结构(左右子树也是二叉树)

           5.叶子结点出现在二叉树的最底层,除叶子结点之外的其它结点都有两个孩子结点。

2.二分搜索树

是特殊的二叉树

每个节点都大于左子树的所有结点,都小于右子树的所有结点

注意:存储的元素必须具有可比性

因为二分搜索树也是二叉树,也具有天然的递归结构,所以许多方法都可以使用递归的思想去实现

三、代码实现

1.树的构建

需要的元素有:根节点,结点,频率(如果添加的元素有重复元素),结点的值,索引,结点个数

//树的结点private static class Node<T> {private final T ele;//结点的值private int frequence;//频率private Node<T> left, right;//分别指向左右孩子的索引public Node(T ele) {this.ele = ele;this.left = this.right = null;}}//树对应的属性private Node<T> root;//树的根节点private int size;//结点的个数//构建树public BinearySeachTree() {this.root = null;this.size = 0;}

在给元素添加泛型后,就不能直接比较,所以在开始就继承Comparable来实现元素的比较

public class BinearySeachTree<T extends Comparable<T>>{}

2.获取树中结点的个数

//获取树中结点的个数public int getSize() {return this.size;}

3.添加元素

将元素添加到二分搜索树的过程中,要注意将大的元素放在结点的右边,小的元素放在左边

再添加元素时,需要找到对应的位置,则可以使用递归的思想。

如果添加的值小于结点的值,则查找结点左孩子,如果还是小于结点,则继续查找

//向树中添加结点public void add(T ele) {//更新根结点this.root = addDG(this.root, ele);}//语义:向以root为根的二分搜索树中添加元素eleprivate Node<T> addDG(Node<T> root, T ele) {//递归终止条件if (root == null) {this.size++;return new Node<T>(ele);}//递归操作if (root.ele.compareTo(ele) > 0) {root.left = addDG(root.left, ele);} else if (root.ele.compareTo(ele) < 0) {root.right = addDG(root.right, ele);} else {//更新频率root.frequence++;}return root;}

4.查找元素

(1)查找元素是否存在

        查找元素是否在二叉树中,查找每一个结点,如果查找元素比当前节点小,就在左子树里重新查找,如果查找元素比当前节点大,就在右子树里重新查找

 //查询的方法public boolean search(T ele) {return searchDG(this.root, ele);}//语义:从以root为根的二分搜索树中查找元素eleprivate boolean searchDG(Node<T> root, T ele) {//递归终止的条件if (root == null) {return false;}//递归操作if (root.ele.compareTo(ele) == 0) {return true;} else if (root.ele.compareTo(ele) > 0) {return searchDG(root.left, ele);} else {return searchDG(root.right, ele);}}

(2)查找最小元素

        二分搜索树中最左边的元素

 //找树中的最小元素public T getMinValue() {if (this.isEmpty()) {return null;}Optional<Node<T>> optional = getMinNode();return optional.get().ele;}//直接查找
private Optional<Node<T>> getMinNode() {if (this.root == null) {return Optional.empty();}//一直向左查找Node<T> node = this.root;while (node.left != null) {node = node.left;}return Optional.of(node);}//利用递归方法查找//语义:在以Node为根结点的树中查找最小结点private Optional<Node<T>> getMinNode(Node<T> node) {if (node.left == null) {return Optional.of(node);}return getMinNode(node.left);}

(3)查找最大元素

        二分搜索树中最右边的元素

//找树中的最大元素public T getMaxValue() {if (this.isEmpty()) {return null;}Optional<Node<T>> optional = getMaxNode(this.root);return optional.get().ele;}//语义:在以Node为根结点的树中查找最大结点private Optional<Node<T>> getMaxNode(Node<T> node) {if (node.right == null) {return Optional.of(node);}return getMaxNode(node.right);}

5.二分搜索树的遍历

树的遍历有四种:前序遍历;中序遍历;后序遍历;层序遍历

(1)前序遍历:

首先打印根节点,然后遍历左子树,最后是右子树

【28,16,13,22,30,29,42】

//前序遍历public void preTravel() {List<AbstractMap.SimpleEntry<T, Integer>> list = new ArrayList<>();preTravelDG(this.root, list);String str = list.stream().map(item -> "[" + item.getKey() + ":" + item.getValue() + "]").collect(Collectors.joining("-"));System.out.println(str);}//前序遍历以root为根的树,讲解稿保存在list中private void preTravelDG(Node<T> root, List<AbstractMap.SimpleEntry<T, Integer>> list) {//递归终止条件if (root == null) {return;}//递归操作list.add(new AbstractMap.SimpleEntry<>(root.ele, root.frequence));//遍历左子树preTravelDG(root.left, list);//遍历右子树preTravelDG(root.right, list);}

(2)中序遍历:

先遍历左子树,在打印中间结点,最后遍历右子树

【13,16,22,28,29,30,42】

//中序遍历public void midTravel() {List<AbstractMap.SimpleEntry<T, Integer>> list = new ArrayList<>();midTravelDG(this.root, list);String str = list.stream().map(item -> item.toString()).collect(Collectors.joining("-"));System.out.println(str);}//中序遍历以root为根的树,讲解稿保存在list中private void midTravelDG(Node<T> root, List<AbstractMap.SimpleEntry<T, Integer>> list) {//递归终止条件if (root == null) {return;}//递归操作//遍历左子树preTravelDG(root.left, list);list.add(new AbstractMap.SimpleEntry<>(root.ele, root.frequence));//遍历右子树preTravelDG(root.right, list);}

(3)后序遍历:

先遍历左子树,在遍历右子树,最后在打印中间结点

【13,22,16,29,42,30,28】

 //后序遍历public void sufTravel() {List<AbstractMap.SimpleEntry<T, Integer>> list = new ArrayList<>();sufTravelDG(this.root, list);String str = list.stream().map(item -> item.toString()).collect(Collectors.joining("-"));System.out.println(str);}//后序遍历以root为根的树,讲解稿保存在list中private void sufTravelDG(Node<T> root, List<AbstractMap.SimpleEntry<T, Integer>> list) {//递归终止条件if (root == null) {return;}//递归操作//遍历左子树preTravelDG(root.left, list);//遍历右子树preTravelDG(root.right, list);list.add(new AbstractMap.SimpleEntry<>(root.ele, root.frequence));}

可以看到,先中后序遍历的代码区别只是在递归最后将元素添加到list的位置不同而已

(4)层序遍历:

一层一层的打印

【28,16,30,13,22,29,42】

//层序遍历public void levelTravel() {//判断树是否为空if (this.isEmpty()) {return;}Queue<AbstractMap.SimpleEntry<Node<T>, Integer>> queue = new LinkedList<>();//1.先将根结点入队queue.add(new AbstractMap.SimpleEntry<>(this.root, 1));//2.遍历队列while (!queue.isEmpty()) {//2-1.出队AbstractMap.SimpleEntry<Node<T>, Integer> pair = queue.poll();//结点Node<T> node = pair.getKey();//层int level = pair.getValue();;System.out.println("[val:" + node.ele + ",level:" + level + "]");//2-2.判断左右子树是否为空if (node.left != null) {queue.add(new AbstractMap.SimpleEntry<>(node.left, level + 1));}if (node.right != null) {queue.add(new AbstractMap.SimpleEntry<>(node.right, level + 1));}}}

6.删除操作

删除的操作中,需要注意删除后二分搜索树也会因此改变,所以要分情况讨论

(1)删除最小元素

删除最小元素并不需要改变树,只需要失去关联关系即可

 //从树中删除最小的结点public T removeMinNode() {T result = getMinValue();if (result == null) {return null;}//更新根结点this.root = removeMinNode(this.root);return result;}//语义:从以Node为根的二分搜索树中删除元素最小的结点private Node<T> removeMinNode(Node<T> node) {//递归终止条件if (node.left == null) {//删除操作//1.记录右子树Node<T> rightTree = node.right;//失去关联关系node.right = null;//3.跟新sizethis.size--;return rightTree;}//递归操作node.left = removeMinNode(node.left);return node;}

(2)删除最大元素

跟删除最小元素一样,只需要失去关联关系即可

//从树中删除最大的结点public T removeMaxNode() {T result = getMaxValue();if (result == null) {return null;}//更新根结点this.root = removeMaxNode(this.root);return result;}//语义:从以Node为根的二分搜索树中删除元素最大的结点private Node<T> removeMaxNode(Node<T> node) {//递归终止条件if (node.right == null) {//删除操作//1.记录左子树Node<T> leftTree = node.left;//失去关联关系node.left = null;//3.跟新sizethis.size--;return leftTree;}//递归操作node.right = removeMaxNode(node.right);return node;}

(3)删除任意元素

在删除任意元素中,需要考虑删除结点有没有左右子树

//语义:从以Node为根的二分搜索树中删除值为ele的结点private Node<T> remove(Node<T> node, T ele) {//递归终止的条件//没有找到if (node == null) {return null;}//找到了if (node.ele.compareTo(ele) == 0) {this.size--;//Node就是要删除的结点if (node.left == null) {Node<T>rightNode=node.right;node.right=null;return rightNode;} else if (node.right == null) {Node<T>leftNode=node.left;node.left=null;return leftNode;} else {Node<T> suffixNode = getMinNode(node.right).get();suffixNode.right=removeMinNode(node.right);suffixNode.left=node.left;this.size++;//失去关联关系node.left=node.right=null;return suffixNode;}}//递归操作if (node.ele.compareTo(ele) > 0) {node.left = remove(node.left, ele);} else {node.right = remove(node.right, ele);}return node;}

(4)删除根节点

直接删除关联关系即可

 //删除根节点public void removeRoot(){if(this.root==null){return;}remove(this.root.ele);}

四、完整代码

package com.algo.lesson.lesson04;import java.util.*;
import java.util.stream.Collectors;//二分搜索树
/*
保存到结点中的元素值必须具有可比性*/
public class BinearySeachTree<T extends Comparable<T>> {//树的结点private static class Node<T> {private final T ele;//结点的值private int frequence;//频率private Node<T> left, right;//分别指向左右孩子的索引public Node(T ele) {this.ele = ele;this.left = this.right = null;}}//树对应的属性private Node<T> root;//树的根节点private int size;//结点的个数//构建树public BinearySeachTree() {this.root = null;this.size = 0;}//获取树中结点的个数public int getSize() {return this.size;}//向树中添加结点public void add(T ele) {//更新根结点this.root = addDG(this.root, ele);}//语义:向以root为根的二分搜索树中添加元素eleprivate Node<T> addDG(Node<T> root, T ele) {//递归终止条件if (root == null) {this.size++;return new Node<T>(ele);}//递归操作if (root.ele.compareTo(ele) > 0) {root.left = addDG(root.left, ele);} else if (root.ele.compareTo(ele) < 0) {root.right = addDG(root.right, ele);} else {//更新频率root.frequence++;}return root;}//查询的方法public boolean search(T ele) {return searchDG(this.root, ele);}//语义:从以root为根的二分搜索树中查找元素eleprivate boolean searchDG(Node<T> root, T ele) {//递归终止的条件if (root == null) {return false;}//递归操作if (root.ele.compareTo(ele) == 0) {return true;} else if (root.ele.compareTo(ele) > 0) {return searchDG(root.left, ele);} else {return searchDG(root.right, ele);}}//二分搜索树的遍历//前序遍历public void preTravel() {List<AbstractMap.SimpleEntry<T, Integer>> list = new ArrayList<>();preTravelDG(this.root, list);String str = list.stream().map(item -> "[" + item.getKey() + ":" + item.getValue() + "]").collect(Collectors.joining("-"));System.out.println(str);}//中序遍历public void midTravel() {List<AbstractMap.SimpleEntry<T, Integer>> list = new ArrayList<>();midTravelDG(this.root, list);String str = list.stream().map(item -> item.toString()).collect(Collectors.joining("-"));System.out.println(str);}//后序遍历public void sufTravel() {List<AbstractMap.SimpleEntry<T, Integer>> list = new ArrayList<>();sufTravelDG(this.root, list);String str = list.stream().map(item -> item.toString()).collect(Collectors.joining("-"));System.out.println(str);}//前序遍历以root为根的树,讲解稿保存在list中private void preTravelDG(Node<T> root, List<AbstractMap.SimpleEntry<T, Integer>> list) {//递归终止条件if (root == null) {return;}//递归操作list.add(new AbstractMap.SimpleEntry<>(root.ele, root.frequence));//遍历左子树preTravelDG(root.left, list);//遍历右子树preTravelDG(root.right, list);}//中序遍历以root为根的树,讲解稿保存在list中private void midTravelDG(Node<T> root, List<AbstractMap.SimpleEntry<T, Integer>> list) {//递归终止条件if (root == null) {return;}//递归操作//遍历左子树preTravelDG(root.left, list);list.add(new AbstractMap.SimpleEntry<>(root.ele, root.frequence));//遍历右子树preTravelDG(root.right, list);}//后序遍历以root为根的树,讲解稿保存在list中private void sufTravelDG(Node<T> root, List<AbstractMap.SimpleEntry<T, Integer>> list) {//递归终止条件if (root == null) {return;}//递归操作//遍历左子树preTravelDG(root.left, list);//遍历右子树preTravelDG(root.right, list);list.add(new AbstractMap.SimpleEntry<>(root.ele, root.frequence));}//判断树是否为空public boolean isEmpty() {return this.size == 0;}//层序遍历public void levelTravel() {//判断树是否为空if (this.isEmpty()) {return;}Queue<AbstractMap.SimpleEntry<Node<T>, Integer>> queue = new LinkedList<>();//1.先将根结点入队queue.add(new AbstractMap.SimpleEntry<>(this.root, 1));//2.遍历队列while (!queue.isEmpty()) {//2-1.出队AbstractMap.SimpleEntry<Node<T>, Integer> pair = queue.poll();//结点Node<T> node = pair.getKey();//层int level = pair.getValue();;System.out.println("[val:" + node.ele + ",level:" + level + "]");//2-2.判断左右子树是否为空if (node.left != null) {queue.add(new AbstractMap.SimpleEntry<>(node.left, level + 1));}if (node.right != null) {queue.add(new AbstractMap.SimpleEntry<>(node.right, level + 1));}}}//找树中的最小元素public T getMinValue() {if (this.isEmpty()) {return null;}Optional<Node<T>> optional = getMinNode();return optional.get().ele;}//找树中的最大元素public T getMaxValue() {if (this.isEmpty()) {return null;}Optional<Node<T>> optional = getMaxNode(this.root);return optional.get().ele;}private Optional<Node<T>> getMinNode() {if (this.root == null) {return Optional.empty();}//一直向左查找Node<T> node = this.root;while (node.left != null) {node = node.left;}return Optional.of(node);}//递归//语义:在以Node为根结点的树中查找最小结点private Optional<Node<T>> getMinNode(Node<T> node) {if (node.left == null) {return Optional.of(node);}return getMinNode(node.left);}//语义:在以Node为根结点的树中查找最大结点private Optional<Node<T>> getMaxNode(Node<T> node) {if (node.right == null) {return Optional.of(node);}return getMaxNode(node.right);}//删除操作//从树中删除最小的结点public T removeMinNode() {T result = getMinValue();if (result == null) {return null;}//更新根结点this.root = removeMinNode(this.root);return result;}//语义:从以Node为根的二分搜索树中删除元素最小的结点private Node<T> removeMinNode(Node<T> node) {//递归终止条件if (node.left == null) {//删除操作//1.记录右子树Node<T> rightTree = node.right;//失去关联关系node.right = null;//3.跟新sizethis.size--;return rightTree;}//递归操作node.left = removeMinNode(node.left);return node;}//删除操作//从树中删除最大的结点public T removeMaxNode() {T result = getMaxValue();if (result == null) {return null;}//更新根结点this.root = removeMaxNode(this.root);return result;}//语义:从以Node为根的二分搜索树中删除元素最大的结点private Node<T> removeMaxNode(Node<T> node) {//递归终止条件if (node.right == null) {//删除操作//1.记录左子树Node<T> leftTree = node.left;//失去关联关系node.left = null;//3.跟新sizethis.size--;return leftTree;}//递归操作node.right = removeMaxNode(node.right);return node;}//删除任意结点public void remove(T ele) {//根据值查找结点this.root = remove(this.root, ele);}//语义:从以Node为根的二分搜索树中删除值为ele的结点private Node<T> remove(Node<T> node, T ele) {//递归终止的条件//没有找到if (node == null) {return null;}//找到了if (node.ele.compareTo(ele) == 0) {this.size--;//Node就是要删除的结点if (node.left == null) {Node<T>rightNode=node.right;node.right=null;return rightNode;} else if (node.right == null) {Node<T>leftNode=node.left;node.left=null;return leftNode;} else {Node<T> suffixNode = getMinNode(node.right).get();suffixNode.right=removeMinNode(node.right);suffixNode.left=node.left;this.size++;//失去关联关系node.left=node.right=null;return suffixNode;}}//递归操作if (node.ele.compareTo(ele) > 0) {node.left = remove(node.left, ele);} else {node.right = remove(node.right, ele);}return node;}//删除根节点public void removeRoot(){if(this.root==null){return;}remove(this.root.ele);}}

五、例题

1.700. 二叉搜索树中的搜索

​​​​

class Solution {public TreeNode searchBST(TreeNode root, int val) {if(root==null){return null;}if(val==root.val){return root;}return searchBST(val<root.val?root.left:root.right,val);}
}

2.力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

class Solution {public TreeNode insertIntoBST(TreeNode root, int val) {
//更新根结点return root = addDG(root, val);}//语义:向以root为根的二分搜索树中添加元素eleprivate TreeNode addDG(TreeNode root, int val) {//递归终止条件if (root == null) {return new TreeNode(val);}//递归操作if (root.val>val) {root.left = addDG(root.left, val);} else if (root.val<val) {root.right = addDG(root.right, val);}return root;}
}

3.力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

class Solution {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> list = new ArrayList<List<Integer>>();if (root == null) {return list;}Queue<TreeNode> queue = new LinkedList<TreeNode>();queue.offer(root);while (!queue.isEmpty()) {List<Integer> level = new ArrayList<Integer>();int temp = queue.size();for (int i = 1; i <= temp; i++) {TreeNode node = queue.poll();level.add(node.val);if (node.left != null) {queue.offer(node.left);}if (node.right != null) {queue.offer(node.right);}}list.add(level);}return list;}
}

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

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

相关文章

合并有序链表---链表OJ---归并思想

https://leetcode.cn/problems/merge-two-sorted-lists/?envTypestudy-plan-v2&envIdtop-100-liked 将两个有序的链表合并为一个新的有序链表&#xff0c;那不就是和归并排序中最后合并的思想一样吗&#xff1f;只不过那里合并的是数组&#xff0c;这里合并的是链表。 首先…

StartAI宝藏功能——关键词解析

AIGC的同学们都有一个“世纪难题”——生图咒语。 想要生成高质量的图&#xff0c;关键词是至关重要地。关键词往往能决定一张图的成败&#xff01;当你看见一张戳中你审美的图&#xff0c;想模仿却不知如何下手&#xff0c;只能全网搜索生图咒语。 费事又费力&#xff0c;甚…

leetcode刷题(剑指offer) 50.Pow(x, n)

50.Pow(x, n) 实现 pow(x, n) &#xff0c;即计算 x 的整数 n 次幂函数&#xff08;即&#xff0c;xn &#xff09;。 示例 1&#xff1a; 输入&#xff1a;x 2.00000, n 10 输出&#xff1a;1024.00000示例 2&#xff1a; 输入&#xff1a;x 2.10000, n 3 输出&#x…

微信小程序|摇骰子

目录 简介设计与功能需求确定用户界面设计确定摇骰子动画效果确定随机数生成算法编码实现实现摇骰子动画测试与优化进行功能测试进行性能测试说明简介 制作一个摇骰子小程序是一个有趣且具有挑战性的项目。通过这个项目,你可以学习如何运用编程技术来模拟骰子的摇动和结果显示…

【LeetCode每日一题】56. 合并区间插入区间

一、判断区间是否重叠 力扣 252. 会议室 给定一个会议时间安排的数组 intervals &#xff0c;每个会议时间都会包括开始和结束的时间 intervals[i] [starti, endi] &#xff0c;请你判断一个人是否能够参加这里面的全部会议。 思路分析 因为一个人在同一时刻只能参加一个会…

Node.js-express

1.了解Ajax 1.1 什么是ajax Ajax的全称是Asynchronous Javascript And XML&#xff08;异步Js和XML&#xff09;. 通俗的理解&#xff1a;在网页中利用XMLHttpRequest对象和服务器进行数据交互的方式&#xff0c;就是Ajax 1.2 为什么要学习Ajax 之前所学的技术&#xff0c…

【git】git update-index --assume-unchanged(不改动.gitignore实现忽略文件)

文章目录 原因分析&#xff1a;添加忽略文件(取消跟踪)的命令&#xff1a;取消忽略文件(恢复跟踪)的命令&#xff1a;查看已经添加了忽略文件(取消跟踪)的命令&#xff1a; 原因分析&#xff1a; 已经维护的项目&#xff0c;文件已经被追踪&#xff0c;gitignore文件不方便修…

用可视化案例讲Rust编程3. 函数分解与参数传递

上一节我们在绘制面要素的时候&#xff0c;发现了函数功能体是三个不同步骤组成的&#xff1a; 读取文件获得geometry把geometry转变为绘图元素trace把绘图元素绘制到地图上 像我们上一节那样&#xff0c;把所有的功能都写在一个函数里面&#xff0c;这样的函数灵活性太差&am…

代理IP购买:选择按流量还是端口收费的代理?

​ 代理通常按以下两种标准之一收费&#xff1a;GB 或端口。但您应该选择哪一个&#xff1f;它们与其他产品有何不同&#xff1f;主要取决于您的需求&#xff0c;每种类型都有自己的优缺点&#xff0c;适合不同的情况。 在本文中&#xff0c;我们将详细分析每种类型&#xff0…

【VSCode】增加或减少一Tab的间隔

文章目录 示例 1&#xff1a;给 console 打印添加一 Tab 的间隔&#xff08;按下tab键即可&#xff09; // 原有的格式 if(a b){ console.log(true) }else{ console.log(false) }// 改变后的格式 if(a b){console.log(true) }else{console.log(false) }示例 2&#xff1a;给…

专有钉钉开发记录,及问题总结

先放几个专有钉钉开发文档 专有钉钉官网的开发指南 服务端(后端)api文档 前端api文档 前端开发工具下载地址 小程序配置文件下载地址 后端SDK包下载地址 专有钉钉域名是openplatform.dg-work.cn 开发记录 开发专有钉钉时有时会遇到要使用钉钉的api&#xff1b;通过 my 的方…

JavaWeb学习|Cookie

学习材料声明 所有知识点都来自互联网&#xff0c;进行总结和梳理&#xff0c;侵权必删。 引用来源&#xff1a;尚硅谷最新版JavaWeb全套教程,java web零基础入门完整版 在此之前&#xff0c;复习一下如何创建项目 首先创建正常的Java项目&#xff0c;之后选择add framework…

C#学习笔记-反射

前言 反射是.NET中的重要机制&#xff0c;通过反射可以得到*.exe或*.dll等程序集内部的接口、类、方法、字段、属性、特性等信息&#xff0c;还可以动态创建出类型实例并执行其中的方法。 反射的功能很强大&#xff0c;任何复杂抽象的分层架构或者复杂的设计模式均是建立在这些…

任务修复实例(1)

实例1 任务名&#xff1a;增强防御&#xff08;quest_template.id 8490&#xff09; 涉及的两个数据表分别为 smart_script 和 creature_summon_groups smart_script Reactstate 取值参考源码 UnitDefines.h 的 ReactStates 定义&#xff0c;其中&#xff1a;0为被动&#…

低导通电阻、汽车级STD20NF06LAG,STO47N60M6、STO33N60M6、STO36N60M6 600V MDmesh™ M6 功率MOSFET

1、STD20NF06LAG 汽车级N沟道60V、32 mOhm典型值、24 A STripFET II功率MOSFET STripFET VI™功率MOSFET是采用ST专有STripFET™技术和新型栅极结构的增强模式MOSFET。该款受益于STripFET™技术的功率MOSFET采用沟槽技术&#xff0c;可实现高效率和低RDS(on) &#xff0c;满足…

SparkSql---用户自定义函数UDFUDAF

文章目录 1.UDF2.UDAF2.1 UDF函数实现原理2.2需求:计算用户平均年龄2.2.1 使用RDD实现2.2.2 使用UDAF弱类型实现2.2.3 使用UDAF强类型实现 1.UDF 用户可以通过 spark.udf 功能添加自定义函数&#xff0c;实现自定义功能。 如&#xff1a;实现需求在用户name前加上"Name:…

83、评估权值预加载带来的性能提升

上两节介绍的权值预加载技术&#xff0c;在很多业务中是真实存在的。 只不过限于本小册内容以及大部分同学硬件设备的局限&#xff0c;这里无法通过真正的推理框架(比如 tvm, pytorch) GPU 来实现底层细节&#xff0c;这些推理框架中一般会将类似的优化技术封装起来。 作为 …

APPium简介及安装

1 APPium简介 1. 什么是APPium&#xff1f; APPium是一个开源测试自动化框架&#xff0c;适用于原生、混合或移动Web应用程序的自动化测试工具。 APPium使用WebDriver协议驱动iOS、Android等应用程序。 2. APPium的特点 支持多平台&#xff08;Android、iOS等&#xff09; …

uniapp组件库Card 卡片 的使用方法

目录 #平台差异说明 #基本使用 #配置卡片间距 #配置卡片左上角的缩略图 #配置卡片边框 #设置内边距 #API #Props #Slot #Event 卡片组件一般用于多个列表条目&#xff0c;且风格统一的场景。 #平台差异说明 AppH5微信小程序支付宝小程序百度小程序头条小程序QQ小程…

基于STM32的以太网通信协议选择与实现

在基于STM32的以太网通信中&#xff0c;主要涉及到选择合适的通信协议和实现对应的功能代码。常见的通信协议包括TCP/IP、UDP、HTTP等&#xff0c;选择合适的协议取决于具体应用需求。以下将介绍在STM32上进行以太网通信时&#xff0c;常用的通信协议选择以及对应功能代码的实现…