当前位置: 首页 > news >正文

数据结构《MapSet哈希表》

文章目录

  • 一、搜索树
    • 1.1 定义
    • 1.2 模拟实现搜索
  • 二、Map
    • 2.1 定义
    • 2.2 Map.Entry
    • 2.3 TreeMap的使用
    • 2.4 Map的常用方法
  • 三、Set
    • 3.1 定义
    • 3.2 TreeSet的使用
    • 3.3 Set的常用方法
  • 四、哈希表
    • 4.1 哈希表的概念
    • 4.2 冲突
      • 4.2.1 冲突的概念
      • 4.2.2 冲突的避免
        • 1. 选择合适的哈希函数
        • 2. 负载因子调节
      • 4.2.3冲突的解决
        • 1. 闭散列
        • 2. 开散列
    • 4.3 模拟实现
  • 五、例题练习
  • 总结


一、搜索树

1.1 定义

它或者是一棵空树,或者是具有以下性质的二叉树:
若它的左子树不为空,则左子树上所有节点的值都小于根节点的值。
若它的右子树不为空,则右子树上所有节点的值都大于根节点的值。
它的左右子树也分别为二叉搜索树。

1.2 模拟实现搜索

public class MyBinarySearchTree {static class TreeNode{int key;TreeNode left;TreeNode right;public TreeNode(int key){this.key = key;}}private TreeNode root = null;/*** 查询节点* 查询是否有节点的key值为所需要找的,如果有返回这个节点,没有则返回null* @param key* @return TreeNode*/public TreeNode search(int key){if(root == null){return null;//如果树为空,不用查询直接返回null}TreeNode cur = root;while (cur != null){if(key == cur.key){return cur;}else if(key < cur.key){//如果查询的值比节点的值小,说明只能在左子树上找cur = cur.left;}else {cur = cur.right;}}return null;}/*** 插入数据* 如果树为空直接插入,如果比节点的值大,往右边走,小,往左走,相等则不插入* @param key* @return*/public boolean insert(int key){if(root == null){root = new TreeNode(key);return true;//树为空,直接插入并返回正确}TreeNode cur = root;TreeNode parent = null;//parent的存在,是为了让我们可以返回到上一个节点while (cur != null){if(key == cur.key){//如果要插入的数据已经存在,说明不需要插入return false;}else if(key < cur.key){//如果要插入的数据比节点值小,说明要往节点的左子树中插入parent = cur;cur = cur.left;}else {//如果要插入的数据比节点值大,说明要往节点的右子树中插入parent = cur;cur = cur.right;}}//到这里,说明我们cur已经为空,此时要插入的数据在parent的左子树或者右子树TreeNode treeNode = new TreeNode(key);if(key < parent.key){parent.left = treeNode;}else {parent.right = treeNode;}return true;}/*** 删除节点* 首先我们要找到这个删除的节点* @param key* @return*/public boolean remove(int key){//首先要先找到这个点if(root == null){return false;//树为空无法删除}TreeNode parent = null;TreeNode cur = root;while (cur != null){if(key < cur.key){parent = cur;cur = cur.left;}else if(key > cur.key){parent = cur;cur = cur.right;}else {//说明找到这个点了return removeNode(parent,cur);}}return false;}/*** 删除节点的真正方法* @param parent* @param cur* @return*/private boolean removeNode(TreeNode parent, TreeNode cur) {if(cur.left == null){//当要删除的节点左节点为空if(cur == root){//当节点为root时,那直接让root往右子树走即可root = cur.right;}else if(cur == parent.left){//节点不为root,说明cur为parent的左或者右孩子parent.left = cur.right;//因为cur左为空,所以父亲节点的左节点直接接上cur的右子树即可}else {parent.right = cur.right;}}else if(cur.right == null){//当要删除的节点右节点为空if(cur == root){//当节点为root时,那直接让root往左子树走即可root = cur.left;}else if(cur == parent.left){parent.left = cur.left;}else {parent.right = cur.left;}}else {//当要删除的节点左右均不为空//找这个节点的左子树的最右边的节点或者右子树最左边的节点来替换数值TreeNode targetParent = cur;TreeNode target = cur.left;while (target.right != null){targetParent = target;target = target.right;}cur.key = target.key;targetParent.right = target.left;}return true;}}

关于上述搜索树中其他的方法,比较简单,看代码大概可以了解如何实现,这里我们主要解释一下删除中的左右孩子节点都存在的情况下删除的原理
在这里插入图片描述
在这里插入图片描述
最后删除完的结果
在这里插入图片描述


测试用例

public class Test {public static void main(String[] args) {MyBinarySearchTree myBinarySearchTree = new MyBinarySearchTree();myBinarySearchTree.insert(5);myBinarySearchTree.insert(4);myBinarySearchTree.insert(6);myBinarySearchTree.insert(9);myBinarySearchTree.insert(3);myBinarySearchTree.insert(2);myBinarySearchTree.insert(7);myBinarySearchTree.insert(8);myBinarySearchTree.insert(10);MyBinarySearchTree.TreeNode treeNode = myBinarySearchTree.search(9);System.out.println(treeNode.key);System.out.println(myBinarySearchTree.remove(9));}
}

在这里插入图片描述
在这里插入图片描述


什么是键值对?
键(key):它是独一无二的标识符,用于快速定位和检索对应的值。在一个Map集合里,不允许有两个相同的键,就像现实生活中每个人都有唯一的身份证号。常见的数据类型都能充当键,比如String、Integer,不过要求键对象必须正确重写hashCode()和equals()方法,以此保证唯一性和一致性。
值(value):与键关联的数据,可以是任意类型,例如在统计单词出现次数的场景中,单词是键,出现的次数作为值,这个次数值就是Integer类型。一个键对应一个值,但不同键可以对应相同的值 。

二、Map

2.1 定义

Map是一个接口类,没有继承自Collection,该类中存储的是<K,V>结构的键值对,并且K一定是唯一的,不能重复。

注意:

  1. Map是一个接口,不能直接实例化对象,如果要实例化对象只能实例化其实现类TreeMap或者HashMap
  2. Map中存放键值对的key是唯一的,value是可以重复的
  3. 在TreeMap中插入键值对时,key不能为空,否则会抛出NullPointerException异常,value可以为空。但是HashMap的key和value都可以为空。
  4. Map中的key可以全部分离出来,存储到Set中来进行访问(因为key不能重复)。
  5. Map中的value可以全部分离出来,存储在Collection的任何一个子集合中(value可能有重复)。
  6. Map中键值对的key不能直接修改,value可以修改,如果要修改key,只能先将该key删除掉,然后再来进行重新插入。

2.2 Map.Entry

Map.Entry是一个接口,它表示Map接口中的一个键值对。每个实现了Map接口的类,例如HashMap、TreeMap等,内部都有对应的内部类实现了Map.Entry接口,用于封装单个的键值对元素,方便对Map进行遍历等操作。

方法解释
K getKey( )返回entry中的key
V getValue( )返回entry中的value
V setValue(V value)将键值对中的value替换掉

如在HashMap中
在这里插入图片描述
在TreeMap中
在这里插入图片描述
在这里插入图片描述


2.3 TreeMap的使用

put(key, value):插入key-value的键值对
如果key不存在,会将key-value的键值对插入到map中,返回null
如果key之前是存过的,会将新的value值作为返回值返回,同时会将新的value值与之前的进行替换

Map<String,Integer> map = new TreeMap<>();//放入不同的人以及他的分数map.put("zhangsan",90);map.put("lisi",80);map.put("wangwu",88);Integer m = map.put("zhaoliu",92);Integer n = map.put("zhaoliu",99);System.out.println("m "+m);System.out.println("n "+n);

在这里插入图片描述


map.size()//返回map中已经存的键值对的个数

在这里插入图片描述


get()
Map<String,Integer> map = new TreeMap<>();//放入不同的人以及他的分数map.put("zhangsan",90);map.put("lisi",80);map.put("wangwu",88);Integer m = map.put("zhaoliu",92);Integer n = map.put("zhaoliu",99);// get(key): 返回key所对应的value// 如果key存在,返回key所对应的value// 如果key不存在,返回nullSystem.out.println(map.get("zhangsan"));System.out.println(map.get("wangmm"));

在这里插入图片描述


getOrDefault()
		//getOrDefault(): 如果key存在,返回与key所对应的value,如果key不存在,返回一个默认值System.out.println(map.getOrDefault("zhangsan", -100));System.out.println(map.getOrDefault("wangmm", -100));

在这里插入图片描述


containKey()
		//containKey(key):检测key是否包含在Map中,时间复杂度:O(logN)// 按照红黑树的性质来进行查找// 找到返回true,否则返回falseSystem.out.println(map.containsKey("zhangsan"));System.out.println(map.containsKey("wangmm"));

在这里插入图片描述


containValue()
		// containValue(value): 检测value是否包含在Map中,时间复杂度: O(N)// 找到返回true,否则返回falseSystem.out.println(map.containsValue(90));System.out.println(map.containsValue(100));

在这里插入图片描述


keySet()

返回类型: keySet()方法返回一个Set集合,因为Map中的键具有唯一性,所以用Set来存储很合适,Set集合会自动去除重复元素,保证每个键在集合里只出现一次。

遍历Map:获取到键的集合后,可以通过遍历这个Set,再配合Map的get方法,来遍历整个Map的键值对,这是一种常见的Map遍历方式。

		// 打印所有的key// keySet是将map中的key放入在Set中返回的for (String key : map.keySet()) {System.out.println(key + " : " + map.get(key));}

在这里插入图片描述


values()
		// 打印所有的value// values()是将map中的value放在collect的一个集合中返回的for(Integer integer : map.values()){System.out.print(integer + " ");}System.out.println();

在这里插入图片描述


entrySet()
		// 打印所有的键值对// entrySet(): 将Map中的键值对放在Set中返回了for(Map.Entry<String, Integer> entry : map.entrySet()){System.out.println(entry.getKey() + ":" + entry.getValue());}System.out.println();

在这里插入图片描述

2.4 Map的常用方法

方法解释
V get(Object key)返回 key 对应的 value
V getOrDefault(Object key, V defaultValue)返回key对应的value,key不存在,返回默认值
V put(K key, V value)设置 key 对应的 value
V remove(Object key)删除key对应的映射关系
Set keySet()返回所有key的不重复集合
Collection values()返回所有value的可重复集合
Set<Map.Entry<K, V>> entrySet()返回所有的key-value映射关系
boolean containsKey(Object key)判断是否包含key
boolean containsValue(Object value)判断是否包含valuel

三、Set

3.1 定义

Set与Map主要的不同有两点:Set是继承自Collection的接口类,Set中只存储了Key。

注意:

  1. Set是继承自Collection的一个接口类

  2. Set中只存储了key,并且要求key一定要唯一

  3. TreeSet的底层是使用Map来实现的,其使用key与Object的一个默认对象作为键值对插入到Map中的
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  4. Set最大的功能就是对集合中的元素进行去重

  5. 实现Set接口的常用类有TreeSet和HashSet,还有一个LinkedHashSet,LinkedHashSet是在HashSet的基础上维护了一个双向链表来记录元素的插入次序。

  6. Set中的Key不能修改,如果要修改,先将原来的删除掉,然后再重新插入

  7. TreeSet中不能插入null的key,HashSet可以。

在这里插入图片描述


3.2 TreeSet的使用

add()
TreeSet<String> treeSet = new TreeSet<>();// add(key): 如果key不存在,则插入,返回ture// 如果key存在,返回falsetreeSet.add("zhangsan");treeSet.add("lisi");treeSet.add("wangwu");boolean m = treeSet.add("zhaoliu");boolean n = treeSet.add("zhangsan");System.out.println(m);System.out.println(n);

在这里插入图片描述


size()

在这里插入图片描述


contains()
		// contains(key): 如果key存在,返回true,否则返回falseSystem.out.println(treeSet.contains("zhangsan"));System.out.println(treeSet.contains("wangmm"));

在这里插入图片描述

3.3 Set的常用方法

方法解释
boolean add(E e)添加元素,但重复元素不会被添加成功
void clear()清空集合
boolean contains(Object o)判断·是否在集合中
Iteratoriterator0返回迭代器
boolean remove(Object o)删除集合中的o
int size()返回set中元素的个数
boolean isEmpty()检测set是否为空,空返回true,否则返回false
Object[ toArray0将set中的元素转换为数组返回
boolean containsAll(Collection<?> c)集合c中的元素是否在set中全部存在,是返回true,否则返回false
boolean addAll(Collection<?extendsE>c)将集合c中的元素添加到set中,可以达到去重的效果

四、哈希表

4.1 哈希表的概念

哈希表是一种数据结构,它使用哈希函数将键(Key)映射到存储桶(Bucket)或槽(Slot),以便可以在平均情况下以O(1)的时间复杂度进行快速的插入、删除和查找操作。

基本原理:

  1. 哈希表由一个数组(也称为哈希表本身)和一个哈希函数组成。
  2. 哈希函数:将键作为输入,通过某种计算得到一个整数索引,这个索引就是存储键值对的存储桶的位置。例如,对于键 k,哈希函数 h(k) 会计算出一个整数 i,表示键值对 (k, v) 应该存储在数组的第 i 个位置。
    在这里插入图片描述

4.2 冲突

4.2.1 冲突的概念

当两个不同的键通过哈希函数计算得到相同的哈希值时,会发生哈希冲突。

在上面我们给出的例子中,没有出现冲突,如果通过例子中的hash函数,我们再放入一个数为44,那么我们就会和4冲突

4.2.2 冲突的避免

1. 选择合适的哈希函数

选择哈希函数的考虑因素:

  1. 分布均匀性:
    理想的哈希函数应该将键均匀地分布在哈希表的存储桶中,避免大量冲突。
  2. 计算速度:
    哈希函数的计算应该快速,避免复杂的计算,尤其是对于大量的插入、查找操作。
  3. 抗碰撞性:
    对于安全相关的应用,需要更高的抗碰撞性,使用加密哈希函数;对于普通的哈希表,可能更注重速度和分布均匀性。

常用的函数:

  1. 取模法: 对于一个整数键 k 和哈希表大小 m,哈希函数 h(k) = k % m
  2. 直接定制法:取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B
2. 负载因子调节

负载因子是哈希表中存储元素的数量与哈希表的容量(即存储桶的数量)的比值。
计算公式为:负载因子 = 元素数量 / 哈希表容量。
在这里插入图片描述

作用和意义:

  1. 它是一个重要的性能指标,用于衡量哈希表的填充程度。
  2. 在 Java 的 HashMap 中,负载因子决定了何时对哈希表进行扩容操作。
  3. 合理的负载因子可以平衡空间使用和性能,避免过多的哈希冲突。

在这里插入图片描述

常见的负载因子取值:

  1. 在 Java 的 HashMap 中,默认的负载因子是 0.75。
  2. 当元素数量达到 哈希表容量 * 负载因子 时,HashMap 会自动扩容,通常扩容为原来的两倍,并重新哈希元素。

4.2.3冲突的解决

1. 闭散列

闭散列:也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,可以把key存放到冲突位置中的下一个空位置中去。

  1. 线性探测:如果发生冲突,顺序地检查下一个槽,直到找到一个空槽。
    采用闭散列处理哈希冲突时,不能随便物理删除哈希表中已有的元素,若直接删除元素会影响其他元素的搜索。比如删除元素4,如果直接删除掉,44查找起来可能会受影响。因此线性探测采用标记的伪删除法来删除一个元素
    在这里插入图片描述

  2. 二次探测(Quadratic Probing):使用二次函数来确定下一个检查的槽,比如检查h(k) + 1^2 ,h(k) + 2^2,h(k) + 3^2,等等。

闭散列性能受探测序列和负载因子影响,当负载因子较高时,性能下降明显,空间利用率低。


2. 开散列

开散列法又叫链地址法,首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中。
在这里插入图片描述
哈希桶其实可以看作将大集合的搜索问题转化为小集合的搜索问题,那如果冲突严重,就意味着小集合的搜索性能其实也时不佳的,这个时候我们就可以将这个所谓的小集合搜索问题继续进行转化:

  1. 每个桶的背后是另一个哈希表
  2. 每个桶的背后是一棵搜索树

4.3 模拟实现

在这里插入图片描述
这里是我自己的一些理解,可能不是那么全面,如果有不对的地方,还望指正
在这里插入图片描述
节点的插入
在这里插入图片描述
数组的扩展
在这里插入图片描述
代码实现


public class HashTable<K,V> {private static final double DEFAULT_LOAD_FACTOR = 0.75f;static class Node<K,V>{public K key;public V value;public Node<K,V> next;public Node(K key,V value){this.key = key;this.value = value;}}//先定义一个数组来作为哈希表存放private Node<K,V>[] array = (Node<K,V>[])new Node[10];private int useSize = 0;public void push(K key,V value){int hashcode = key.hashCode();//获得哈希值int index = hashcode % array.length;Node<K,V> cur = array[index];while (cur != null){if(key.equals(cur.key)){//如果key在链表中存在,我们就更新它的value值,不新添节点,key唯一性cur.value = value;return;}cur = cur.next;}Node<K,V> node = new Node<>(key,value);node.next = array[index];array[index] = node;useSize++;if(doLoadFactor() > DEFAULT_LOAD_FACTOR){resize();}}private void resize() {Node<K,V>[] newarray = (Node<K,V>[])new Node[array.length*2];for (int i = 0; i < array.length; i++) {Node<K,V> cur = array[i];while (cur != null){int newHashcode = cur.key.hashCode();int newIndex = newHashcode % newarray.length;//重新计算位置Node<K,V> curN = cur.next;//记录节点的下一个节点cur.next = newarray[newIndex];newarray[newIndex] = cur;cur = curN;}}array = newarray;}private double doLoadFactor() {return useSize * 1.0 / array.length;}public V getVal(K key){int hashcode = key.hashCode();int index = hashcode % array.length;Node<K,V> cur = array[index];while (cur != null){if(cur.key.equals(key)){return cur.value;}cur = cur.next;}return null;}
}

在这里插入图片描述
当负载因子过大时,进行扩容
在这里插入图片描述
在这里插入图片描述


五、例题练习

例题1 字符串中的第一个唯一字符
通过HashMap来实现

class Solution {public int firstUniqChar(String s) {Map<Character,Integer> map = new HashMap<Character,Integer>();for(int i = 0; i < s.length(); i++){char ch = s.charAt(i);map.put(ch,map.getOrDefault(ch,0)+1);}for(int i = 0; i < s.length(); i++){if(map.get(s.charAt(i)) == 1){return i;}}return -1;}
}

例题2 只出现一次的数字

使用set

遍历数组,将数组中的数字放入set中,在放入之前判断set中是否存在这个数,如果存在,将set中的这个数出出去,最后遍历set中剩下的数便是出现一次的数

class Solution {public int singleNumber(int[] nums) {HashSet<Integer> set = new HashSet<>();for(int i = 0; i < nums.length; i++){if(set.contains(nums[i])){set.remove(nums[i]);}else{set.add(nums[i]);}}for(int i = 0; i < nums.length; i++){if(set.contains(nums[i])){return nums[i];}}return 0;}
}

例题3 随机链表的复制
在这里插入图片描述

class Solution {public Node copyRandomList(Node head) {HashMap<Node,Node> map = new HashMap<>();Node cur = head;while(cur != null){Node node = new Node(cur.val);map.put(cur,node);//key为老节点,value为新节点cur = cur.next;}cur = head;while(cur != null){map.get(cur).next = map.get(cur.next);map.get(cur).random = map.get(cur.random);cur = cur.next;}return map.get(head);}
}

例题4 宝石与石头
运用set存储宝石,然后看石头中在set中能不能找到

class Solution {public int numJewelsInStones(String jewels, String stones) {HashSet<Character> set = new HashSet<>();int count = 0;for(int i = 0; i < jewels.length(); i++){set.add(jewels.charAt(i));}for(int i = 0; i < stones.length(); i++){if(set.contains(stones.charAt(i))){count++;}}return count;}
}

例题5 旧键盘
将实际输入的字符串放入setReal中,然后从正确的字符串中一个一个取出字符看,实际输入的字符串中有没有,没有就打印并且将它放入已经判断后的set中,以防反复判断。

import java.util.Scanner;
import java.util.HashSet;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);String strAct = in.nextLine();//正确的字符串String strBroken = in.nextLine();//实际输入的字符串strAct = strAct.toUpperCase();strBroken = strBroken.toUpperCase();HashSet<Character> hashSetReal = new HashSet<>();//实际输入的HashSet<Character> hashSetAlready = new HashSet<>();//已经判断过的for(int i = 0; i < strBroken.length(); i++){hashSetReal.add(strBroken.charAt(i));}for(int i = 0; i < strAct.length(); i++){char ch = strAct.charAt(i);if(!hashSetReal.contains(ch) && !hashSetAlready.contains(ch)){hashSetAlready.add(ch);System.out.print(ch);}}}
}

总结

本篇文章,介绍了有关Map和Set,以及哈希表相关的数据结构内容,如果有什么不正确不严谨的地方,还望指正,我会尽快更改,谢谢大家!!

相关文章:

数据结构《MapSet哈希表》

文章目录 一、搜索树1.1 定义1.2 模拟实现搜索 二、Map2.1 定义2.2 Map.Entry2.3 TreeMap的使用2.4 Map的常用方法 三、Set3.1 定义3.2 TreeSet的使用3.3 Set的常用方法 四、哈希表4.1 哈希表的概念4.2 冲突4.2.1 冲突的概念4.2.2 冲突的避免1. 选择合适的哈希函数2. 负载因子调…...

【QT】QComboBox:activated信号和currentIndexChanged信号的区别

目录 1、activated1.1 原型1.2 触发机制1.3 使用场景1.4 连接信号和槽的方法1.4.1 方式一1.4.2 方式二 2、currentIndexChanged2.1 原型2.2 触发机制2.3 使用场景2.4 连接信号和槽的方法 1、activated 1.1 原型 [signal] void QComboBox::activated(int index) [signal] void…...

【Block总结】ELGCA模块,池化-转置(PT)注意力和深度卷积有效聚合局部和全局上下文信息

ELGCA结构 论文题目&#xff1a;ELGC-Net: Efficient Local-Global Context Aggregation for Remote Sensing Change Detection 论文链接&#xff1a;https://arxiv.org/pdf/2403.17909 官方github&#xff1a;https://github.com/techmn/elgcnet 高效局部-全局上下文聚合器&…...

MERN全栈脚手架(MongoDB、Express、React、Node)与Yeoman详解

MERN 全栈脚手架是一种用于快速构建基于 MongoDB、Express、React 和 Node.js 的全栈应用的框架或模板。它帮助开发者快速启动项目&#xff0c;减少了从零开始配置的时间。以下是关于 MERN 全栈脚手架的详细解析。 一、MERN 技术栈简介 MongoDB: 文档型数据库&#xff0c;用于…...

基于springboot+vue+微信小程序的宠物领养系统

基于springbootvue微信小程序的宠物领养系统 一、介绍 本项目利用SpringBoot、Vue和微信小程序技术&#xff0c;构建了一个宠物领养系统。 本系统的设计分为两个层面&#xff0c;分别为管理层面与用户层面&#xff0c;也就是管理者与用户&#xff0c;管理权限与用户权限是不…...

如何使用策略模式并让spring管理

1、策略模式公共接口类 BankFileStrategy public interface BankFileStrategy {String getBankFile(String bankType) throws Exception; } 2、策略模式业务实现类 Slf4j Component public class ConcreteStrategy implements BankFileStrategy {Overridepublic String ge…...

react中hooks之useRef 用法总结

1. 基本概念 useRef 是 React 的一个 Hook&#xff0c;返回一个可变的 ref 对象&#xff0c;其 .current 属性被初始化为传入的参数。这个对象在组件的整个生命周期内保持不变。 2. 主要用途和特性 2.1 获取 DOM 元素实例 function TextInputWithFocusButton() {const inpu…...

使用 Docker 部署 Java 项目(通俗易懂)

目录 1、下载与配置 Docker 1.1 docker下载&#xff08;这里使用的是Ubuntu&#xff0c;Centos命令可能有不同&#xff09; 1.2 配置 Docker 代理对象 2、打包当前 Java 项目 3、进行编写 DockerFile&#xff0c;并将对应文件传输到 Linux 中 3.1 编写 dockerfile 文件 …...

如何在Ubuntu上安装和配置Git

版本控制系统&#xff08;VCS&#xff09;是软件开发过程中不可或缺的工具之一&#xff0c;它帮助开发者跟踪代码变更、协作开发以及管理不同版本的项目。Git作为当前最流行的分布式版本控制系统&#xff0c;因其高效性和灵活性而广受青睐。本文将指导你如何在Ubuntu操作系统上…...

FPGA 21 ,深入理解 Verilog 中的基数,以及二进制数与十进制数之间的关系( Verilog中的基数 )

目录 前言 一. 基数基础 1.1 基数介绍 2.1 基数符号 3.1 二进制数 二. 二进制与十进制数 三. 二进制数 3.1 定义寄存器类型变量 3.2 定义线网类型变量 3.3 赋值操作 3.4 解析二进制数为十进制数 四. 代码示例 五. 注意事项 六. 更多操作 前言 在Verilog中&#…...

【redis】redis-cli命令行工具的使用

redis-cli命令行工具是一个功能强大的Redis客户端&#xff0c;它允许用户与Redis数据库进行交互和管理。 以下是一些常用参数的使用说明&#xff1a; 基本连接参数 -h, --host <hostname>&#xff1a;指定要连接的Redis服务器的主机名或IP地址。如果未指定&#xff0c;…...

使用Matplotlib显示中文的方法

1 问题提出 使用图1所示的代码进行matplotlib绘图时&#xff0c;因为其默认不支持中文&#xff0c;此时无法显示正确内容&#xff0c;如图2所示。 图1 matplotlib绘图绘图代码 图2 matplotlib无法显示中文 2 问题解决 2.1 设置全局字体 在图1所示的代码中&#xff0c;第13…...

SQL Server2022详细安装教程

1. 打开SQL Server官网&#xff1a;SQL Server 下载 | Microsoft 2. 选择Developer版 3. 下载好安装包&#xff0c;打开&#xff0c;选择自定义 4. 选择下载位置&#xff0c;最好不要在C盘即主磁盘即可。等待下载 5. 下载成功之后会弹出这个框 6. 点击“安装”&#…...

家里温度随心控,假期出行更舒适~

春节假期马上到来啦&#xff01;这是放松身心、陪伴家人的最佳时机~      但旅途结束的温差变化、空气质量问题是否让你有些担忧呢&#xff1f;      别担心&#xff01;有了约克VRF中央空调&#xff0c;让你的假期更加舒心无忧~      清新空气&#xff0c;自在出游…...

压力测试详解

压力测试 压力测试是一种软件测试&#xff0c;用于验证软件应用程序的稳定性和可靠性。压力测试的目标是在极其沉重的负载条件下测量软件的健壮性和错误处理能力&#xff0c;并确保软件在危急情况下不会崩溃。它甚至可以测试超出正常工作点的测试&#xff0c;并评估软件在极端…...

从epoll事件的视角探讨TCP:三次握手、四次挥手、应用层与传输层之间的联系

目录 一、应用层与TCP之间的联系 二、 当通信双方中的一方如客户端主动断开连接时&#xff0c;仅是在客户端的视角下连接已经断开&#xff0c;在服务端的眼中&#xff0c;连接依然存在&#xff0c;为什么&#xff1f;——触发EPOLLRDHUP事件&#xff1a;对端关闭连接或停止写…...

Redis复制(replica)

Redis主从复制 [Redis主从复制]&#xff08;replica&#xff09;是一个多Redis实例进行数据同步的过程&#xff0c;其中一个实例是主实例&#xff08;Master&#xff09;&#xff0c;其他实例是从实例&#xff08;Slave&#xff09;。主实例负责处理命令请求&#xff0c;而从实…...

[云讷科技] 用于软件验证的仿真环境

我们使用Pursuit自动驾驶仪为各种场景设计仿真环境&#xff0c;以便用户可以在模拟环境中直接验证他们的软件&#xff0c;无需现场测试。该环境基于Gazebo引擎。 1. 工作区目录 模拟环境的工作区位于提供的U盘中的~/pursuit_space/sitl_space_pursuit中。用户可以按照用户手册…...

使用 Vite 和 Vue 框架创建组件库

在前端开发中&#xff0c;组件化开发已成为一种高效、可维护的方式。通过创建组件库&#xff0c;不仅可以提高代码复用率&#xff0c;还能方便地在不同项目之间共享组件。本文将详细介绍如何使用 Vite 和 Vue 框架创建一个组件库&#xff0c;并将其导出供其他项目使用。为保持一…...

【数据结构学习笔记】19:跳表(Skip List)

介绍 跳表是一个能在 O ( n l o g n ) O(nlogn) O(nlogn)时间完成查找、插入、删除的数据结构&#xff0c;相比于树形结构优点就是很好写&#xff08;所以也用于实现Redis ZSet&#xff09;。其核心思想就是维护一个元素有序的&#xff0c;能随机提升索引层数的链表。最下面一…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学&#xff1f;传统医学奠基期&#xff08;远古 - 17 世纪&#xff09;近代医学转型期&#xff08;17 世纪 - 19 世纪末&#xff09;​现代医学成熟期&#xff08;20世纪至今&#xff09; 中医的源远流长和一脉相承远古至…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

Web后端基础(基础知识)

BS架构&#xff1a;Browser/Server&#xff0c;浏览器/服务器架构模式。客户端只需要浏览器&#xff0c;应用程序的逻辑和数据都存储在服务端。 优点&#xff1a;维护方便缺点&#xff1a;体验一般 CS架构&#xff1a;Client/Server&#xff0c;客户端/服务器架构模式。需要单独…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

嵌入式常见 CPU 架构

架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集&#xff0c;单周期执行&#xff1b;低功耗、CIP 独立外设&#xff1b;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel&#xff08;原始…...