Map和Set—数据结构

文章目录

  • 1.搜索
    • 1.1常见搜索方式
    • 1.2模型
  • 2.map
    • 2.1介绍
    • 2.2 Map.Entry<K, V>
    • 2.3map的使用
    • 2.4遍历map
    • 2.5TreeMap和HashMap的区别
  • 3.set
    • 3.1介绍
    • 3.2set的使用
    • 3.3遍历set
    • 3.4 TreeSet和HashSet的不同
  • 4.搜索树
    • 4.1概念
    • 4.2实现
    • 4.3性能分析
  • 5.哈希表
    • 5.1查找数据
    • 5.2冲突的概念
    • 5.3冲突的避免方法
    • 5.4冲突的解决方法
    • 5.5实现(简单类型)
    • 5.6实现(泛型)

1.搜索

1.1常见搜索方式

(1)直接遍历:时间复杂度会达到O(N)
(2)二分查找:时间复杂度O(logN)
(3)Map和set:一种专门用来进行搜索的容器或者数据结构,其搜索的效率与其具体的实例化子类有关

1.2模型

(1)k-v模型:map(key-value)
(2)k模型:set(key)

2.map

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

2.1介绍

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

2.2 Map.Entry<K, V>

Map.Entry<K, V> 是Map内部实现的用来存放<key, value>键值对映射关系的内部类

public static void main(String[] args) {
        Map<String,Integer> map = new HashMap<>();
        map.put("hello",2);
        map.put("world",4);
        map.put("school",6);
        System.out.println(map);//{world=4, school=6, hello=2}
        //通过map.entrySet遍历key和value
        Set<Map.Entry<String,Integer>> entrySet = map.entrySet();
        for (Map.Entry<String,Integer> entry:entrySet){
            //key:world  val:4 key:school  val:6 key:hello  val:2
            System.out.print("key:"+entry.getKey()+"  val:"+entry.getValue()+" ");
        }
        System.out.println();
        //将键值对中的value替换为指定value
        for (Map.Entry<String,Integer> entry:entrySet){
            //4 6 2
            System.out.print(entry.setValue(entry.getValue())+" ");
        }
    }

2.3map的使用

public static void main(String[] args) {
        Map<String,Integer> map = new HashMap<>();
        map.put("hello",2);
        map.put("world",4);
        map.put("school",6);//设置 key 对应的 value
        System.out.println(map);//{world=4, school=6, hello=2}
        //存储顺序和打印的顺序不同是由于他的底层是通过哈希函数计算的
        System.out.println(map.get("hello"));//2 返回 key 对应的 value
        System.out.println(map.getOrDefault("hello", 4));//2 返回 key 对应的 value,key 不存在,返回默认值
        System.out.println(map.remove("world"));//4 删除 key 对应的映射关系
        System.out.println(map.keySet());//[school, hello] 返回所有 key 的不重复集合
        System.out.println(map.values());//[6, 2] 返回所有 value 的可重复集合
        System.out.println(map.entrySet());//[school=6, hello=2] 返回所有的 key-value 映射关系
        System.out.println(map.containsKey("world"));//false 判断是否包含 key
        System.out.println(map.containsValue(2));//true 判断是否包含 value
    }

2.4遍历map

public static void main(String[] args){
        Map<String,Integer> map = new HashMap<>();
        map.put("hello",2);
        map.put("world",4);
        map.put("school",6);
        System.out.println(map);//{world=4, school=6, hello=2}
        //通过map.keySet遍历key和value
        for (String key:map.keySet()){
            //key:world value:4 key:school value:6 key:hello value:2
            System.out.print("key:"+key+" value:"+map.get(key)+" ");
        }
        System.out.println();
        //通过map.values遍历value
        for (Integer value:map.values()){
            //4 6 2
            System.out.print(value+" ");
        }
        System.out.println();
        //集合方式遍历key
        Set<String> set = map.keySet();
        System.out.println(set);//[world, school, hello]
        //集合方式遍历value
        Collection<Integer> collection = map.values();
        System.out.println(collection);//[4, 6, 2]
        //通过map.entrySet遍历key和value
        Set<Map.Entry<String,Integer>> entrySet = map.entrySet();
        for (Map.Entry<String,Integer> entry:entrySet){
            //key:world  val:4 key:school  val:6 key:hello  val:2
            System.out.print("key:"+entry.getKey()+"  val:"+entry.getValue()+" ");
        }
        System.out.println();
        //Map.Entry<>迭代器
        Set<Map.Entry<String,Integer>> entrySet1 = map.entrySet();
        Iterator<Map.Entry<String,Integer>> iterator = entrySet1.iterator();
        while (iterator.hasNext()){
            Map.Entry<String,Integer> entry = iterator.next();
            //key:world  val:4 key:school  val:6 key:hello  val:2
            System.out.print("key:"+entry.getKey()+"  val:"+entry.getValue()+" ");
        }
        System.out.println();
        //java8特有的遍历方法
        map.forEach((key,value)->{
            //key:world value:4 key:school value:6 key:hello value:2
            System.out.print("key:"+key+" value:"+value+" ");
        });
    }

2.5TreeMap和HashMap的区别

在这里插入图片描述

3.set

3.1介绍

  1. Set是继承自Collection的接口类,Set中只存储了Key,并且要求key唯一
  2. Set的底层是使用Map来实现的,其使用key与Object的一个默认对象作为键值对插入到Map中的
  3. Set最大的功能就是对集合中的元素进行去重
  4. 实现Set接口的常用类有TreeSet和HashSet
  5. Set中的Key不能修改,如果要修改,先将原来的删除掉,然后再重新插入
  6. Set中不能插入null的key

3.2set的使用

public static void main(String[] args) {
        //set不能添加重复元素
        Set<String> set = new HashSet<>();
        set.add("hello");
        set.add("world");
        set.add("world");
        set.add("school");//添加元素
        System.out.println(set);//[world, school, hello]
        System.out.println(set.contains("hello"));//true
        System.out.println(set.contains("d"));//false 是否包含某个元素
        System.out.println(set.remove("hello"));//true;
        System.out.println(set.remove("d"));//false 删除某个元素
        System.out.println(set.size());//2 返回set中元素的个数
        System.out.println(set.isEmpty());//false 检测set是否为空
        List<String> list = new ArrayList<>();
        list.add("abc");
        list.add("def");
        list.add("fag");
        set.addAll(list);//将集合c中的元素添加到set中
        System.out.println(set);//[world, abc, def, school, fag]
        set.clear();//清空set
}

3.3遍历set

public static void main(String[] args) {
        //set不能添加重复元素
        Set<String> set = new HashSet<>();
        set.add("hello");
        set.add("world");
        set.add("school");//添加元素
        System.out.println(set);//[world, school, hello]
        //使用toArray(),将set中的元素转换为数组返回,对数组进行遍历
        Object[] array = set.toArray();
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i]+" ");//world school hello
        }
        System.out.println();
        //使用toArray(T[] a),传递一个数组,把集合中的元素存储到数组中
        String[] array1 = new String[set.size()];
        String[] strings = set.toArray(array1);
        for (int i = 0; i < strings.length; i++) {
            System.out.print(strings[i]+" ");//world school hello
        }
        System.out.println();
        //使用迭代器遍历
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.print(iterator.next()+" ");//world school hello
        }
    }

3.4 TreeSet和HashSet的不同

在这里插入图片描述

4.搜索树

4.1概念

二叉搜索树(二叉排序树):每一棵树的左子树小于根结点,右子树大于根结点,也可以是一棵空树
在这里插入图片描述

4.2实现

public class BinaryTree {
    static class TreeNode{
        public int val;
        public TreeNode left;
        public TreeNode right;
        public TreeNode(int val){
            this.val = val;
        }
    }
    public static TreeNode root;
    //查找二叉搜索树中是否包含某个元素
    public static boolean search(int val){
        if (root == null){
            return false;
        }
        TreeNode cur = root;
        while (cur!=null){
            //找到val
            if(cur.val==val){
                return true;
            }else if (cur.val>val){
                //大于val,在左子树找
                cur = cur.left;
            }else {
                //小于val,在左子树找
                cur = cur.right;
            }
        }
        return false;
    }
    //添加一个元素到二叉搜索树中
    public static boolean insert(int val) {
    //空树,直接插入到根结点
        if (root == null){
            root = new TreeNode(val);
        }
        TreeNode cur = root;
        TreeNode tmp = null;
        //找到插入位置的父亲结点
        while (cur!=null){
            if (cur.val > val){
                tmp = cur;
                cur = cur.left;
            }else if (cur.val < val){
                tmp = cur;
                cur = cur.right;
            }else {
                return false;
            }
        }
        if (tmp.val < val){
            tmp.right = new TreeNode(val);
        }else {
            tmp.left = new TreeNode(val);
        }
        return true;
    }

    //中序遍历二叉树
    public static void inorder(TreeNode root) {
        if (root == null){
            return;
        }
        inorder(root.left);
        System.out.print(root.val+" ");
        inorder(root.right);
    }
    //删除元素
    public static boolean remove(int key){
        if (root == null){
            return false;
        }
        TreeNode cur = root;
        TreeNode parent = null;
        //找到删除结点和要删除的结点的父节点
        while (cur != null){
            if (cur.val > key){
                parent = cur;
                cur = cur.left;
            }else if(cur.val < key){
                parent = cur;
                cur = cur.right;
            }else {
                removeNode(cur,parent);
                return true;
            }
        }
        return false;
    }
    public static void removeNode(TreeNode cur,TreeNode parent){
        if (cur.left == null){
            if (cur == root){
                root = root.right;
            }else if (parent.right == cur){
                parent.right = cur.right;
            }else {
            //parent.left == cur
                parent.left = cur.right;
            }
        }else if (cur.right == null){
            if (cur == root){
                root = root.left;
            }else if (parent.right == cur){
                parent.right = cur.left;
            }else {
            //parent.left == cur
                parent.left = cur.left;
            }
        }else {
        //cur.left!=null&&cur.right!=null
        //使用替代法删除,此处在右树找最小值
            TreeNode target = cur.right;
            TreeNode targetParent = cur;
            while (target.left != null){
                targetParent = target;
                target = target.left;
            }
            cur.val = target.val;
            if (target == targetParent.left){
                targetParent.left = target.right;
            }else {
                targetParent.right = target.right;
            }
        }
    }
}

4.3性能分析

(1)单分支的树:时间复杂度为N
(2)改进:AVL树(高度平衡的二叉树)、红黑树(RBTree)

5.哈希表

存储和取数据的时候都会遵守某种规则,称作哈希函数,哈希函数是可以自己设定的,构造出来的结构称哈希表(散列表),用该方法进行搜索不需要进行多次关键码的比较,因此搜索的效率比较高

5.1查找数据

(1)顺序查找:时间复杂度O(N)
(2)二分查找:时间复杂度O(logN)
(3)哈希表:增删查改的时间复杂度都可以达到O(1)

5.2冲突的概念

不同关键字通过相同哈希哈数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞

5.3冲突的避免方法

冲突的发生是必然的,我们只能尽量降低冲突的发生频率
(1)设计合理的哈希函数
设计原则:哈希函数定义域必须包括需要存储的全部关键码;哈希函数计算出来的地址能均匀分布在整个空间中;哈希函数应该比较简单
(2)调节负载因子
a,散列表的负载因子=填入表中的元素的个数/散列表的长度
b,负载因子和冲突率的关系
在这里插入图片描述
c,超过负载因子就需要扩容
d,想要降低冲突率就只能减少负载因子,想要减少负载因子就只能增加散列表的长度

5.4冲突的解决方法

(1)闭散列(开放定址法):空间利用率低
a,线性探测:放到冲突位置的下一个空的地方(不好删除;会把冲突元素放到一起)
b,二次探测:使用Hi = (H0+i^2)%m放到下一个空的地方(i是冲突的次数,H0是冲突的位置,m是散列表的长度)
(2)开散列(哈希桶/链地址法/开链法):把所有的元素挂到链表上,JDK1.8使用的是尾插法
a,解决:数组+链表+红黑树(树化是有条件的)
b,树化的条件:链表的长度超过8;数组的长度超过64
c,把红黑树变为链表的条件:树的结点为6
在这里插入图片描述
d,哈希表的扩容要注意:重新哈希

5.5实现(简单类型)

public class HashBuck {
    static class Node{
        public int key;
        public int val;
        public Node next;
        public Node(int key,int val){
            this.key = key;
            this.val = val;
        }
    }
    public int usedSize;//存放数据个数
    public static final double FACTOR = 0.75;//负载因子
    public Node[] array;
    public HashBuck(){
        this.array = new Node[8];
    }
    //插入元素
    public boolean put(int key,int val){
        Node node = new Node(key,val);
        //1、找到要插入下标的位置
        int index = key % array.length;
        //2、遍历这个下标的链表,看看有没有一样的值
        Node cur = array[index];
        while (cur!=null){
            if (cur.key == key){
                cur.val = val;//更新val的值
                return false;
            }
            cur = cur.next;
        }
        //3、遍历完成当前链表的值,若没有相同的就开始插入
        cur = array[index];
        node.next = cur;
        array[index] = node;
        this.usedSize++;
        //4、存放元素之后,判断当前哈希桶中的负载因子是否超过默认的负载因子
        if (loadFactor() >= FACTOR){
            //5、扩容
            resize();
        }
        return true;
    }
    //扩容
    private void resize(){
        //1、更新数组长度,申请二倍数组长度
        Node[] tmp = new Node[this.array.length*2];
        //2、遍历原来的数组,将每个小标的节点的数据都进行重新哈希
        for (int i = 0; i < array.length; i++) {
            Node cur = array[i];
            while (cur!=null){
                Node curNext = cur.next;
                int newIndex = cur.key % tmp.length;//新的数组的下标
                cur.next = tmp[newIndex];
                tmp[newIndex] = cur;
                cur = curNext;
            }
        }
        array = tmp;
    }
    //得到负载因子的值
    private double loadFactor(){
        return this.usedSize*1.0/this.array.length;
    }
    //获取val的值
    public int get(int key){
        int index = key % array.length;
        Node cur = array[index];
        while (cur != null){
            if (cur.key == key){
                return cur.val;
            }
            cur = cur.next;
        }
        return -1;
    }
}
//测试
public static void main(String[] args) {
        HashBuck h = new HashBuck();
        h.put(1,1);
        h.put(2,2);
        h.put(3,3);
        h.put(6,4);
        h.put(14,14);
        h.put(17,17);
        h.put(24,24);
        System.out.println('a');//在此处打断点
    }

5.6实现(泛型)

HashMap:

class Person{
    public String id;
    public Person(String id) {
        this.id = id;
    }
    @Override
    public String toString() {
        return "person{" +
                "id='" + id + '\'' +
                '}';
    }
    //找到下标下和key一样的结点
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return Objects.equals(id, person.id);
    }
    //找到下标的节点
    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}
public static void main(String[] args) {
        HashMap<Person,String> hashMap = new HashMap<>();
        Person p1 = new Person("12345");
        Person p2 = new Person("12345");
        hashMap.put(p1,"xian");
        System.out.println(hashMap.get(p2));//xian
    }

注意:
(1)以后我们自己定义的类一定要重写equals和HashCode,要知道HashCode一样,equals不一定一样,equals一样,HashCode一定一样
(2)HashSet的底层是一个HashMap(原码中HashSet存的元素作为HashMap的key,不能重复)
(3)map第一次添加元素的时候,容量才会赋予16

public class HashBuck2<k,v> {
    static class Node<k,v>{
        public k key;
        public v val;
        public Node<k,v> next;
        public Node(k key,v val){
            this.key = key;
            this.val = val;
        }
    }
    public Node<k,v>[] array = (Node<k,v>[])new Node[8];
    public static final double FACTOR = 0.75;//负载因子
    public int usedSize;
    public void put(k key,v val){
        Node<k,v> node = new Node<>(key,val);
        //1、找到要插入的下标位置
        int hash = key.hashCode();//将key变成一个整数
        int index = hash % array.length;
        //2、遍历这个下标的链表,看看有没有一样的值
        Node<k,v> cur = array[index];
        while (cur!=null){
            if (cur.key.equals(key)){
                cur.val = val;//更新val的值
            }
            cur = cur.next;
        }
        //3、遍历完成当前链表的值,若没有相同的就开始插入
        cur = array[index];
        node.next = cur;
        array[index] = node;
        this.usedSize++;
        //4、存放元素之后,判断当前哈希桶中的负载因子是否超过默认的负载因子
        if (loadFactor() >= FACTOR){
            //5、扩容
            resize();
        }
    }
    //扩容
    private void resize(){
        //1、更新数组长度,申请二倍数组长度
        Node<k,v>[] tmp = new Node[this.array.length*2];
        //2、遍历原来的数组,将每个小标的节点的数据都进行重新哈希
        for (int i = 0; i < array.length; i++) {
            Node<k,v> cur = array[i];
            while (cur!=null){
                Node<k,v> curNext = cur.next;
                int hash = array[i].hashCode();//将key变成一个整数
                int newIndex = hash % array.length;//新的数组的下标
                cur.next = tmp[newIndex];
                tmp[newIndex] = cur;
                cur = curNext;
            }
        }
        array = tmp;
    }
    //得到负载因子的值
    private double loadFactor(){
        return this.usedSize*1.0/this.array.length;
    }
    //获取val的值
    public v get(k key){
        int hash = key.hashCode();
        int index = hash % array.length;
        Node<k,v> cur = array[index];
        while (cur != null){
            if (cur.key.equals(key)){
                return cur.val;
            }
            cur = cur.next;
        }
        return null;
    }
}
//测试
public static void main(String[] args) {
        HashBuck2<Person,String> hashBuck2 = new HashBuck2<>();
        Person p1 = new Person("12345");
        Person p2 = new Person("12345");
        hashBuck2.put(p1,"xian");
        System.out.println(hashBuck2.get(p2));//xian
    }

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

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

相关文章

如何批量加密PDF文件并设置不同密码 - 批量PDF加密工具使用教程

如果你正在寻找一种方法来批量加密和保护你的PDF文件&#xff0c;批量PDF加密工具是一个不错的选择。 它是一个体积小巧但功能强大的Windows工具软件&#xff0c;能够批量给多个PDF文件加密和限制&#xff0c;包括设置打印限制、禁止文字复制&#xff0c;并增加独立的打开密码。…

LAMP架构介绍配置命令讲解

LAMP架构介绍配置命令讲解 一、LAMP架构介绍1.1概述1.2LAMP各组件的主要作用1.3各组件的安装顺序 二、编译安装Apache httpd服务---命令讲解1、关闭防火墙&#xff0c;将安装Apache所需的软件包传到/opt/目录下2、安装环境依赖包3、配置软件模块4、编译安装5、优化配置文件路径…

数据的深海潜行:数据湖、数据仓库与数据湖库之间的微妙关系

导言&#xff1a;数据的重要性与存储挑战 在这个信息爆炸的时代&#xff0c;数据已经成为企业的核心资产&#xff0c;而如何高效、安全、便捷地存储这些数据&#xff0c;更是每个组织面临的重大挑战。 数据作为组织的核心资产 数据在过去的几十年里从一个辅助工具演变成企业的…

【JVM 内存结构 | 程序计数器】

内存结构 前言简介程序计数器定义作用特点示例应用场景 主页传送门&#xff1a;&#x1f4c0; 传送 前言 Java 虚拟机的内存空间由 堆、栈、方法区、程序计数器和本地方法栈五部分组成。 简介 JVM&#xff08;Java Virtual Machine&#xff09;内存结构包括以下几个部分&#…

【一】ubuntu20.04上搭建containerd版( 1.2.4 以上)k8s及kuboard V3

k8s 部署全程在超级用户下进行 sudo su本文请根据大纲顺序阅读&#xff01; 一、配置基础环境&#xff08;在全部节点执行&#xff09; 1、安装docker 使用apt安装containerd 新版k8s已经弃用docker转为containerd&#xff0c;如果要将docker改为containerd详见&#xff1a…

【K8S源码之Pod漂移】整体概况分析 controller-manager 中的 nodelifecycle controller(Pod的驱逐)

参考 k8s 污点驱逐详解-源码分析 - 掘金 k8s驱逐篇(5)-kube-controller-manager驱逐 - 良凯尔 - 博客园 k8s驱逐篇(6)-kube-controller-manager驱逐-NodeLifecycleController源码分析 - 良凯尔 - 博客园 k8s驱逐篇(7)-kube-controller-manager驱逐-taintManager源码分析 - 良…

多维时序 | MATLAB实现PSO-CNN-BiLSTM多变量时间序列预测

多维时序 | MATLAB实现PSO-CNN-BiLSTM多变量时间序列预测 目录 多维时序 | MATLAB实现PSO-CNN-BiLSTM多变量时间序列预测基本介绍模型特点程序设计参考资料 基本介绍 本次运行测试环境MATLAB2021b&#xff0c;MATLAB实现PSO-CNN-BiLSTM多变量时间序列预测。代码说明&#xff1a…

Matplotlib数据可视化(五)

目录 1.绘制折线图 2.绘制散点图 3.绘制直方图 4.绘制饼图 5.绘制箱线图 1.绘制折线图 import matplotlib.pyplot as plt import numpy as np %matplotlib inline x np.arange(9) y np.sin(x) z np.cos(x) # marker数据点样式&#xff0c;linewidth线宽&#xff0c;li…

猿辅导Motiff亮相IXDC 2023国际体验设计大会,发布新功能获行业高度关注

近日&#xff0c;“IXDC 2023国际体验设计大会”在北京国家会议中心拉开序幕&#xff0c;3000设计师、1000企业、200全球商业领袖&#xff0c;共襄为期5天的用户体验创新盛会。据了解&#xff0c;此次大会是以“设计领导力”为主题&#xff0c;分享全球设计、科技、商业的前沿趋…

9.Sentinel哨兵

1.Sentinel Sentinel&#xff08;哨兵&#xff09;是由阿里开源的一款流量控制和熔断降级框架&#xff0c;用于保护分布式系统中的应用免受流量涌入、超载和故障的影响。它可以作为微服务架构中的一部分&#xff0c;用于保护服务不被异常流量冲垮&#xff0c;从而提高系统的稳定…

StreamingWarehouse的一些思考和未来趋势

300万字&#xff01;全网最全大数据学习面试社区等你来&#xff01; 一篇笔记。 以Hudi、Iceberg、Paimon这几个框架为例&#xff0c;它们支持高效的数据流/批读写、数据回溯以及数据更新。具备一些传统的实时和离线数仓不具备的特性&#xff0c;主要有几个方面&#xff1a; 这…

接口文档管理解决方案调研及Torna+Smart-doc的使用

文章目录 一、现状二、需求三、调研Swagger官方地址介绍 Knife4j官方地址介绍 Apifox官方地址介绍 Smart-doc Torna官方地址介绍 EasyYapi Yapi官方地址介绍 四、对比&#xff08;一&#xff09;Swagger1、部署方式2、优点3、缺点4、分享方式 &#xff08;二&#xff09;Knif…

VS+Qt 自定义Dialog

与QtCreator不同&#xff0c;刚用VS添加Qt Dialog界面有点懵&#xff0c;后整理了下&#xff1a; 1.右击项目&#xff0c;选择“添加-模块”&#xff0c;然后选择“Qt-Qt Widgets Class” 2.选择基类[1]QDialog,更改[2]ui文件名称&#xff0c;修改定义Dialog[3]对应类名&#…

学习Linux的注意事项(使用经验;目录作用;服务器注意事项)

本篇分享学习Linux过程中的一些经验 文章目录 1. Linux系统的使用经验2. Linux各目录的作用3. 服务器注意事项 1. Linux系统的使用经验 Linux严格区分大小写Linux中所有内容以文件形式保存&#xff0c;包括硬件&#xff0c;Linux是以管理文件的方式操作硬件 硬盘文件是/dev/s…

第4篇:vscode+platformio搭建esp32 arduino开发环境

第1篇:Arduino与ESP32开发板的安装方法 第2篇:ESP32 helloword第一个程序示范点亮板载LED 第3篇:vscode搭建esp32 arduino开发环境 1.配置默认安装路径&#xff0c;安装到D盘。 打开环境变量&#xff0c;点击新建 输入变量名PLATFORMIO_CORE_DIR与路径&#xff1a;D:\PLATF…

SpringBoot案例-配置文件-@ConfigurationProperties

问题分析 在往期的配置参数的文章中&#xff0c;对于阿里云OSS的参数时设置在yml配置文件中&#xff0c;然后使用Value&#xff08;”${}“&#xff09;对参数进行赋值&#xff0c;具体如下&#xff1a; 此种方法比较繁琐 问题解决 使用注解 Data 为变量自动生成get/set方…

游戏反外挂方案解析

近年来&#xff0c;游戏市场高速发展&#xff0c;随之而来的还有图谋利益的游戏黑产。在利益吸引下&#xff0c;游戏黑产扩张迅猛&#xff0c;已发展成具有庞大规模的产业链&#xff0c;市面上游戏受其侵扰的案例屡见不鲜。 据《FairGuard游戏安全2022年度报告》数据统计&…

IP协议报文结构

IP报文结构 4位版本号: 指定IP协议的版本, 对于IPv4来说, 就是4.4位头部长度: IP头部的长度是多少个32bit, 也就是 length * 4 的字节数. 4bit表示最大的数字是15, 因此IP头部最大长度是60字节.8位服务类型: 3位优先权字段(已经弃用) 4位TOS字段 1位保留字段(必须置为0). 4位…

C语言练习1(巩固提升)

C语言练习1 选择题 前言 “人生在勤&#xff0c;勤则不匮。”幸福不会从天降&#xff0c;美好生活靠劳动创造。全面建成小康社会的奋斗目标&#xff0c;为广大劳动群众指明了光明的未来&#xff1b;全面建成小康社会的历史任务&#xff0c;为广大劳动群众赋予了光荣的使命&…

缓存的设计方式

问题情况&#xff1a; 当有大量的请求到内部系统时&#xff0c;若每一个请求都需要我们操作数据库&#xff0c;例如查询操作&#xff0c;那么对于那种数据基本不怎么变动的数据来说&#xff0c;每一次都去数据库里面查询&#xff0c;是很消耗我们的性能 尤其是对于在海量数据…