C++哈希(个人笔记)

C++哈希

    • 1.unordered_mapd
      • 1.1unordered_map的构造函数
      • 1.2unorder_map的容量
      • 1.3unordered_map的迭代器
      • 1.4unordered_map的元素访问
      • 1.5unorder_map的查找
      • 1.6unordered_map的修改操作
      • 1.7unordered_map的桶操作
    • 2.unordered_set
    • 3.unordered_set和unordered_set的笔试题
    • 4.哈希
      • 4.1哈希概念
      • 4.2哈希冲突
      • 4.3哈希函数
      • 4.4哈希冲突解决
        • 4.4.1闭散列
          • 4.4.1.1线性探测的实现
        • 4.4.2开散列
          • 4.4.2.1开散列的实现
    • 4.unordered_map和unordered_set模拟实现
      • 4.1哈希表的改造
      • 4.2unordered_set模拟实现
      • 4.3unordered_map模拟实现
    • 5.位图
      • 5.1位图的实现
      • 5.2布隆过滤器
        • 5.2.1布隆过滤器的实现


1.unordered_mapd

C++unorder_map官方文档

1.1unordered_map的构造函数

函数声明功能介绍
unordered_map构造不同格式的unordered_map对象

1.2unorder_map的容量

函数声明功能介绍
bool empty() const检测unordered_map是否为空
size_t size() const获取unordered_map的有效元素个数

1.3unordered_map的迭代器

函数声明功能介绍
begin返回unordered_map第一个元素的迭代器
end返回unordered_map最后一个元素下一个位置的迭代器
cbegin返回unordered_map第一个元素的const迭代器
cend返回unordered_map最后一个元素下一个位置的const迭代器

1.4unordered_map的元素访问

函数声明功能介绍
operator[]返回与key对应的value,没有则返回一个默认值

注意:
该函数中实际调用哈希桶的插入操作,用参数key与V()构造一个默认值往底层哈希桶中插入,如果key不在哈希桶中,插入成功,返回V(),插入失败,说明key已经在哈希桶中,将key对应的value返回。

1.5unorder_map的查找

函数声明功能介绍
iterator find(const K& key)返回key在哈希桶中的位置
size_t count(const K& key)返回哈希桶中关键码为key的键值对的个数

注意:unordered_map中key是不能重复的,因此count函数的返回值最大为1

1.6unordered_map的修改操作

函数声明功能介绍
insert向容器中插入键值对
erase删除容器中的键值对
void clear()清空容器中有效元素个数
void swap(unorder map&)交换两个容器中的元素

1.7unordered_map的桶操作

函数声明功能介绍
size_t bucket count()const返回哈希桶中桶的总个数
size_t bucket size(size_t n)const返回n号桶中有效元素的总个数
size_t bucket(const K& key)返回元素key所在的桶号

2.unordered_set

C++unordered_set官方文档
这里不在一 一列举

3.unordered_set和unordered_set的笔试题

在长度 2N 的数组中找出重复 N 次的元素
在这里插入图片描述

class Solution {
public:int repeatedNTimes(vector<int>& nums){unordered_map<int, int> found;for (int num : nums){found[num]++;}for (auto it = found.begin(); it != found.end(); ++it){if (it->second == nums.size() / 2){return it->first;}}return -1;}
};

两个数组的交集
在这里插入图片描述

class Solution {
public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2){set<int> s1(nums1.begin(),nums1.end());set<int> s2(nums2.begin(),nums2.end());auto it1=s1.begin();auto it2=s2.begin();vector<int> v;while(it1!=s1.end()&&it2!=s2.end()){if(*it1<*it2){++it1;}else if(*it1>*it2){++it2;}else{v.push_back(*it1);++it1;++it2;}}return v;}
};

两个数组的交集 II
在这里插入图片描述

class Solution {
public:vector<int> intersect(vector<int>& nums1, vector<int>& nums2){multiset<int> s1(nums1.begin(),nums1.end());multiset<int> s2(nums2.begin(),nums2.end());auto it1=s1.begin();auto it2=s2.begin();vector<int> v;while(it1!=s1.end()&&it2!=s2.end()){if(*it1<*it2){it1++;}else if(*it1>*it2){it2++;}else{v.push_back(*it1);it1++;it2++;}}return v;}
};

存在重复元素
在这里插入图片描述

class Solution {
public:bool containsDuplicate(vector<int>& nums){unordered_map<int,int> mp;for(int num:nums){mp[num]++;}auto it=mp.begin();while(it!=mp.end()){if(it->second>=2){return true;}++it;}return false;}
};

两句话中的不常见单词
在这里插入图片描述

class Solution {
public:vector<string> uncommonFromSentences(string s1, string s2){vector<string> v;unordered_map<string,int> mp;stringstream ss1(s1);string word;while(ss1>>word){mp[word]++;}stringstream ss2(s2);while(ss2>>word){mp[word]++;}for(auto& w:mp){if(w.second==1){v.push_back(w.first);}}return v;}
};

4.哈希

4.1哈希概念

通过某种函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一 一映射的关系,在查找时通过该函数可以很快找到该元素。

1.插入元素
根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放

2.搜索元素
对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键码相等,则找到了

哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表(Hash Table)(或者称散列表)

4.2哈希冲突

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

4.3哈希函数

哈希函数设计原则:

  1. 1.哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值域必须在0到m-1之间

  2. 哈希函数计算出来的地址能均匀分布在整个空间中

  3. 哈希函数应该比较简单
    常见的哈希函数

  4. 直接定址法–(常用)
    取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B
    优点:简单、均匀
    缺点:需要事先知道关键字的分布情况
    使用场景:适合查找比较小且连续的情况

  5. 除留余数法–(常用)
    设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,
    按照哈希函数:Hash(key) = key% p(p<=m),将关键码转换成哈希地址

4.4哈希冲突解决

解决哈希冲突两种常见的方法是:闭散列和开散列

4.4.1闭散列

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

线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。

1.插入

  1. 通过哈希函数获取待插入元素在哈希表中的位置
  2. 如果该位置中没有元素则直接插入新元素,如果该位置中有元素发生哈希冲突, 使用线性探测找到下一个空位置,插入新元素
    在这里插入图片描述
    2.删除
    采用闭散列处理哈希冲突时,不能物理删除哈希表中已有的元素,若直接删除元素会影响其他元素的搜索。比如删除元素4,如果直接删除掉,44查找起来可能会受影响。因此线性探测采用标记的伪删除法来删除一个元素。(也就是给位置标记状态)
// 哈希表每个空间给个标记
// EMPTY此位置空, EXIST此位置已经有元素, DELETE元素已经删除
enum State{EMPTY, EXIST, DELETE};
4.4.1.1线性探测的实现
enum Status
{EMPTY,EXIST,DELETE
};template<class K,class V>
struct HashData
{pair<K, V> _kv;Status _s;          //状态
};//HashFunc<int>
template<class K>
struct HashFunc
{size_t operator()(const K& Key){return (size_t)Key;}
};//HashFunc<string>
template<>
struct HashFunc<string>
{size_t operator()(const string& key){size_t hash = 0;for (auto e : key){hash *= 31;hash += e;}cout << key << ":" << hash << endl;return hash;}
};template<class K,class V,class Hash=HashFunc<K>>
class HashTable
{
public:HashTable(){_tables.resize(10);}bool Insert(const pair<K, V>& kv){if (Find(kv.first)){return false;}//负载因子0.7就扩容if (_n * 10 / _tables.size() == 7){size_t newSize = _tables.size() * 2;HashTable<K, V> newHT;newHT._tables.resize(newSize);for (size_t i = 0;i < _tables.size();i++){if (_tables[i]._s == EXIST){newHT.Insert(_tables[i]._kv);}}_tables.swap(newHT._tables);}Hash hf;size_t hashi = hf(kv.first) % _tables.size();while (_tables[hashi]._s == EXIST){hashi++;hashi %= _tables.size();}_tables[hashi]._kv = kv;_tables[hashi]._s = EXIST;++_n;return true;}HashData<K, V>* Find(const K& key){Hash hf;size_t hashi = hf(key) % _tables.size();while (_tables[hashi]._s != EMPTY){if (_tables[hashi]._s == EXIST && _tables[hashi]._kv.first == key){return &_tables[hashi];}hashi++;hashi %= _tables.size();}return nullptr;}bool Erase(const K& key){HashData<K, V>* ret = Find(key);if (ret){ret->_s = DELETE;--_n;return true;}else{return false;}}void Print(){for (size_t i = 0;i < _tables.size();i++){if (_tables[i]._s == EXIST){cout << "[" << i << "]->" << _tables[i]._kv.first << ":" << _tables[i]._kv.second << endl;}else if (_tables[i]._s == EMPTY){printf("[%d]->\n", i);}else{printf("[%d]->D\n", i);}}cout << endl;}private:vector<HashData<K,V>> _tables;size_t _n = 0;//存储的关键字的个数
};

线性探测优点:实现非常简单

线性探测缺点:一旦发生哈希冲突,所有的冲突连在一起,容易产生数据“堆积”,即:不同
关键码占据了可利用的空位置,使得寻找某关键码的位置需要许多次比较,导致搜索效率降
低。

4.4.2开散列

开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地
址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链
接起来,各链表的头结点存储在哈希表中。
在这里插入图片描述

4.4.2.1开散列的实现
//HashFunc<int>
template<class K>
struct HashFunc
{size_t operator()(const K& Key){return (size_t)Key;}
};//HashFunc<string>
template<>
struct HashFunc<string>
{size_t operator()(const string& key){size_t hash = 0;for (auto e : key){hash *= 31;hash += e;}cout << key << ":" << hash << endl;return hash;}
};template<class K, class V>
struct HashNode
{HashNode* _next;pair<K, V> _kv;HashNode(const pair<K, V>& kv):_kv(kv), _next(nullptr){}
};template<class K, class V,class Hash=HashFunc<K>>
class HashTable
{typedef HashNode<K, V> Node;
public:HashTable(){_tables.resize(10);}~HashTable(){for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){Node* next = cur->_next;delete cur;cur = next;}_tables[i] = nullptr;}}bool Insert(const pair<K, V>& kv){if (Find(kv.first))return false;Hash hf;// 负载因子最大到1if (_n == _tables.size()){vector<Node*> newTables;newTables.resize(_tables.size() * 2, nullptr);// 遍历旧表for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){Node* next = cur->_next;//挪动到映射的新表size_t hashi = hf(cur->_kv.first) % newTables.size();cur->_next = newTables[hashi];//标记newTables[hashi] = cur;cur = next;}_tables[i] = nullptr;}_tables.swap(newTables);}size_t hashi = hf(kv.first) % _tables.size();Node* newnode = new Node(kv);// 头插newnode->_next = _tables[hashi];_tables[hashi] = newnode;++_n;return true;}Node* Find(const K& key){Hash hf;size_t hashi = hf(key) % _tables.size();Node* cur = _tables[hashi];while (cur){if (cur->_kv.first == key){return cur;}cur = cur->_next;}return nullptr;}bool Erase(const K& key){Hash hf;size_t hashi = hf(key) % _tables.size();Node* prev = nullptr;Node* cur = _tables[hashi];while (cur){if (cur->_kv.first == key){if (prev == nullptr){_tables[hashi] = cur->_next;}else{prev->_next = cur->_next;}delete cur;return true;}prev = cur;cur = cur->_next;}return false;}void Some(){size_t bucketSize = 0;size_t maxBucketLen = 0;size_t sum = 0;double averageBucketLen = 0;for (size_t i = 0;i < _tables.size();i++){Node* cur = _tables[i];if (cur){++bucketSize;}size_t bucketLen = 0;while (cur){++bucketLen;cur = cur->_next;}sum += bucketLen;if (bucketLen > maxBucketLen){maxBucketLen = bucketLen;}}printf("all bucketSize:%d\n", _tables.size());printf("bucketSize:%d\n", bucketSize);printf("maxBucketLen:%d\n", maxBucketLen);printf("averageBucketLen:%lf\n\n", averageBucketLen);}private:vector<Node*> _tables;size_t _n = 0;
};

4.unordered_map和unordered_set模拟实现

4.1哈希表的改造

//HashFunc<int>
template<class K>
struct HashFunc
{size_t operator()(const K& Key){return (size_t)Key;}
};//HashFunc<string>
template<>
struct HashFunc<string>
{size_t operator()(const string& key){size_t hash = 0;for (auto e : key){hash *= 31;hash += e;}cout << key << ":" << hash << endl;return hash;}
};
namespace hash_bucket
{template<class T>struct HashNode{HashNode* _next;T _data;HashNode(const T& data):_data(data), _next(nullptr){}};// 前置声明template<class K, class T, class KeyOfT, class Hash>class HashTable;template<class K,class T,class Ref,class Ptr,class KeyOfT,class Hash>struct __HTIterator{typedef HashNode<T> Node;typedef __HTIterator<K, T, Ref, Ptr, KeyOfT, Hash> Self;Node* _node;const HashTable<K, T, KeyOfT, Hash>* _pht;size_t _hashi;__HTIterator(Node* node,HashTable<K,T,KeyOfT,Hash>* pht,size_t hashi):_node(node),_pht(pht),_hashi(hashi){}__HTIterator(Node* node, const HashTable<K, T, KeyOfT, Hash>* pht, size_t hashi):_node(node), _pht(pht), _hashi(hashi){}Self& operator++(){if (_node->_next){_node = _node->_next;}else{++_hashi;while (_hashi < _pht->_tables.size()){if (_pht->_tables[_hashi]){_node = _pht->_tables[_hashi];break;}++_hashi;}if (_hashi == _pht->_tables.size()){_node = nullptr;}}return *this;}Ref operator*(){return _node->_data;}Ptr operator->(){return &(_node->_data);}bool operator!=(const Self& s){return _node != s._node;}};//unordered_set->HashTable<K,K>//unordered_map->HashTable<K,pair<K,V>>template<class K, class T,class KeyOfT,class Hash>class HashTable{typedef HashNode<T> Node;template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>friend struct __HTIterator;public:typedef __HTIterator<K, T, T&, T*, KeyOfT, Hash> iterator;typedef __HTIterator<K, T, const T&, const T*, KeyOfT, Hash> const_iterator;iterator begin(){for (size_t i = 0;i < _tables.size();i++){if (_tables[i]){return iterator(_tables[i], this, i);}}return end();}iterator end(){return iterator(nullptr, this, -1);}const_iterator begin() const{for (size_t i = 0;i < _tables.size();i++){if (_tables[i]){return const_iterator(_tables[i], this, i);}}return end();}const_iterator end() const{return const_iterator(nullptr, this, -1);}HashTable(){_tables.resize(10);}~HashTable(){for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){Node* next = cur->_next;delete cur;cur = next;}_tables[i] = nullptr;}}pair<iterator,bool> Insert(const T& data){Hash hf;KeyOfT kot;iterator it = Find(kot(data));if (it != end()){return make_pair(it, false);}// 负载因子最大到1if (_n == _tables.size()){vector<Node*> newTables;newTables.resize(_tables.size() * 2, nullptr);// 遍历旧表for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){Node* next = cur->_next;//挪动到映射的新表size_t hashi = hf(kot(data)) % newTables.size();cur->_next = newTables[hashi];//标记newTables[hashi] = cur;cur = next;}_tables[i] = nullptr;}_tables.swap(newTables);}size_t hashi = hf(kot(data)) % _tables.size();Node* newnode = new Node(data);// 头插newnode->_next = _tables[hashi];_tables[hashi] = newnode;++_n;return make_pair(iterator(newnode,this,hashi),true);}iterator Find(const K& key){Hash hf;KeyOfT kot;size_t hashi = hf(key) % _tables.size();Node* cur = _tables[hashi];while (cur){if (kot(cur->_data) == key){return iterator(cur,this,hashi);}cur = cur->_next;}return end();}bool Erase(const K& key){Hash hf;KeyOfT kot;size_t hashi = hf(key) % _tables.size();Node* prev = nullptr;Node* cur = _tables[hashi];while (cur){if (kot(cur->_data) == key){if (prev == nullptr){_tables[hashi] = cur->_next;}else{prev->_next = cur->_next;}delete cur;return true;}prev = cur;cur = cur->_next;}return false;}void Some(){size_t bucketSize = 0;size_t maxBucketLen = 0;size_t sum = 0;double averageBucketLen = 0;for (size_t i = 0;i < _tables.size();i++){Node* cur = _tables[i];if (cur){++bucketSize;}size_t bucketLen = 0;while (cur){++bucketLen;cur = cur->_next;}sum += bucketLen;if (bucketLen > maxBucketLen){maxBucketLen = bucketLen;}}averageBucketLen = (double)sum / (double)bucketSize;printf("all bucketSize:%d\n", _tables.size());printf("bucketSize:%d\n", bucketSize);printf("maxBucketLen:%d\n", maxBucketLen);printf("averageBucketLen:%lf\n\n", averageBucketLen);}private:vector<Node*> _tables;size_t _n = 0;};
}

4.2unordered_set模拟实现

#pragma once
#include"HashTable.h"namespace ljh
{template<class K, class Hash = HashFunc<K>>class unordered_set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename hash_bucket::HashTable<K, K, SetKeyOfT, Hash>::const_iterator iterator;typedef typename hash_bucket::HashTable<K, K, SetKeyOfT, Hash>::const_iterator const_iterator;/*iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}*/const_iterator begin() const{return _ht.begin();}const_iterator end() const{return _ht.end();}pair<const_iterator, bool> insert(const K& key){auto ret = _ht.Insert(key);return pair<const_iterator, bool>(const_iterator(ret.first._node, ret.first._pht, ret.first._hashi), ret.second);}iterator find(const K& key){return _ht.Find(key);}bool erase(const K& key){return _ht.Erase(key);}private:hash_bucket::HashTable<K, K, SetKeyOfT, Hash> _ht;};
}

4.3unordered_map模拟实现

#pragma once
#include"HashTable.h"
namespace ljh
{template<class K,class V,class Hash=HashFunc<K>>class unordered_map{struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};public:typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::iterator iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}pair<iterator, bool> insert(const pair<K, V>& kv){return _ht.Insert(kv);}V& operator[](const K& key){pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));return ret.first->second;}const V& operator[](const K& key) const{pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));return ret.first->second;}iterator find(const K& key){return _ht.Find(key);}bool erase(const K& key){return _ht.Erase(key);}private:hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;};
}

5.位图

给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。
解决方案:
1:暴力遍历:时间复杂度O(N)
2.快排(O(NlogN))+二分查找(logN)
3.位图
数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,可以使用一个二进制比特位来代表数据是否存在,如果二进制比特位为1,代表存在,为0代表不存在。

5.1位图的实现

//N为需要多少比特位
template<size_t N>
class bitset
{
public:bitset(){_bits.resize(N / 32 + 1);}void set(size_t x){size_t i = x / 32;size_t j = x % 32;_bits[i] |= (1 << j);}void reset(size_t x){size_t i = x / 32;size_t j = x % 32;_bits[i] &= ~(1 << j);}bool test(size_t x){size_t i = x / 32;size_t j = x % 32;return _bits[i] & (1 << j);}private:vector<int> _bits;
};template<size_t N>
class twobitset
{
public:void set(size_t x){//00->01//01->10//10->11//11->不变if (_bs1.test(x) == false && _bs2.test(x) == false){_bs2.set(x);}else if (_bs1.test(x) == false && _bs2.test(x) == true){_bs1.set(x);_bs2.reset(x);}else if (_bs1.test(x) == true && _bs2.test(x) == false){_bs2.set(x);}}void Print(){for (size_t i = 0;i < N;i++){if (_bs1.test(i) == false && _bs2.test(i) == true){cout << "1->" << i << endl;}else if (_bs1.test(i) == true && _bs2.test(i) == false){cout << "2->" << i << endl;}}cout << endl;}private:bitset<N> _bs1;bitset<N> _bs2;
};

5.2布隆过滤器

具体实现思想:用多个哈希函数,将一个数据映射到位图结构中
作用:某样东西一定不存在或者可能存在
在这里插入图片描述
在这里插入图片描述

5.2.1布隆过滤器的实现
#include<string>
#include<iostream>
#include<vector>
using namespace std;
#include"bitset.h"
struct BKDRHash
{size_t operator()(const string& key){// BKDRsize_t hash = 0;for (auto e : key){hash *= 31;hash += e;}return hash;}
};struct APHash
{size_t operator()(const string& key){size_t hash = 0;for (size_t i = 0; i < key.size(); i++){char ch = key[i];if ((i & 1) == 0){hash ^= ((hash << 7) ^ ch ^ (hash >> 3));}else{hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));}}return hash;}
};struct DJBHash
{size_t operator()(const string& key){size_t hash = 5381;for (auto ch : key){hash += (hash << 5) + ch;}return hash;}
};template<size_t N,class K = string,class HashFunc1 = BKDRHash,class HashFunc2 = APHash,class HashFunc3 = DJBHash>
class BloomFilter
{
public:void Set(const K& key){size_t hash1 = HashFunc1()(key) % N;size_t hash2 = HashFunc2()(key) % N;size_t hash3 = HashFunc3()(key) % N;_bs.set(hash1);_bs.set(hash2);_bs.set(hash3);}//void Reset(const K& key);一般不支持删除bool Test(const K& key){//判断不存在是准确的,其他的都是存在偏差的size_t hash1 = HashFunc1()(key) % N;if (_bs.test(hash1) == false){return false;}size_t hash2 = HashFunc2()(key) % N;if (_bs.test(hash2) == false){return false;}size_t hash3 = HashFunc3()(key) % N;if (_bs.test(hash3) == false){return false;}// 存在误判的return true;}private:ljh::bitset<N> _bs;
};

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

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

相关文章

应急救灾北斗终端手机应用方案

在应对自然灾害和紧急救援的严峻挑战中&#xff0c;技术的力量从未如此重要。为了保障救援人员能够迅速、准确地响应灾情&#xff0c;提供及时有效的救助&#xff0c;顶坚应急救灾北斗终端手机应用应运而生。这款应用依托北斗卫星导航系统的高精度定位与通信功能&#xff0c;不…

图扑智慧农业——生态鱼塘数字孪生监控

智慧农业园作为新型农业经营模式&#xff0c;正在以其高效、环保、可持续的特点受到广泛关注。智慧鱼塘作为智慧农业中一项关键技术&#xff0c;结合物联网、人工智能、云计算等技术&#xff0c;实现对新型养殖模式的实时监控、优化与管理。 效果展示 图扑软件应用自研 HT for…

巩固学习7

正则表达式 就是用来找到符合模式的字符串&#xff0c;这些模式包括&#xff1a;是什么字符&#xff0c;重复多少次&#xff0c;在什么位置&#xff0c;有哪些额外的约束 找某个字符串 import re text身高:178 体重:168 学号:123456 密码:9527 #在Python中&#xff0c;r前缀用…

BFD双向转发检测

BFD概述 Bidirectional Forwarding Detection &#xff1a;双向转发检测 BFD技术背景 现网中存在的问题 不能快速有效的发现网络设备或链路中出现的故障不能以毫秒级的速度发现网络中的问题协议自身的报文检测机制一般都大于1秒 解决方案&#xff1a; 需要一种专门用于快…

【脚本】使用脚本备份docker中部署的mysql数据库

v1版本明文密码方式&#xff1a; #!/bin/bash# 定义 MySQL 容器名称和数据库信息 container_name"mysql_container" db_user"root" db_password"your_password"# 定义要备份的数据库列表 databases("database1" "database2"…

Outlook的IMAP服务器怎么填写?填写步骤?

Outlook的IMAP服务器如何使用&#xff1f;服务器地址怎么查找&#xff1f; 当我们在Outlook中设置新的电子邮件账户时&#xff0c;经常会遇到一个问题&#xff1a;Outlook的IMAP服务器怎么填写呢&#xff1f;接下来&#xff0c;AokSend将详细解答这个问题&#xff0c;并帮助大…

400元已到账,成交从认真开始

昨天发了一个值班的需求&#xff0c;收到了很多好友的响应&#xff0c;这里非常感谢关注创业程序员卡酷的老朋友、新朋友。今天分享一下&#xff1a;拓展、合作、成交 现在不管是IT行业还是其他行业&#xff0c;大环境可谓一片惨淡&#xff0c;35乃至30找不到工作的失业人员一抓…

深度论证-高速走线控制100欧姆阻抗一定是最好的选择吗?

高速先生成员--黄刚 对于高速差分信号到底需要控制多少欧姆的阻抗&#xff0c;高速先生相信大部分工程师首先都会看下例如信号的协议文档或者芯片的文档&#xff0c;看看里面有没有推荐的控制阻抗值。例如像PCIE信号&#xff0c;在4.0之后的阻抗会明确要求按照85欧姆来控制&…

4.Jmeter阶梯加压Stepping Thread Group

1. 先去Jmeter下载地址下载PluginsManager&#xff0c;放置在Jmeter的lib/ext 目录下 &#xff0c;重启Jmeter 2. 在插件管理器查找并安装jpgc - Standard Set,重启Jmeter 3.右键测试计划->添加->Threads(Users)->jpgc - Stepping Thread Group 然后设置阶梯加压参数…

贷款没有逾期,征信没问题,为什么大数据信用评分低呢?

大数据信用在金融贷前风控越来越重要&#xff0c;这让不少人开始关心自己的大数据信用了&#xff0c;其中就有不少人有疑问&#xff0c;那就是自己网贷没有逾期&#xff0c;征信记录也还可以&#xff0c;为什么大数据信用评分低呢?这个问题也是不少人都想知道的&#xff0c;小…

鸿蒙开发之跨设备文件访问

分布式文件系统为应用提供了跨设备文件访问的能力&#xff0c;开发者在多个设备安装同一应用时&#xff0c;通过基础文件接口&#xff0c;可跨设备读写其他设备该应用分布式文件路径&#xff08;/data/storage/el2/distributedfiles/&#xff09;下的文件。 例如&#xff1a;多…

软件测试之【软件测试初级工程师技能点全解】

读者大大们好呀&#xff01;&#xff01;!☀️☀️☀️ &#x1f525; 欢迎来到我的博客 &#x1f440;期待大大的关注哦❗️❗️❗️ &#x1f680;欢迎收看我的主页文章➡️寻至善的主页 文章目录 &#x1f525;前言&#x1f680;初级测试工程师技能点&#x1f449;测试理论基…

Shell脚本之数组

数组 数组中可以存放多个值&#xff08;bash 只支持一维数组&#xff09;数组元素的索引从0开始数组在括号内指定数组的值&#xff0c;每个值仅能用空格分割 其中&#xff1a;30为索引0 20为索引1 10为索引2 60为索引3 以此类推&#xff0c;不过注意索引是从0开始的 如果数组中…

vue布局设置——使用 el-drawer 打造个性化 Admin 后台布局设置

在前端开发中&#xff0c;我们常常需要为 admin 后台构建灵活且个性化的布局设置。今天&#xff0c;我要分享的是如何利用 el-drawer 来实现这样一个有趣的功能。 首先&#xff0c;我们来看一下主要的设置参数&#xff1a; 1. theme: 用于定义主题&#xff0c;可以根据需求切换…

【已解决】attributeerror: ‘FreeTypeFont‘ object has no attribute ‘getsize‘

&#x1f60e; 作者介绍&#xff1a;我是程序员行者孙&#xff0c;一个热爱分享技术的制能工人。计算机本硕&#xff0c;人工制能研究生。公众号&#xff1a;AI Sun&#xff0c;视频号&#xff1a;AI-行者Sun &#x1f388; 本文专栏&#xff1a;本文收录于《AI实战中的各种bug…

ctfshow web入门 phpCVE web312web314

web311 web312 IMAP协议&#xff08;因特网消息访问协议&#xff09;它的主要作用是邮件客户端可以通过这种协议从邮件服务器上获取邮件的信息&#xff0c;下载邮件等。它运行在TCP/IP协议之上&#xff0c;使用的端口是143&#xff0c;在php中调用的是imap_open函数来实现功能…

学习java

在实验室看见这本书&#xff0c;无聊看了下&#xff0c;写出了第一个java代码 成功下载了eclipse并且汉化。 写了自己的第一个java程序&#xff1a; package ttttt;public class ttttt {public static void main(String[] args) {System.out.println("hello world")…

Unreal自定义字体中,缺少字怎么办,有没有字表?

关键词&#xff1a;自定义字体&#xff0c;字表&#xff0c;编码&#xff0c;UTF-8,4E00-9FFF,4E00-9FA5,字符查重&#xff0c;字符唯一&#xff0c; 问题&#xff1a; 游戏中经常要自定义字体&#xff0c; 自定义字体往往要做离线字库 offline fonts 离线字库 离不开字符表。…

调味品企业的销量增长秘诀:五丰黎红引领大厨革新之路

随着时代的发展和消费升级&#xff0c;调味品行业的竞争愈发激烈&#xff0c;在此大环境之下&#xff0c;企业需要不断寻找创新的突破点来实现销量的增长。众所周知&#xff0c;调味品行业的销售渠道主要有餐饮、家庭消费和食品加工&#xff0c;按销售额的占比约为6&#xff1a…

[JAVASE] 类和对象(二)(续篇)

目录 一. static 修饰成员方法 1.1 基本使用 1.2 注意事项 (重点) 1.2.1 1.2.1 二. 代码块 2.1 代码块的分类及使用 2.1.1 静态代码块 2.1.2 实例代码块 2.1.3 普通代码块 2.2 代码块的执行顺序 三. 对象的打印 3.1 打印对象的引用 3.2 重写 toString 方法 四. 总结 一…