哈希表 | 哈希查找 | 哈希函数 | 数据结构 | 大话数据结构 | Java

🙋大家好!我是毛毛张!
🌈个人首页: 神马都会亿点点的毛毛张

📌毛毛张今天分享的内容🖆是数据结构中的哈希表,毛毛张主要是依据《大话数据结构📖》的内容来进行整理,不同之处是使用Java语言来介绍其中的代码实现,同时也为后面介绍Java中的集合做铺垫🛤️

文章目录

  • 1.散列表查找(哈希表)概述
    • 1.1 散列表查找定义
    • 1.2 散列表查找步骤
  • 2.散列函数的构造方法
    • 2.1 直接定址法(了解)
    • 2.2 数字分析法(了解)
    • 2.3 平方取中法(了解)
    • 2.4 折叠法(了解)
    • 2.5 除留余数法(掌握)
    • 2.6 随机数法(了解)
  • 3.处理散列冲突
    • 3.1 开放定址法
    • 3.2 链地址法
    • 3.3 公共溢出区法
  • 4.散列表查找实现
    • 4.1 散列表查找的算法Java实现
    • 4.2 性能分析
  • 参考文献

1.散列表查找(哈希表)概述

1.1 散列表查找定义

  • 散列技术: 是在记录的存储位置和它的关键字之间建立一个确定的对应关系 f f f,使得每个关键字key对应一个存储位置 f ( k e y ) f(key) f(key)。查找时,根据这个确定的对应关系找到给定值key的映射 f ( k e y ) f(key) f(key),若查找集合中存在这个记录,则必定在 f ( k e y ) f(key) f(key)的位置上。我们把这种对应关系 f f f称为散列函数,又称哈希(Hash)函数
    存储位置 = f ( 关键字 ) 存储位置 = f(关键字) 存储位置=f(关键字)
  • 散列表/哈希表(Hash table): 采用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间称为散列表哈希表(Hash table)。而关键字对应的记录存储位置我们称为散列地址
  • 总结:
    • 散列表通过建立关键字和存储地址之间的一种直接映射关系,是一种根据关键字而直接进行访问的数据结构
    • 散列技术使得我们可以通过查找关键字不需要比较就可获得需要的记录的存储位置

1.2 散列表查找步骤

  • 散列过程步骤: 如下图
    • 第一步: 通过散列函数计算记录的散列地址,并按此散列地址存储记录
    • 第二步: 当查找记录时,我们通过同样的散列函数计算记录的散列地址,按此散列地址访问该记录,由于存取用的是同一个散列函数,因此结果当然也是相同的
      image-20240627154931051
  • 散列技术既是一种存储方法, 也是一种查找方法,而散列技术的记录之间不存在什么逻辑关系,它只与关键字有关联,因此散列主要是面向查找的存储结构
  • 散列技术最合适的求解问题是查找与给定值相等的记录
    • 不适合那种同样关键字,它能对应很多记录的情况,就不适合用散列技术
    • 散列表也不适合范围查找,比如查找一个班级18~22岁的同学,在散列表中没法进行
  • 冲突(collision): 散列函数可能会把两个或两个以上的不同关键字映射到同一地址,称这种情况为冲突,这些发生碰撞的不同关键字称为同义词
    • 一方面,设计得好的散列函数应尽量减少这样的冲突
    • 另一方面,由于这样的冲突总是不可避免的,所以还要设计好处理冲突的方法
  • 设计一个简单、均匀、存储利用率高的散列函数是散列技术中最关键的问题,一个好的散列表在理想情况下,对散列表进行查找的时间复杂度为$O(1) $,即与表中元素的个数无关

2.散列函数的构造方法

  • 好的散列函数设计原则:
    • 计算简单: 散列函数的计算应尽量简单,能够在较短的时间内计算出任一关键字对应的散列地址
    • 散列地址分布均匀: 散列函数计算出来的地址应该能等概率、均匀地分布在整个地址空间中,从而减少冲突的发生
    • 散列函数的定义域必须包含全部需要存储的关键字,而值域的范围则依赖于散列表的大小或地址范围
  • 下面介绍接种常用的散列函数构造方法

2.1 直接定址法(了解)

  • 直接取关键字的某个线性函数值为散列地址,散列函数为:其中a、b为常数
    f ( k e y ) = a × k e y + b f(key)=a×key + b f(key)=a×key+b
    image-20240627160121771
  • 这种方法计算最简单,且不会产生冲突,但并不常用。它适合关键字的分布基本连续的情况,若关键字分布不连续,空位较多,则会造成存储空间的浪费。

2.2 数字分析法(了解)

  • 例如当手机号码为关键字时,其11位数字是有规则的,此时是无需把11位数值全部当做散列地址,这时我们给关键词抽取, 抽取方法是使用关键字的一部分来计算散列存储位置的方法,这在散列函数中是常常用到的手段
  • 数字分析法通常适合处理关键字位数比较大的情况,如果事先知道关键字的分布且关键字的若干位分布较均匀,就可以考虑用这个方法。

2.3 平方取中法(了解)

  • 这个方法计算很简单,假设关键字是1234,那么它的平方就是1522756,再抽取中间的3位就是227,用做散列地址。
  • 再比如关键字是4321,那么它的平方就是18671041,抽取中间的3位就可以是671,也可以是710,用做散列地址。
  • 平方取中法比较适合于不知道关键字的分布,而位数又不是很大的情况

2.4 折叠法(了解)

  • 折叠法 是将关键字从左到右分割成位数相等的几部分(最后一部分位数可以短些),然后将这几部分叠加求和,并按散列表表长,取后几位作为散列地址。
  • 折叠法适合事先不需要知道关键字的分布,适合关键字位数比较多的情况

2.5 除留余数法(掌握)

  • 除留取余法对于散列表长为m的散列函数公式为:f(key)= key mod p (p ≤ m)mod是取模(求余数)的意思,这方法不仅可以对关键字直接取模,也可在折叠、平方取中后再取模。
  • 除留余数法的关键是就在于选择合适的 p p p p p p如果选择不好,就有可能产生同义词,根据前辈门的经验,若散列表表长为 m m m,通常 p p p为小于或等于表长(最好接近 m m m)的最小质数或不包含小于20质因子的合数
  • 图例:
    image-20240627161944061
  • 此方法是最常用的构造散列函数的方法

2.6 随机数法(了解)

  • 选择一个随机数,取关键字的随机函数值为它的散列地址。也就是 f ( k e y ) = r a n d o m ( k e y ) f(key)=random(key) f(key)=random(key)这里 r a n d o m random random是随机函数。
  • 当关键字的长度不等时,采用这个方法构造散列函数是比较合适的

3.处理散列冲突

  • 任何设计出来的散列函数都不可能绝对地避免冲突,因此,必须考虑在发生冲突时应该如何处理,即为产生冲突的关键字寻找下一个空的Hash地址
  • H i H_i Hi表示处理冲突中第 i i i次探测得到的散列地址,假设得到的另一个散列地址 H 1 H_1 H1仍然发生冲突,只得继续求下一个地址 H 2 H_2 H2,以此类推,直到 H k H_k Hk不发生冲突为止,则 H k H_k Hk为关键字在表中的地址

3.1 开放定址法

  • 开放定址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入
  • 计算公式: H i ( k e y ) = ( f ( k e y ) + d i ) % m   ( d i = 1 , 2 , 3 , . . . , m − 1 ) H_i(key)=(f(key)+d_i) \% m\ (d_i=1,2,3,...,m-1) Hi(key)=(f(key)+di)%m (di=1,2,3,...,m1),式中, H ( k e y ) H(key) H(key)为散列函数 i = 0 , 1 , 2 , . . . , k   ( k < = m − 1 ) i=0,1,2,...,k\ (k<=m-1) i=0,1,2,...,k (k<=m1) m m m表示散列列表表长; d i d_i di​​为增量序列
  • 取定某一增量序列后,对应的处理方法就是确定的,通常有以下4种方法:
  • 线性探测法:当 d i = 0 , 1 , 2 , . . . , m − 1 d_i=0,1,2,..., m-1 di=0,1,2,...,m1时,称为线性探测法
    • 特点: 当冲突发生时,顺序查看表中下一个单元(探测到表尾地址 m − 1 m-1 m1时,下一个探测地址是表首地址 0 0 0),直到找出一个空闲单元(当表未填满时一定能找到一个空闲单元)或查遍全表
    • 缺点: 线性探测法可能使第 i i i个散列地址的同义词存入第 i + 1 i+1 i+1个散列地址,这使得本应存入第 i + 1 i+1 i+1个散列地址的元素就争夺第 i + 2 i + 2 i+2个散列地址的元素的地址,从而造成大量元素在相邻的散列地址上堆积,大大降低了查找效率。
  • 平方探测法: d i = 0 2 , 1 2 , − 1 2 , 2 2 , − 2 2 , . . , k 2 , − k 2 d_i=0^2,1^2,-1^2,2^2,-2^2,..,k^2, -k^2 di=02,12,12,22,22,..,k2,k2时,称为平方探测法,其中 k < m / 2 k<m/2 k<m/2,散列表长度 m m m必须是一个可以表示成 4 k + 3 4k+ 3 4k+3​的素数,又称二次探测法
    • 平方探测法是一种较好的处理冲突的方法,可以避免出现堆积问题
    • 缺点: 不能探测到散列表上的所有单元,但至少能探测到一半单元
  • 再散列法: d i = H a s h 2 ( k e y ) d_i= Hash_2(key) di=Hash2(key)时,称为再散列法,又称双散列法,需要使用两个或者多个散列函数,当通过第一个散列函数 H ( k e y ) H(key) H(key)得到的地址发生冲突时,则利用第二个散列函数 H a s h 2 ( k e y ) Hash_2(key) Hash2(key)计算该关键字的地址增量
    • 具体散列函数形式为: H i = ( H ( k e y ) + i ∗ H a s h 2 ( k e y ) ) % m H_i= (H(key) + i*Hash_2(key)) \% m Hi=(H(key)+iHash2(key))%m,初始探测位置 H 0 = H ( k e y ) H_0 = H(key)% m H0=H(key) i i i是冲突的次数,初始为 0 0 0
    • 使用该方法,最多经过 m − 1 m-1 m1次探测就会遍历表中所有位置,回到 H 0 H_0 H0​位置
    • 这种方法使得关键字不产生剧集,相应地也增加了计算的时间
  • 伪随机数探测法: 在发生冲突时,对于位移量 d i d_i di​采用随机函数计算得到,称为伪随机探测法
    • 伪随机数是说,如果我们设置随机种子相同,则不断调用随机函数可以生成不会重复的数列,我们在查找时,用同样的随机种子,它每次得到的数列是相同的,相同的 d i d_i di当然可以得到相同的散列地址

注意:

  • 在开放定址的情形下,不能随便物理删除表中的已有元素,因为若删除元素,则会截断其他具有相同散列地址的元素的查找地址。
  • 因此,要删除一个元素时,可给它做一个删除标记,进行逻辑删除。
  • 但这样做的副作用是:执行多次删除后,表面上看起来散列表很满,实际上有许多位置未利用,因此需要定期维护散列表,要把删除标记的元素物理删除。

3.2 链地址法

  • 将所有关键字为同义词的记录存储在一个单链表中,我们称这种表为同义词子表,在散列表中只存储所有同义词子表的头指针
  • 示例: 有关键字序列为 { 12 , 67 , 56 , 16 , 25 , 37 , 22 , 29 , 15 , 47 , 48 , 34 } \{12, 67, 56, 16, 25, 37, 22, 29,15, 47,48, 34\} {12,67,56,16,25,37,22,29,15,47,48,34},我们用除留余数法构造散列函数 H ( k e y ) = k e y % 12 H(key)=key\%12 H(key)=key%12,用链地址法处理冲突,建立的表如下图所示
    image-20240627173927852
  • 链地址法对于可能会造成很多冲突的散列函数来说,提供了绝不会出现找不到地址的保障。当然,这也就带来了查找时需要遍历单链表的性能损耗

3.3 公共溢出区法

  • 这个方法其实就更加好理解,就是把凡是冲突的家伙额外找个公共场所待着,我们为所有冲突的关键字建立了一个公共的溢出区来存放
  • 示例:我们共有三个关键字 37 , 48 , 34 {37,48,34} 37,48,34与之前的关键字位置有冲突,那么就将它们存储到溢出表中,如下图所示
    在这里插入图片描述
  • 查找步骤:
    • 在查找时,对给定值通过散列函数计算出散列地址后,先与基本表的相应位置进行对比,如果相等,则查找成功;
    • 如果不相等,则到溢出表去进行顺序查找
  • 如果相对于基本表而言,有冲突的数据很少的情况下,公共溢出区的结构对查找性能来说还是非常高的

4.散列表查找实现

4.1 散列表查找的算法Java实现

  • 首先是需要定义一个散列表的结构以及一些相关的常数,其中HashTable就是散列表类,结构当中的elem为一个动态数组
public class HashTable {
    public static final int SUCCESS = 1;
    public static final int UNSUCCESS = 0;
    public static final int HASHSIZE = 12;    // 定义散列表表长为数组的长度
    public static final int NULLKEY = -32768; // 代表空地址

    private int[] elem;  // 数组元素存储基址,动态分配数组
    private int count;   // 当前数据元素个数
    private static int m = HASHSIZE; // 散列表表长,全局变量
}
  • 利用构造函数对散列表进行初始化
 public HashTable() {
     m = HASHSIZE;
     this.count = m;
     this.elem = new int[m];
     for (int i = 0; i < m; i++) {
         this.elem[i] = NULLKEY; // 初始化为空地址
     }
}
  • 为了插入时计算地址,我们需要定义散列函数,散列函数可以根据不同情况更改算法
// 散列函数
public int hash(int key) {
    return key % m;  // 除留余数法
}
  • 初始化完成后,我们可以对散列表进行插入操作,假设我们插入的关键字集合为 12 , 67 , 56 , 16 , 25 , 37 , 22 , 29 , 15 , 47 , 48 , 34 {12,67,56,16,25,37,22,29,15,47, 48,34} 12,67,56,16,25,37,22,29,15,47,48,34
 // 插入关键字进散列表
public void insertHash(int key) {
    int addr = hash(key);  // 通过散列函数求散列地址
    // 如果不为空,则冲突
    while (this.elem[addr] != NULLKEY) {
        addr = (addr + 1) % m;  // 开放定址法的线性探测
    }
    this.elem[addr] = key;  // 直到有空位后插入关键字
}
  • 代码中插入关键字时,首先算出散列地址,如果当前地址不为空关键字,则说明有冲突。此时我们应用开放定址法的线性探测进行重新寻址,此处也可更改为链地址法等其他解决冲突的办法。
  • 散列表存在后,我们在需要时就可以通过散列表查找要的记录
// 散列表查找关键字,找到后用addr保存地址
public boolean searchHash(int key, int[] addr) {
    addr[0] = hash(key);  // 通过散列函数求得散列地址
    // 如果不为空,则有同义词冲突
    while (this.elem[addr[0]] != key) {
        addr[0] = (addr[0] + 1) % m;  // 开放地址法的线性探测
        if (this.elem[addr[0]] == NULLKEY || addr[0] == hash(key)) {
            // 如果循环到空址或回到原点
            return false;  // 则说明关键字不存在
        }
    }
    return true;
}
  • 查找的代码与插入的代码非常类似,只需做一个不存在关键字的判断而已
  • 完整的测试代码如下:
public class HashTable {
    public static final int SUCCESS = 1;
    public static final int UNSUCCESS = 0;
    public static final int HASHSIZE = 12;    // 定义散列表表长为数组的长度
    public static final int NULLKEY = -32768; // 代表空地址

    private int[] elem;  // 数组元素存储基址,动态分配数组
    private int count;   // 当前数据元素个数
    private static int m = HASHSIZE; // 散列表表长,全局变量

    public HashTable() {
        this.elem = new int[HASHSIZE];
        this.count = HASHSIZE;
        for (int i = 0; i < HASHSIZE; i++) {
            this.elem[i] = NULLKEY; // 初始化为空地址
        }
    }

    // 初始化散列表
    public boolean initHashTable() {
        m = HASHSIZE;
        this.count = m;
        this.elem = new int[m];
        for (int i = 0; i < m; i++) {
            this.elem[i] = NULLKEY; // 初始化为空地址
        }
        return true;
    }

    // 散列函数
    public int hash(int key) {
        return key % m;  // 除留余数法
    }

    // 插入关键字进散列表
    public void insertHash(int key) {
        int addr = hash(key);  // 通过散列函数求散列地址
        // 如果不为空,则冲突
        while (this.elem[addr] != NULLKEY) {
            addr = (addr + 1) % m;  // 开放定址法的线性探测
        }
        this.elem[addr] = key;  // 直到有空位后插入关键字
    }

    // 散列表查找关键字,找到后用addr保存地址
    public boolean searchHash(int key, int[] addr) {
        addr[0] = hash(key);  // 通过散列函数求得散列地址
        // 如果不为空,则有同义词冲突
        while (this.elem[addr[0]] != key) {
            addr[0] = (addr[0] + 1) % m;  // 开放地址法的线性探测
            if (this.elem[addr[0]] == NULLKEY || addr[0] == hash(key)) {
                // 如果循环到空址或回到原点
                return false;  // 则说明关键字不存在
            }
        }
        return true;
    }

    public static void main(String[] args) {
        HashTable hashTable = new HashTable();
        boolean isInitialized = hashTable.initHashTable();
        System.out.println("HashTable initialized: " + isInitialized);

        // 插入一些关键字
        hashTable.insertHash(10);
        hashTable.insertHash(22);
        hashTable.insertHash(31);
        hashTable.insertHash(4);

        // 查找关键字
        int[] addr = new int[1];
        boolean found = hashTable.searchHash(22, addr);
        System.out.println("Key 22 found: " + found + ", at address: " + addr[0]);

        found = hashTable.searchHash(15, addr);
        System.out.println("Key 15 found: " + found);
    }
}

4.2 性能分析

  • 虽然散列表在关键字与记录的存储位置之间建立了直接映像,但由于冲突的产生,使得散列表的查找过程仍然是一个给定值和关键字进行比较的过程,因此,仍需要以平均查找长度作为衡量散列表的查找效率的度量。如果没有冲突,散列查找的时间复杂度是最高的,时间复杂度为 O ( 1 ) O(1) O(1)
  • 若用 c i c_i ci表示每一个关键字查找的次数,则平均查找次数可表示为: A S L = ( ∑ i = 0 m c i ) / m ASL=(\displaystyle\sum_{i=0}^{m}c_i)/m ASL=(i=0mci)/m
  • 散列表的查找效率取决于三个因素:
    • 散列函数是否均匀:散列函数的好坏直接影响着出现冲突的频繁程度,不过,由于不同的散列函数对同一组随机的关键字,产生冲突的可能性是相同的,因此我们可以不考虑它对平均查找长度的影响
    • 处理冲突的方法:相同的关键字、相同的散列函数,但处理冲突的方法不同,会使得平均查找长度不同。比如线性探测处理冲突可能会产生堆积,显然就没有二次探测法好,而链地址法处理冲突不会产生任何堆积,因而具有更佳的平均查找性能
    • 散列表的装填因子
  • 装填因子: 散列表的装填因子一般记为 α \alpha α,它用来表征散列表的装满程度,其计算公式为: α = n ( 表中填入的记录个数 ) / m ( 散列表长度 ) \alpha=n_{(表中填入的记录个数)}/m_{(散列表长度)} α=n(表中填入的记录个数)/m(散列表长度)
  • 散列表的平均查找长度取决于散列表的装填因子 α \alpha α,而不直接依赖于 n n n m m m
    • 直观地看, α \alpha α越大,表示装填的记录越,发生冲突的可能性越大,反之发生冲突的可能性越小
  • 不管记录个数 n n n有多大,我们总可以选择一个合适的装填因子以便将平均查找长度限定在一个范围之内,此时我们散列查找的时间复杂度就真的是 O ( 1 ) O(1) O(1)了。 为了做到这一点,通常我们都是将散列表的空间设置得比查找集合大,此时虽然是浪费了一定的空间,但换来的是查找效率的大大提升,总的来说,还是非常值得的。

参考文献

  • 《大话数据结构》
  • https://blog.csdn.net/Real_Fool_/article/details/114359564
  • https://blog.csdn.net/qq_56884023/article/details/123072671

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

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

相关文章

vue的学习--day2

如有错误&#xff0c;烦请指正~ 目录 一、什么是单页面应用程序 二、使用工具&#xff1a;node.js 三、工具链 易错点 一、什么是单页面应用程序 多个组件&#xff08;例如登录、注册等以vue结尾的都叫做组件&#xff09;在一个页面显示&#xff0c;叫单页面应用…

Linux C 程序 【02】创建线程

1.开发背景 上一个篇章&#xff0c;基于 RK3568 平台的基础上&#xff0c;运行了最简单的程序&#xff0c;然而我们使用了 Linux 系统&#xff0c;系统自带的多线程特性还是比较重要的&#xff0c;这个篇章主要描述线程的创建。 2.开发需求 设计实验&#xff1a; 创建一个线程…

极验行为式验证码适配HarmonyOS 鸿蒙SDK下载

现阶段&#xff0c;越来越多的开发者正在积极加入鸿蒙生态系统。随着更多开发者的参与&#xff0c;早在去年9月&#xff0c;极验就成为首批拥有鸿蒙NEXT内测版本和手机系统测试机会的验证码供应商。 为了提高各开发者及企业客户集成鸿蒙版本行为验4.0的效率&#xff0c;方便大家…

Android 通知组

一. 通知组简介 从 Android 7.0&#xff08;API 级别 24&#xff09;开始&#xff0c;您可以在一个组中显示相关通知。如下所示: 图 1. 收起&#xff08;顶部&#xff09;和展开&#xff08;底部&#xff09;的通知组。 注意 &#xff1a;如果应用发出 4 条或更多条通知且未…

大数据平台需要存算分离吗?某保险集团:以 ZBS 优化资源利用率,缩短业务用时超一半

金融机构普遍采用“存算一体”架构支撑基于 Hadoop 框架的大数据平台。而随着金融业务的多元化发展&#xff0c;不同业务对计算和存储的需求差异较大&#xff0c;由于“存算一体”架构共享存储与计算资源&#xff0c;经常会出现资源需求不均衡、资源利用率低下、难以灵活调度等…

工具篇:鸿蒙DevEco Studio5.0版本下载及安装

1、下载中心地址 下载中心 | 华为开发者联盟-HarmonyOS开发者官网&#xff0c;共建鸿蒙生态 2、安装 DevEco Studio支持Windows和macOS系统&#xff0c;下面将针对两种操作系统的软件安装方式分别进行介绍。 Windows环境 运行环境要求 为保证DevEco Studio正常运行&#…

Mysql需要知道的点

目录 一、数据库的三范式是什么 二、Mysql数据库引擎有哪些 三、说说Innodb与MYISAM的区别 四、数据库的事务 五、索引是什么 六、优化手段有哪些 七、简单说一说 drop&#xff0c;delete与truncate的区别 八、什么是视图 九、什么是内连接、左外连接、右外连接&#x…

Ubuntu20.04使用Samba

目录 一、Samba介绍 Samba 的主要功能 二、启动samba 三、主机操作 四、Ubuntu与windows系统中文件互联 五、修改samba路径 一、Samba介绍 Samba 是一个开源软件套件&#xff0c;用于在 Linux 和 Unix 系统上实现 SMB&#xff08;Server Message Block&#xff09;协议…

[行业原型] Web端原型案例:康欣医疗后台管理系统

​医疗管理系统是一个业务复杂&#xff0c;功能庞大的系统&#xff0c;以下为HIS医院管理系统的常见模块&#xff0c;供大家参考。 本周为大家带来Web端原型案例&#xff1a;康欣医疗后台管理系统&#xff0c;先上原型&#xff1a; 完整文档加班主任微信号 添加班主任回复 “1…

ansible常用模块详解

一、Ansible 1.1 简介 Ansible是自动化运维工具&#xff0c;能实现跨主机对应用编排管理部署。 Ansible能批量配置、部署、管理上千台主机&#xff0c;是应用级别的跨主机编排工具。 比如以前需要切换到每个主机上执行的一或多个操作&#xff0c;使用Ansible只需在固定的一…

练习实践:ubuntu18.04安装、配置Nginx+PHP环境,两种配置方式,多站点

参考来源&#xff1a; https://help.aliyun.com/document_detail/464753.html https://www.cnblogs.com/laosan007/p/12803287.html https://blog.csdn.net/qq_55364077/article/details/132207083 【安装同版本7.2的php】 需要知道对应php和nginx的安装版本 需要安装php-fpm…

stl之string

构造函数 void test1() {string s1;//不传参cout << s1 << endl;string s2("123456");cout << s2 << endl;string s3(s2);cout << s3 << endl;string s4(s2, 1, 5);cout << s4 << endl;string s5("123456&quo…

PHP 网络通信底层原理分析

大家好&#xff0c;我是码农先森。 引言 我们日常的程序开发大多数都是以业务为主&#xff0c;很少会接触到底层逻辑。对于我们程序员来说&#xff0c;了解程序的底层运行逻辑&#xff0c;更有助于提升我们对程序的理解。我相信大多数的人&#xff0c;每天基本上都是完成业务…

丝杆支撑座:滚珠丝杆稳定运行的守护者!

丝杆支撑座是丝杆和电机之间连接的重要组成部分&#xff0c;发挥着非常重要的功能。提到丝杆支撑座和滚珠丝杆&#xff0c;很多人都会想到支撑关系&#xff0c;但丝杆支撑座作为滚珠丝杆系统中至关重要的角色&#xff0c;其作用远不止于简单的支撑。 丝杆支撑座安装过程非常简单…

第30课 绘制原理图——放置网络标签

什么是网络标签&#xff1f; 我们在很多电路图中都能看到&#xff0c;为了让图纸更加简洁&#xff0c;并不是每一根导线都要确确实实地画出来。可以在导线悬空的一端添加一个名称标签&#xff0c;接着在另一根导线的悬空一端添加上一个同名的名称标签&#xff0c;那么就可以让…

【自监督-MIM】系列方法学习二

Masked image modeling 是一种训练深度学习模型的技术,尤其是在视觉领域,类似于自然语言处理中的掩码语言建模(Masked Language Modeling)。它通过在输入图像中随机遮挡(或称为掩码)部分区域,然后训练模型来预测这些被遮挡部分的内容,从而提高模型的视觉理解能力。 Ma…

IDEA无法输入中文,怎么破

1.导航栏处&#xff0c;点击help菜单&#xff0c;选择Edit Custom VM Options.. 2.编辑文件&#xff0c;在文件末尾添加&#xff1a; -Drecreate.x11.input.methodtrue 3.保存文件即可&#xff0c;如果还是不行&#xff0c;就关闭所有Idea程序&#xff0c;重新启动Idea

机器学习之集成学习

一&#xff1a;概念 顾名思义集成学习就是用多个其他的算法结合起来使用 对于“其他算法”有同类和同质的区别&#xff0c;同质指的是所用的算法都是同一类型的&#xff0c;比如决策树和神经网络&#xff0c;这种也叫基学习器。反之亦然&#xff0c;但一般使用的是同质的。 …

网络治理新模式:Web3时代的社会价值重构

随着Web3技术的崛起&#xff0c;传统的网络治理模式正在经历革新&#xff0c;这不仅仅是技术的进步&#xff0c;更是对社会价值观念的挑战和重构。本文将深入探讨Web3时代的网络治理新模式&#xff0c;其背后的技术基础、社会影响以及未来的发展方向。 1. 引言 Web3时代&#…

文件进行周期性备份后权限更改的解决方案--使用脚本和定时任务

这里写目录标题 背景现象解决方案原因分析面临的问题解决思路操作步骤每个文件夹权限分配表测试chmod和chown两个命令是否可行写脚本实现定时同步同时修改权限 异地同步改权限在NAS上生成SSH密钥对将NAS的公钥复制到Linux服务器在NAS上编写同步脚本在NAS上执行脚本&#xff0c;…