c 中的哈希表

  1. 哈希是一種可以接受各種類型、大小的輸入,輸出一個固定長度整數的過程。
  2. 你可以將哈希理解成一種特殊的映射,哈希映射,將一個理論無限的集合A映射到有限整數集合B上。

哈希函數:哈希函數是哈希過程的核心,它決定了哈希映射過程的規則。

哈希沖突:哈希是一種化無限為有限的映射,允許出現多對一,但絕不允許出現一對多。若映射中出現多對一,就是哈希沖突。哈希沖突可以減少,但絕不可能沒有。

哈希函數

/* murmur_hash2 */
static uint32_t hash(const void* key, int len, uint32_t seed) {const uint32_t m = 0x5bd1e995;const int r = 24;uint32_t h = seed ^ len;const unsigned char* data = (const unsigned char*)key;while (len >= 4) {uint32_t k = *(uint32_t*)data;k *= m;k ^= k >> r;k *= m;h *= m;h ^= k;data += 4;len -= 4;}switch (len) {case 3: h ^= data[2] << 16;case 2: h ^= data[1] << 8;case 1: h ^= data[0];h *= m;};h ^= h >> 13;h *= m;h ^= h >> 15;return h;
}

?

MurmurHash 是一種非加密哈希函數,適用于一般的哈希檢索操作。它以高運行速度和分布均勻性而聞名。其中uint32_t表示無符號 32 位整型,要想使用它需要包含頭文件<stdint.h>

該函數調用需要三個參數:

  1. void* key,也就是需要計算哈希值的key元素。此形參的類型是void*,這意味著它可以傳入任何類型的數據,提高了函數的通用性。

    1. 如果key是基本數據類型,那就傳入指向基本數據類型的指針
    2. 如果key本身就是一個指針類型,比如字符串,那么就直接傳入這個指針就可以了。
  2. int len,表示哈希函數要處理的key的大小長度。key若是字符串可以使用函數strlen計算,若是其它類型可以使用sizeof計算。
  3. uint32_t seed,種子值。

    1. 此哈希函數會根據key和seed共同生成一個哈希值
    2. 不同的種子值會導致相同的數據產生不同的哈希值。需要注意的是,在程序一次運行中,同一個哈希表應該具有相同的種子值!
    3. 最常見的設置種子值的方式就是用時間戳,也就是time(NULL);函數調用。這對于大家而言,應該都比較熟悉了。

?拉鏈法實現固定容量的哈希表

#ifndef HASH_MAP_H
#define HASH_MAP_H#include <stdint.h> // 包含它是為了使用別名uint32_t
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define HASHMAP_CAPACITY 10 // 哈希表中數組的長度固定是10// 此時哈希表用于存儲字符串類型的鍵值對
typedef char *KeyType;
typedef char *ValueType;// 鍵值對結點
typedef struct node_s {KeyType key;ValueType val;struct node_s *next;
} KeyValueNode;typedef struct {// 哈希桶KeyValueNode *buckets[HASHMAP_CAPACITY];    // 直接給定哈希桶的數量是10個// 哈希函數需要的種子值uint32_t hash_seed;
} HashMap;// 創建一個固定容量的哈希表
HashMap *hashmap_create();
// 銷毀一個哈希表
void hashmap_destroy(HashMap *map);
// 插入一個鍵值對
ValueType hashmap_put(HashMap *map, KeyType key, ValueType val);
// 查詢一個鍵值對
ValueType hashmap_get(HashMap *map, KeyType key);
// 刪除某個鍵值對
bool hashmap_remove(HashMap *map, KeyType key);#endif // !HASH_MAP_H

?

實現創建哈希表

// 創建一個固定容量的哈希表
HashMap *hashmap_create() {HashMap *map = calloc(1, sizeof(HashMap));if (map == NULL) {printf("error: calloc failed in hashmap_create.\n");exit(-1);}map->hash_seed = time(NULL);return map;
}

?

實現哈希表銷毀

// 銷毀一個哈希表
void hashmap_destroy(HashMap *map) {// 遍歷數組,然后銷毀哈希桶中的鏈表,最后銷毀HashMap結構體for (size_t i = 0; i < HASHMAP_CAPACITY; i++) {KeyValueNode *curr = map->buckets[i];while (curr != NULL) {KeyValueNode *tmp = curr->next;free(curr);curr = tmp;}}free(map);
}

?

實現插入鍵值對

// 插入一個鍵值對
ValueType hashmap_put(HashMap *map, KeyType key, ValueType val) {// 1.計算哈希值確定哈希桶的位置int idx = hash(key, strlen(key), map->hash_seed) % HASHMAP_CAPACITY;// 2.遍歷哈希桶,查找Key是否重復KeyValueNode *curr = map->buckets[idx];while (curr != NULL) {// 比較字符串if (strcmp(key, curr->key) == 0) {// key已存在,更新value,并返回舊valueValueType old_val = curr->val;curr->val = val;return old_val;}curr = curr->next;}// 3.只要Key不重復肯定都要插入,于是無腦使用鏈表頭插法插入結點KeyValueNode *new_node = malloc(sizeof(KeyValueNode));if (new_node == NULL) {printf("Error: malloc failed in hashmap_put.\n");exit(1);}new_node->key = key;    // key和val都是指針類型,可以直接"="賦值new_node->val = val;// 鏈表頭插法new_node->next = map->buckets[idx]; // 新結點指向原本的第一個結點map->buckets[idx] = new_node;   // 更新頭指針// 沒有更新鍵值對返回空指針return NULL;
}

?

實現鍵值對查詢

// 查詢一個鍵值對
ValueType hashmap_get(HashMap *map, KeyType key) {// 1.計算哈希值確定哈希桶的位置int idx = hash(key, strlen(key), map->hash_seed) % HASHMAP_CAPACITY;// 2.遍歷哈希桶,查找Key是否存在KeyValueNode *curr = map->buckets[idx];while (curr != NULL) {// 比較字符串if (strcmp(key, curr->key) == 0) {// 已找到目標鍵值對return curr->val;}curr = curr->next;}// 目標鍵值對不存在return NULL;
}

?

實現鍵值對刪除

// 刪除某個鍵值對
bool hashmap_remove(HashMap *map, KeyType key) {// 1.計算哈希值確定哈希桶的位置int idx = hash(key, strlen(key), map->hash_seed) % HASHMAP_CAPACITY;// 2.初始化兩個指針,用于刪除結點KeyValueNode *curr = map->buckets[idx];KeyValueNode *prev = NULL;// 3.遍歷鏈表查找目標Keywhile (curr != NULL) {// 比較字符串if (strcmp(key, curr->key) == 0) {// 已找到目標鍵值對if (prev == NULL) {// 刪除的是第一個結點map->buckets[idx] = curr->next;}else{// 刪除的不是第一個結點prev->next = curr->next;}// free結點free(curr);return true;    // 刪除成功}prev = curr;        // 更新prev為當前節點curr = curr->next;  // 當前結點向后移動}// 沒找到目標鍵值對,刪除失敗return false;
}

?

負載因子(Load Factor

?一般來說,負載因子在0.7/0.75以下時,哈希表處在健康、性能優秀的狀態。但一旦超出這個閾值,就意味著哈希沖突會增多,鏈表平均長度變長,從而導致性能下降。

  1. 最佳情況下,即哈希函數均勻分布且沖突較少時,哈希表的插入、查詢和刪除操作的效率非常高,接近 O(1)。
  2. 最壞情況下,特別是哈希沖突很多導致鏈表過長時,這些操作的效率會降低,接近 O(L),因為此時的哈希表訪問幾乎相當于鏈表的訪問。

?實現動態哈希表

頭文件

#ifndef DYNAMIC_HASHMAP_H
#define DYNAMIC_HASHMAP_Htypedef char *KeyType;
typedef char *ValueType;#include <stdint.h>typedef struct node_s {KeyType key;ValueType val;struct node_s *next;
} KeyValueNode;typedef struct {KeyValueNode **buckets;     // 此時哈希桶是一個動態數組,指向char*元素的指針,所以是一個二級指針int size;               // 鍵值對的個數int capacity;           // 數組的長度uint32_t hash_seed;     // 哈希函數需要的種子值
} DynamicHashMap;// 創建一個固定容量的哈希表
DynamicHashMap *hashmap_create();
// 銷毀一個哈希表
void hashmap_destroy(DynamicHashMap *map);
// 插入一個鍵值對
ValueType hashmap_put(DynamicHashMap *map, KeyType key, ValueType val);
// 查詢一個鍵值對
ValueType hashmap_get(DynamicHashMap *map, KeyType key);
// 刪除某個鍵值對
bool hashmap_remove(DynamicHashMap *map, KeyType key);#endif // !DYNAMIC_HASHMAP_H

?

實現創建和銷毀動態哈希表

#include "dynamic_hashmap.h"
#define DEFAULT_CAPACITY 8  // 哈希表的初始默認容量是8// 創建一個固定容量的哈希表
DynamicHashMap *hashmap_create() {DynamicHashMap *map = malloc(sizeof(DynamicHashMap));if (map == NULL) {printf("Error: malloc failed in hashmap_create\n");exit(1);}map->buckets = calloc(DEFAULT_CAPACITY, sizeof(KeyValueNode *));if (map->buckets == NULL) {// 不要忘記先free結構體free(map);printf("Error: calloc failed in hashmap_create\n");exit(1);}// 初始化其它成員map->size = 0;map->capacity = DEFAULT_CAPACITY;map->hash_seed = time(NULL);return map;
}// 銷毀一個哈希表
void hashmap_destroy(DynamicHashMap *map) {// 1.先遍歷動態數組銷毀鏈表的每一個結點for (int i = 0; i < map->capacity; i++) {KeyValueNode *curr = map->buckets[i];while (curr != NULL) {KeyValueNode *tmp = curr->next;free(curr);curr = tmp;}}// 2.再銷毀動態數組free(map->buckets);// 3.最后銷毀哈希表結構體free(map);
}

?

實現插入和擴容功能

#define LOAD_FACTOR_THRESHOLD  0.75     // 負載因子的閾值
#define CAPACITY_THRESHOLE 1024     // 數組容量的閾值/* murmur_hash2 */
static uint32_t hash(const void* key, int len, uint32_t seed) {const uint32_t m = 0x5bd1e995;const int r = 24;uint32_t h = seed ^ len;const unsigned char* data = (const unsigned char*)key;while (len >= 4) {uint32_t k = *(uint32_t*)data;k *= m;k ^= k >> r;k *= m;h *= m;h ^= k;data += 4;len -= 4;}switch (len) {case 3: h ^= data[2] << 16;case 2: h ^= data[1] << 8;case 1: h ^= data[0];h *= m;};h ^= h >> 13;h *= m;h ^= h >> 15;return h;
}static void rehash(KeyValueNode *curr, KeyValueNode **new_table, int new_capacity, uint32_t seed) {// 計算 key 的哈希值int len = strlen(curr->key);int idx = hash(curr->key, len, seed) % new_capacity;// 頭插法curr->next = new_table[idx];new_table[idx] = curr;
}// 對哈希表進行擴容操作
static void grow_capacity(DynamicHashMap *map) {/** 擴容策略:* 1.如果容量沒有達到閾值,那就每次將長度擴大為原先的2倍* 2.如果容量達到閾值,此時哈希表已經很長了,為了避免擴容過程性能損耗過大*   所以擴容保守一些,每次只擴容閾值長度的容量** 擴容的過程:* 1.每個鍵值對結點都要重新計算哈希值,重新映射到新哈希桶中(新數組)* 2.原先的動態數組的鏈表很復雜,難以進行重哈希操作,建議直接丟棄它* 重新創建一個新動態數組*/int new_capacity =(map->capacity <= CAPACITY_THRESHOLE) ?(map->capacity << 1) :(map->capacity + CAPACITY_THRESHOLE);// 動態數組擴容需要使用 callocKeyValueNode **new_buckets = calloc(new_capacity, sizeof(KeyValueNode *));if (new_buckets == NULL) {printf("Error: calloc failed in grow_capacity\n");exit(1);}// 每次擴容都更改一次哈希種子,提高安全性uint32_t seed = time(NULL);// 將所有鍵值對重新映射到新數組中for (int i = 0; i < map->capacity; i++) {KeyValueNode *curr = map->buckets[i];while (curr != NULL) {KeyValueNode *next = curr->next;// 重新進行哈希映射rehash(curr, new_buckets, new_capacity, seed);curr = next;}}// 將舊動態數組free,但是注意不要free鍵值對結點,結點已經被鏈接到新數組中了。free(map->buckets);// 更新 HashMap 的信息map->buckets = new_buckets;map->capacity = new_capacity;map->hash_seed = seed;
}// 插入一個鍵值對
// 1. 如果key不存在,則添加鍵值對結點
// 2. 如果key存在,則更新val,將舊的val返回
ValueType hashmap_put(DynamicHashMap *map, KeyType key, ValueType val) {// 計算key的哈希值確定存儲位置int idx = hash(key, strlen(key), map->hash_seed) % (map->capacity);// 遍歷鏈表KeyValueNode *curr = map->buckets[idx];while (curr != NULL) {if (strcmp(key, curr->key) == 0) {// 更新 key 關聯的 val, 并將舊的value返回ValueType old_val = curr->val;curr->val = val;return old_val;}curr = curr->next;} // while循環結束時, curr是一個NULL// 鍵值對不存在,即需要將鍵值對插入// 插入操作前需要計算當前哈希表的負載因子double load_factor = (1.0 * map->size) / (map->capacity);if (load_factor >= LOAD_FACTOR_THRESHOLD) {// 當前哈希表負載因子已達到閾值,將動態數組進行擴容grow_capacity(map);// 數組長度已變,需要再哈希確定當前鍵值對的存儲位置idx = hash(key, strlen(key), map->hash_seed) % (map->capacity);}// 開始插入新鍵值對KeyValueNode *new_node = malloc(sizeof(KeyValueNode));if (new_node == NULL) {printf("Error: malloc failed in hashmap_put\n");exit(1);}// 初始化結點new_node->key = key;new_node->val = val;// 鏈表的頭插法new_node->next = map->buckets[idx];map->buckets[idx] = new_node;// 不要忘記更新sizemap->size++;return NULL;
}

?

訪問和刪除鍵值對

// 查詢一個鍵值對
ValueType hashmap_get(DynamicHashMap *map, KeyType key) {// 計算key的哈希值,從而確定哈希桶int idx = hash(key, strlen(key), map->hash_seed) % map->capacity;// 遍歷哈希桶的鏈表,判斷 key 是否存在KeyValueNode *curr = map->buckets[idx];while (curr != NULL) {if (strcmp(key, curr->key) == 0) {// 找到目標鍵值對return curr->val;}curr = curr->next;} // curr == NULL// 沒找到目標鍵值對return NULL;
}// 刪除某個鍵值對
bool hashmap_remove(DynamicHashMap *map, KeyType key) {// 計算key的哈希值,從而確定哈希桶int idx = hash(key, strlen(key), map->hash_seed) % map->capacity;// 初始化兩個指針,一個指向鏈表當前結點,一個指向當前結點的前驅KeyValueNode *prev = NULL;KeyValueNode *curr = map->buckets[idx];while (curr != NULL) {if (strcmp(key, curr->key) == 0) {// 找到了要刪除的節點if (prev == NULL) {// 刪除的是哈希桶的第一個節點,于是更新頭指針map->buckets[idx] = curr->next;}else {// 刪除的是哈希桶中的非第一個節點,只需要讓當前結點的前驅結點指向當前結點的后繼prev->next = curr->next;}free(curr);map->size--;return true;}// 繼續遍歷鏈表prev = curr;curr = curr->next;}// 沒找到指定key的節點return false;
}

?

擴展:利用哈希表判斷單鏈表有環

頭文件

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>#define CAPACITY 10  // 哈希表的底層數組長度是10typedef struct node {int data;struct node *next;
}Node;  // 哈希表當中存儲的鏈表結點類型// 此哈希表只存儲鍵,不存儲value
// key值存儲鏈表結點的指針
typedef Node *KeyType;// 鍵值對結點,此時無需存儲值了
typedef struct node_s {KeyType key;    // 鍵struct node_s *next;
} HashNode; // 鍵值對結點類型typedef struct {HashNode *buckets[CAPACITY];uint32_t hash_seed;
} HashMap;    // 哈希表結構體類型// 創建一個固定容量的哈希表
HashMap *hashmap_create();
// 銷毀哈希表
void hashmap_destroy(HashMap *map);/*嘗試將鏈表結點的指針(地址)插入哈希表若發現結點已存入哈希表, 則函數返回true若結點未存入, 則將結點地址存入哈希表并返回false
*/
bool hashmap_put(HashMap *map, KeyType key);

該哈希表的實現代碼如下所示:

#include "hash_map.h"/* murmur_hash2 */
static uint32_t hash(const void *key, int len, uint32_t seed) {const uint32_t m = 0x5bd1e995;const int r = 24;uint32_t h = seed ^ len;const unsigned char *data = (const unsigned char *)key;while (len >= 4) {uint32_t k = *(uint32_t *)data;k *= m;k ^= k >> r;k *= m;h *= m;h ^= k;data += 4;len -= 4;}switch (len) {case 3: h ^= data[2] << 16;case 2: h ^= data[1] << 8;case 1: h ^= data[0];h *= m;};h ^= h >> 13;h *= m;h ^= h >> 15;return h;
}// 創建一個固定容量的哈希表
HashMap *hashmap_create() {HashMap *map = calloc(1, sizeof(HashMap));if (map == NULL) {printf("error: calloc failed in hashmap_create.\n");return NULL;}map->hash_seed = time(NULL);return map;
}// 銷毀哈希表
void hashmap_destroy(HashMap *map) {// 遍歷每一個哈希桶(也就是遍歷數組的每一個元素),逐一銷毀鏈表結點,最后銷毀結構體自身for (int i = 0; i < CAPACITY; i++) {HashNode *curr = map->buckets[i];while (curr != NULL) {HashNode *tmp = curr->next;free(curr);curr = tmp;}}free(map);
}/*該函數會將鏈表結點的地址作為一個結點key值,存入哈希表當中在存入的過程中,如果發現key值重復,說明有環,直接返回true如果key值不重復,那就將key結點正常存入哈希表,并且返回false
*/
bool hashmap_put(HashMap *map, KeyType key) {// 1.根據key這個結點地址數據來計算哈希值,確定哈希桶的位置int idx = hash(key, sizeof(KeyType), map->hash_seed) % CAPACITY;// 2.遍歷哈希桶,確定這個結點地址是否已經出現HashNode *curr = map->buckets[idx];while (curr != NULL) {if (key == curr->key) {// 當前結點已經重復出現了,說明有環return true;}curr = curr->next;}// 3.key是不存在的,于是新增這個結點HashNode *new_node = malloc(sizeof(HashNode));if (new_node == NULL) {printf("error: malloc failed in hashmap_put.\n");exit(-1);}new_node->key = key;    // 由于key是Node結點指針類型,是地址,所以可以直接用=賦值// 4.執行鏈表的頭插法,將新結點鏈接到鏈表中new_node->next = map->buckets[idx];map->buckets[idx] = new_node;return false;   // 表示當前結點還沒有重復,所以插入哈希表成功了
}
// 利用哈希表來判斷單鏈表有環
bool has_circle(Node *head) {// 1.創建一個哈希表HashMap *map = hashmap_create();// 2.遍歷整條單鏈表,并且將每一個結點的地址存入哈希表Node *curr = head;while (curr != NULL) {if (hashmap_put(map, curr)) {// 已經存儲了重復結點,有環hashmap_destroy(map);return true;}curr = curr->next;}// 如果while循環能夠結束,且能夠執行到這里,說明鏈表沒環hashmap_destroy(map);return false;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/80878.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/80878.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/80878.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【一次成功!】Ubuntu22.04安裝cartographer

之前在ubuntu20.04上成功安裝cartographer&#xff0c;但是翻遍全網都沒找到官方的22.04安裝教程&#xff0c;然后找到小魚的&#xff0c;試了一下&#xff0c;一次成功&#xff0c;連接如下&#xff1a; gd2l-ros2/docs/humble/chapt10/get_started/2.Carto介紹及安裝.md at …

【WPF】Opacity 屬性的使用

在WPF&#xff08;Windows Presentation Foundation&#xff09;中&#xff0c;Opacity 屬性是定義一個元素透明度的屬性&#xff0c;其值范圍是從 0.0&#xff08;完全透明&#xff09;到 1.0&#xff08;完全不透明&#xff09;。由于 Opacity 是在 UIElement 類中定義的&…

8天Python從入門到精通【itheima】-6~10

目錄 7節-開發出第一個Python程序: 1.在cmd窗口寫下第一個最簡單的程序:Hello World!!! 9節: 1.如何卸載python: 2.報錯:不是可運行的程序 ?編輯 3.報錯:無法初始化設備PRN: 4.報錯:語法錯誤——非法的字符 10節-python解釋器: 1.python解釋器的原理: 2.解…

Mac 3大好用的復制粘貼管理工具對比

剪貼板管理器是查看復制粘貼歷史記錄的工具&#xff0c;幾乎是每個蘋果電腦用戶必備工具。市面上的工具很多&#xff0c;我結合了功能豐富、設計簡潔、交互便利整理了目前3款頭部剪貼板應用 Paste、PasteNow、PasteMe。 Paste 優勢&#xff1a;老牌剪切板應用&#xff0c;功能…

2025年全國青少年信息素養大賽初賽模擬測試網站崩了的原因及應對比賽流程

2025年全國青少年信息素養大賽初賽模擬測試昨天開始&#xff0c;由于同一時間涌入太多的人&#xff0c;導致網站的服務器奔了&#xff0c;出現了各種狀況&#xff0c;導致很多人沒有模擬上&#xff0c;大家今天可以刷新或者提前打開網頁。 有的是一直“轉圈圈”&#xff0c;有的…

02 | 大模型微調 | 從0學習到實戰微調 | 從數學概率到千億參數大模型

一、導讀 作為非AI專業技術開發者&#xff08;我是小小爬蟲開發工程師&#x1f60b;&#xff09; 本系列文章將圍繞《大模型微調》進行學習&#xff08;也是我個人學習的筆記&#xff0c;所以會持續更新&#xff09;&#xff0c;最后以上手實操模型微調的目的。 &#xff08;…

十四、繼承與組合(Inheritance Composition)

十四、繼承與組合&#xff08;Inheritance & Composition&#xff09; 引言 C最引人注目的特性之一是代碼復用。組合&#xff1a;在新類中創建已有類的對象。繼承&#xff1a;將新類作為已有類的一個類型來創建。 14.1 組合的語法 Useful.h //C14:Useful.h #ifndef US…

2025年5月-信息系統項目管理師高級-軟考高項一般計算題

決策樹和期望貨幣值 加權算法 自制和外購分析 溝通渠道 三點估算PERT 當其他條件一樣時&#xff0c;npv越大越好

OpenJDK 17 中線程啟動的完整流程用C++ 源碼詳解

1. 線程創建入口&#xff08;JNI 層&#xff09; 當 Java 層調用 Thread.start() 時&#xff0c;JVM 通過 JNI 進入 JVM_StartThread 函數&#xff1a; JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))// 1. 檢查線程狀態&#xff0c;防止重復啟動if (java_…

Spring MVC參數傳遞

本內容采用最新SpringBoot3框架版本,視頻觀看地址:B站視頻播放 1. Postman基礎 Postman是一個接口測試工具,Postman相當于一個客戶端,可以模擬用戶發起的各類HTTP請求,將請求數據發送至服務端,獲取對應的響應結果。 2. Spring MVC相關注解 3. Spring MVC參數傳遞 Spri…

Python面向對象編程(OOP)深度解析:從封裝到繼承的多維度實踐

引言 面向對象編程(Object-Oriented Programming, OOP)是Python開發中的核心范式&#xff0c;其三大特性——??封裝、繼承、多態??——為構建模塊化、可維護的代碼提供了堅實基礎。本文將通過代碼實例與理論結合的方式&#xff0c;系統解析Python OOP的實現機制與高級特性…

0.66kV0.69kV接地電阻柜常規配置單

0.66kV/0.69kV接地電阻柜是變壓器中性點接地電阻柜中的特殊存在&#xff0c;主要應用于低壓柴油發電機組220V、火力發電廠380V、煤炭企業660V/690V等電力系統或電力用戶1000V的低壓系統中。 我們來看看0.66kV0.69kV接地電阻柜配置單&#xff1a; 配置特點如下&#xff1a; 1…

矩陣短劇系統:如何用1個后臺管理100+小程序?深度解析多端綁定技術

短劇行業效率革命&#xff01;一套系統實現多平臺內容分發、數據統管與流量聚合 在短劇行業爆發式增長的今天&#xff0c;內容方和運營者面臨兩大核心痛點&#xff1a;多平臺運營成本高與流量分散難聚合。傳統模式下&#xff0c;每個小程序需獨立開發后臺&#xff0c;導致人力…

CSS可以繼承的樣式匯總

CSS可以繼承的樣式匯總 在CSS中&#xff0c;以下是一些常見的可繼承樣式屬性&#xff1a; 字體屬性&#xff1a;包括 font-family &#xff08;字體系列&#xff09;、 font-size &#xff08;字體大小&#xff09;、 font-weight &#xff08;字體粗細&#xff09;、 font-sty…

BFS算法篇——打開智慧之門,BFS算法在拓撲排序中的詩意探索(上)

文章目錄 引言一、拓撲排序的背景二、BFS算法解決拓撲排序三、應用場景四、代碼實現五、代碼解釋六、總結 引言 在這浩瀚如海的算法世界中&#xff0c;有一扇門&#xff0c;開啟后通向了有序的領域。它便是拓撲排序&#xff0c;這個問題的解決方法猶如一場深刻的哲學思考&#…

【Qt開發】信號與槽

目錄 1&#xff0c;信號與槽的介紹 2&#xff0c;信號與槽的運用 3&#xff0c;自定義信號 1&#xff0c;信號與槽的介紹 在Qt框架中&#xff0c;信號與槽機制是一種用于對象間通信的強大工具。它是在Qt中實現事件處理和回調函數的主要方法。 信號&#xff1a;窗口中&#x…

數據庫基礎:概念、原理與實戰示例

在當今信息時代&#xff0c;數據已經成為企業和個人的核心資產。無論是社交媒體、電子商務、金融交易&#xff0c;還是物聯網設備&#xff0c;幾乎所有的現代應用都依賴于高效的數據存儲和管理。數據庫&#xff08;Database&#xff09;作為數據管理的核心技術&#xff0c;幫助…

前端-HTML基本概念

目錄 什么是HTML 常用的瀏覽器引擎是什么&#xff1f; 常見的HTML實體字符 HTML注釋 HTML語義化是什么&#xff1f;為什么要語義化&#xff1f;一定要語義化嗎&#xff1f; 連續空格如何渲染&#xff1f; 聲明文檔類型 哪些字符集編碼支持簡體中文&#xff1f; 如何解…

Linux進程信號處理(26)

文章目錄 前言一、信號的處理時機處理情況“合適”的時機 二、用戶態與內核態概念重談進程地址空間信號的處理過程 三、信號的捕捉內核如何實現信號的捕捉&#xff1f;sigaction 四、信號部分小結五、可重入函數六、volatile七、SIGCHLD 信號總結 前言 這篇就是我們關于信號的最…

C++ 字符格式化輸出

文章目錄 一、簡介二、實現代碼三、實現效果 一、簡介 這里使用std標準庫簡單實現一個字符格式化輸出&#xff0c;方便后續的使用&#xff0c;它有點類似Qt中的QString操作。 二、實現代碼 FMTString.hpp #pragma once#include <cmath> #include <cstdio> #include…