【C++】哈希表的模拟实现及 unordered_set 和 unorderded_map 的封装

在这里插入图片描述

目录

  • 前言
  • 一、哈希表的模拟实现
    • 1.1 哈希表的改造
      • 1.1.1 模板参数列表的改造
      • 1.1.2 增加迭代器操作
    • 1.2 哈希表的模拟实现
      • 1.2.1 哈希表中仿函数的实现
      • 1.2.2 哈希表中节点类的实现
      • 1.2.3 哈希表中迭代器类的实现
      • 1.2.4 哈希表中构造函数、析构函数和 Clear() 函数的实现
      • 1.2.5 哈希表中Swap 和 Size 函数的实现
      • 1.2.6 哈希表中 begin 和 end 函数的实现
      • 1.2.7 哈希表中 Find 函数的实现
      • 1.2.8 哈希表中 Insert 和 Erase 函数的实现
      • 1.2.9 哈希表的整体实现
  • 二、unordered_set的实现及测试
  • 三、unordered_map的实现及测试
  • 结尾

前言

上一篇文章中讲到了哈希的概念和STL中关于哈希容器的使用,并且在后面对开散列进行了模拟实现,那么在这一篇文章中在开散列的基础上进行改造成哈希表,并且在哈希表的基础上封装 unordered_set 和 unordered_map。


一、哈希表的模拟实现

1.1 哈希表的改造

1.1.1 模板参数列表的改造

K:表示关键码类型

T:不同容器V的类型不同,如果是unordered_map,K代表一个键值对,如果是unordered_set,T 为 K。

KOfT: 因为V的类型不同,通过value取key的方式就不同,详细见
unordered_map/set的实现

HF: 哈希函数仿函数对象类型,哈希函数使用除留余数法,需要将Key转换为整形数字才能取模

template<class K, class T ,  class KOfT , class HF>
class hash_table;

1.1.2 增加迭代器操作

// 前置声明,否则后面的__HTIterator找不到hash_tabletemplate<class K, class T, class KOfT, class HF>class hash_table;template<class K, class T , class Ref, class Ptr, class KOfT, class HF>struct __HTIterator{typedef HashNode<T> Node;typedef __HTIterator<K, T, Ref , Ptr , KOfT, HF> self;// 成员变量Node* _node;// 由于const迭代器中const修饰this// 所以这里需要加const,否则会导致权限放大// 编译无法通过的情况const hash_table<K, T, KOfT, HF>* _pht;// size_t hashi;// 构造函数__HTIterator(Node* node, hash_table<K, T, KOfT, HF>* pht , size_t i):_node(node),_pht(pht),hashi(i){}// 构造函数__HTIterator(Node* node, const hash_table<K, T, KOfT, HF>* pht, size_t i):_node(node), _pht(pht), hashi(i){}self& operator++(){if (_node->_next){// 若当前桶其他节点没有走完// 那么继续走下一个节点_node = _node->_next;}else{// 若当前桶的所有节点都已经走完// 那么继续向下一个桶不为空的桶走hashi++;while (hashi < _pht->_table.size()){if (_pht->_table[hashi]){_node = _pht->_table[hashi];break;}hashi++;}if (hashi == _pht->_table.size())_node = nullptr;}return *this;}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator!=(const self& s){return _node != s._node;}};

1.2 哈希表的模拟实现

1.2.1 哈希表中仿函数的实现

若存储key的类型不是整形时,需要将其转化为整数,整形不需要处理,日常中我们最常用到的类型是string,那么这里就写一个string转化为整形的版本。

// 整数类型
template<class K>
struct HashFunc
{size_t operator()(const K& key){return (size_t)key;}
};// 特化
template<>
struct HashFunc<string>
{size_t operator()(const string& s){size_t sum = 0;for (size_t i = 0; i < s.size(); i++){sum = sum * 31 + s[i];}return sum;}
};

1.2.2 哈希表中节点类的实现

namespace hash_bucket
{template<class T>struct HashNode{HashNode* _next;T _data;HashNode(const T& data):_data(data), _next(nullptr){}};}

1.2.3 哈希表中迭代器类的实现

namespace hash_bucket
{// 前置声明,否则后面的__HTIterator找不到hash_tabletemplate<class K, class T, class KOfT, class HF>class hash_table;template<class K, class T, class Ref, class Ptr, class KOfT, class HF>struct __HTIterator{typedef HashNode<T> Node;typedef __HTIterator<K, T, Ref, Ptr, KOfT, HF> self;// 成员变量Node* _node;// 由于const迭代器中const修饰this// 所以这里需要加const,否则会导致权限放大// 编译无法通过的情况const hash_table<K, T, KOfT, HF>* _pht;// size_t hashi;// 构造函数__HTIterator(Node* node, hash_table<K, T, KOfT, HF>* pht, size_t i):_node(node), _pht(pht), hashi(i){}// 构造函数__HTIterator(Node* node, const hash_table<K, T, KOfT, HF>* pht, size_t i):_node(node), _pht(pht), hashi(i){}self& operator++(){if (_node->_next){// 若当前桶其他节点没有走完// 那么继续走下一个节点_node = _node->_next;}else{// 若当前桶的所有节点都已经走完// 那么继续向下一个桶不为空的桶走hashi++;while (hashi < _pht->_table.size()){if (_pht->_table[hashi]){_node = _pht->_table[hashi];break;}hashi++;}if (hashi == _pht->_table.size())_node = nullptr;}return *this;}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator!=(const self& s){return _node != s._node;}};
}

1.2.4 哈希表中构造函数、析构函数和 Clear() 函数的实现

namespace hash_bucket
{template<class K, class T, class KOfT, class HF>class hash_table{public:typedef HashNode<T> Node;public:// 构造函数hash_table(int n = 10):_table(vector<Node*>(n)), _n(0){}// 析构函数~hash_table(){Clear();}void Clear(){for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[i];while (cur){Node* next = cur->_next;delete cur;cur = next;}_table[i] = nullptr;}}private:vector<Node*> _table;int _n;};
}

1.2.5 哈希表中Swap 和 Size 函数的实现

namespace hash_bucket
{template<class K, class T, class KOfT, class HF>class hash_table{public:size_t Size(){return _n;}void Swap(hash_table<K, T, KOfT, HF>& ht){_table.swap(ht._table);swap(_n, ht._n);}private:vector<Node*> _table;int _n;};
}

1.2.6 哈希表中 begin 和 end 函数的实现

namespace hash_bucket
{template<class K, class T, class KOfT, class HF>class hash_table{public:typedef HashNode<T> Node;typedef __HTIterator<K, T, T&, T*, KOfT, HF> iterator;typedef __HTIterator<K, T, const T&, const T*, KOfT, HF> const_iterator;// 将__HTIterator设置为hash_table的友元// 使__HTIterator可以访问hash_table的私有template<class K, class T, class Ref, class Ptr, class KOfT, class HF>friend struct __HTIterator;public:// 迭代器iterator begin(){for (size_t i = 0; i < _table.size(); i++){if (_table[i])return iterator(_table[i], this, i);}return end();}iterator end(){return iterator(nullptr, this, -1);}const_iterator begin()const{for (size_t i = 0; i < _table.size(); i++){if (_table[i])return const_iterator(_table[i], this, i);}return end();}const_iterator end()const{return const_iterator(nullptr, this, -1);}private:vector<Node*> _table;int _n;};
}

1.2.7 哈希表中 Find 函数的实现

namespace hash_bucket
{template<class K, class T, class KOfT, class HF>class hash_table{public:typedef HashNode<T> Node;typedef __HTIterator<K, T, T&, T*, KOfT, HF> iterator;typedef __HTIterator<K, T, const T&, const T*, KOfT, HF> const_iterator;// 将__HTIterator设置为hash_table的友元// 使__HTIterator可以访问hash_table的私有template<class K, class T, class Ref, class Ptr, class KOfT, class HF>friend struct __HTIterator;public:// 查找iterator Find(const K& key){HF hf;KOfT koft;int hashi = hf(key) % _table.size();Node* cur = _table[hashi];while (cur){if (koft(cur->_data) == key)return iterator(cur, this, hashi);cur = cur->_next;}// 找不到返回空return end();}private:vector<Node*> _table;int _n;};
}

1.2.8 哈希表中 Insert 和 Erase 函数的实现

namespace hash_bucket
{template<class K, class T, class KOfT, class HF>class hash_table{public:typedef HashNode<T> Node;typedef __HTIterator<K, T, T&, T*, KOfT, HF> iterator;typedef __HTIterator<K, T, const T&, const T*, KOfT, HF> const_iterator;// 将__HTIterator设置为hash_table的友元// 使__HTIterator可以访问hash_table的私有template<class K, class T, class Ref, class Ptr, class KOfT, class HF>friend struct __HTIterator;public:// 插入pair<iterator, bool> Insert(const T& data){HF hf;KOfT koft;iterator tmp = Find(koft(data));// 不允许有相同的值if (tmp != end())return make_pair(tmp, false);// 扩容if (_n == _table.size()){int newcapacity = 2 * _table.size();hash_table newtable(newcapacity);for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[i];while (cur){Node* next = cur->_next;int hashi = hf(koft(cur->_data)) % newcapacity;cur->_next = newtable._table[hashi];newtable._table[hashi] = cur;cur = next;}_table[i] = nullptr;}_table.swap(newtable._table);}// 头插 int hashi = hf(koft(data)) % _table.size();Node* newnode = new Node(data);newnode->_next = _table[hashi];_table[hashi] = newnode;_n++;return make_pair(iterator(newnode, this, hashi), true);}// 删除bool Erase(const K& key){Node* tmp = Find(key);// 找不到则删除失败if (tmp == nullptr)return false;HF hf;KOfT koft;int hashi = hf(key) % _table.size();Node* prev = nullptr;Node* cur = _table[hashi];while (cur){Node* next = cur->_next;if (koft(cur->_data) == key){if (prev == nullptr){_table[hashi] = next;}else{prev->_next = next;}_n--;delete cur;return true;}else{prev = cur;cur = next;}}return false;}private:vector<Node*> _table;int _n;};
}

1.2.9 哈希表的整体实现

#pragma once#include<iostream>
#include<string>
#include<vector>
#include<unordered_set>
#include<set>using namespace std;// 整数类型
template<class K>
struct HashFunc
{size_t operator()(const K& key){return (size_t)key;}
};// 特化
template<>
struct HashFunc<string>
{size_t operator()(const string& s){size_t sum = 0;for (size_t i = 0; i < s.size(); i++){sum = sum * 31 + s[i];}return sum;}
};namespace hash_bucket
{template<class T>struct HashNode{HashNode* _next;T _data;HashNode(const T& data):_data(data), _next(nullptr){}};// 前置声明,否则后面的__HTIterator找不到hash_tabletemplate<class K, class T, class KOfT, class HF>class hash_table;template<class K, class T , class Ref, class Ptr, class KOfT, class HF>struct __HTIterator{typedef HashNode<T> Node;typedef __HTIterator<K, T, Ref , Ptr , KOfT, HF> self;// 成员变量Node* _node;// 由于const迭代器中const修饰this// 所以这里需要加const,否则会导致权限放大// 编译无法通过的情况const hash_table<K, T, KOfT, HF>* _pht;// size_t hashi;// 构造函数__HTIterator(Node* node, hash_table<K, T, KOfT, HF>* pht , size_t i):_node(node),_pht(pht),hashi(i){}// 构造函数__HTIterator(Node* node, const hash_table<K, T, KOfT, HF>* pht, size_t i):_node(node), _pht(pht), hashi(i){}self& operator++(){if (_node->_next){// 若当前桶其他节点没有走完// 那么继续走下一个节点_node = _node->_next;}else{// 若当前桶的所有节点都已经走完// 那么继续向下一个桶不为空的桶走hashi++;while (hashi < _pht->_table.size()){if (_pht->_table[hashi]){_node = _pht->_table[hashi];break;}hashi++;}if (hashi == _pht->_table.size())_node = nullptr;}return *this;}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator!=(const self& s){return _node != s._node;}};template<class K, class T ,  class KOfT , class HF>class hash_table{public:typedef HashNode<T> Node;typedef __HTIterator<K, T, T& , T* ,KOfT, HF> iterator;typedef __HTIterator<K, T, const T&, const T*, KOfT, HF> const_iterator;// 将__HTIterator设置为hash_table的友元// 使__HTIterator可以访问hash_table的私有template<class K, class T, class Ref, class Ptr, class KOfT, class HF>friend struct __HTIterator;public:// 构造函数hash_table(int n = 10):_table(vector<Node*>(n)),_n(0){}// 析构函数~hash_table(){Clear();}void Clear(){for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[i];while (cur){Node* next = cur->_next;delete cur;cur = next;}_table[i] = nullptr;}}size_t Size(){return _n;}void Swap(hash_table<K,T,KOfT,HF>& ht){_table.swap(ht._table);swap(_n, ht._n);}// 迭代器iterator begin(){for (size_t i = 0; i < _table.size(); i++){if (_table[i])return iterator(_table[i], this, i);}return end();}iterator end(){return iterator(nullptr, this, -1);}const_iterator begin()const{for (size_t i = 0; i < _table.size(); i++){if (_table[i])return const_iterator(_table[i], this, i);}return end();}const_iterator end()const{return const_iterator(nullptr, this, -1);}// 插入pair<iterator,bool> Insert(const T& data){HF hf;KOfT koft;iterator tmp = Find(koft(data));// 不允许有相同的值if (tmp != end())return make_pair(tmp,false);// 扩容if (_n == _table.size()){int newcapacity = 2 * _table.size();hash_table newtable(newcapacity);for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[i];while (cur){Node* next = cur->_next;int hashi = hf(koft(cur->_data)) % newcapacity;cur->_next = newtable._table[hashi];newtable._table[hashi] = cur;cur = next;}_table[i] = nullptr;}_table.swap(newtable._table);}// 头插 int hashi = hf(koft(data)) % _table.size();Node* newnode = new Node(data);newnode->_next = _table[hashi];_table[hashi] = newnode;_n++;return make_pair(iterator(newnode,this,hashi),true);}// 删除bool Erase(const K& key){Node* tmp = Find(key);// 找不到则删除失败if (tmp == nullptr)return false;HF hf;KOfT koft;int hashi = hf(key) % _table.size();Node* prev = nullptr;Node* cur = _table[hashi];while (cur){Node* next = cur->_next;if (koft(cur->_data) == key){if (prev == nullptr){_table[hashi] = next;}else{prev->_next = next;}_n--;delete cur;return true;}else{prev = cur;cur = next;}}return false;}// 查找iterator Find(const K& key){HF hf;KOfT koft;int hashi = hf(key) % _table.size();Node* cur = _table[hashi];while (cur){if (koft(cur->_data) == key)return iterator(cur,this,hashi);cur = cur->_next;}// 找不到返回空return end();}void Some(){size_t bucketSize = 0;size_t maxBucketLen = 0;size_t sum = 0;double averageBucketLen = 0;for (size_t i = 0; i < _table.size(); i++){Node* cur = _table[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", _table.size());printf("bucketSize:%d\n", bucketSize);printf("maxBucketLen:%d\n", maxBucketLen);printf("averageBucketLen:%lf\n\n", averageBucketLen);}private:vector<Node*> _table;int _n;public:void TestHT1(){hash_table<int, int> ht;int a[] = { 4,14,24,34,5,7,1 };for (auto e : a){ht.Insert(make_pair(e, e));}ht.Insert(make_pair(3, 3));ht.Insert(make_pair(3, 3));ht.Insert(make_pair(-3, -3));ht.Some();}void TestHT2(){string arr[] = { "香蕉", "甜瓜","苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };//HashTable<string, int, HashFuncString> ht;hash_table<string, int> ht;for (auto& e : arr){//auto ret = ht.Find(e);HashNode<string, int>* ret = ht.Find(e);if (ret){ret->_kv.second++;}else{ht.Insert(make_pair(e, 1));}}ht.Insert(make_pair("apple", 1));ht.Insert(make_pair("sort", 1));ht.Insert(make_pair("abc", 1));ht.Insert(make_pair("acb", 1));ht.Insert(make_pair("aad", 1));}void TestHT3(){const size_t N = 1000;unordered_set<int> us;set<int> s;hash_table<int, int> ht;vector<int> v;v.reserve(N);srand(time(0));for (size_t i = 0; i < N; ++i){//v.push_back(rand()); // N比较大时,重复值比较多v.push_back(rand() + i); // 重复值相对少//v.push_back(i); // 没有重复,有序}size_t begin1 = clock();for (auto e : v){s.insert(e);}size_t end1 = clock();cout << "set insert:" << end1 - begin1 << endl;size_t begin2 = clock();for (auto e : v){us.insert(e);}size_t end2 = clock();cout << "unordered_set insert:" << end2 - begin2 << endl;size_t begin3 = clock();for (auto e : v){ht.Insert(make_pair(e, e));}size_t end3 = clock();cout << "hash_table insert:" << end3 - begin3 << endl << endl;size_t begin4 = clock();for (auto e : v){s.find(e);}size_t end4 = clock();cout << "set find:" << end4 - begin4 << endl;size_t begin5 = clock();for (auto e : v){us.find(e);}size_t end5 = clock();cout << "unordered_set find:" << end5 - begin5 << endl;size_t begin6 = clock();for (auto e : v){ht.Find(e);}size_t end6 = clock();cout << "hash_table find:" << end6 - begin6 << endl << endl;cout << "插入数据个数:" << us.size() << endl << endl;ht.Some();size_t begin7 = clock();for (auto e : v){s.erase(e);}size_t end7 = clock();cout << "set erase:" << end7 - begin7 << endl;size_t begin8 = clock();for (auto e : v){us.erase(e);}size_t end8 = clock();cout << "unordered_set erase:" << end8 - begin8 << endl;size_t begin9 = clock();for (auto e : v){ht.Erase(e);}size_t end9 = clock();cout << "hash_table Erase:" << end9 - begin9 << endl << endl;}};}

二、unordered_set的实现及测试

#pragma once#include"HashTable.h"namespace aj
{template<class K>class unordered_set{public:struct SetKeyOfT{const K& operator()(const K& k){return k;}};public:// 因为unordered_set中K是不能被改变// 所以普通迭代器也无法改变K的值// 所以让普通迭代器也是const迭代器typedef typename hash_bucket::hash_table<const K, K, SetKeyOfT, HashFunc<K>>::const_iterator iterator;typedef typename hash_bucket::hash_table<const K, K, SetKeyOfT, HashFunc<K>>::const_iterator const_iterator;// 由于_ht.Insert(key)返回的普通迭代器// 而pair<iterator, bool>中的迭代器// 看起来是普通迭代器,但实际上是const迭代器// 所以这里不能直接 return _ht.Insert(key)pair<iterator, bool> insert(const K& key){auto tmp = _ht.Insert(key);return make_pair(iterator(tmp.first._node, tmp.first._pht, tmp.first.hashi), tmp.second);}// 由于这里普通迭代器也是const迭代器// 那么这里只保留const迭代器版本/*iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}*/const_iterator begin()const{return _ht.begin();}const_iterator end()const{return _ht.end();}bool erase(const K& key){return _ht.Erase(key);}iterator find(const K& key){return _ht.Find(key);}void clear(){_ht.Clear();}size_t size(){return _ht.Size();}void swap(unordered_set<K>& us){_ht.Swap(us._ht);}private:// unordered_set中K是不能被改变的hash_bucket::hash_table <const K, K , SetKeyOfT , HashFunc<K>> _ht;};void test_unordered_set(){// 17:05/*unordered_set<int> us;us.insert(5);us.insert(15);us.insert(52);us.insert(3);*///unordered_set<int>::iterator it = us.begin();//while (it != us.end())//{//	// *it += 5;//	cout << *it << " ";//	++it;//}//cout << endl;unordered_set<int> us1;us1.insert(1);us1.insert(2);us1.insert(3);us1.insert(4);unordered_set<int> us2;us2.insert(10);us2.insert(20);us2.insert(30);us2.insert(40);for (auto e : us1){cout << e << " ";}cout << endl;for (auto e : us2){cout << e << " ";}cout << endl;us1.swap(us2);for (auto e : us1){cout << e << " ";}cout << endl;for (auto e : us2){cout << e << " ";}cout << endl;}
}

三、unordered_map的实现及测试

#pragma once#include"HashTable.h"namespace aj
{template<class K , class V>class unordered_map{public:struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};public:typedef typename hash_bucket::hash_table<K, pair<const K, V>, MapKeyOfT, HashFunc<K>>::iterator iterator;typedef typename hash_bucket::hash_table<K, pair<const K, V>, MapKeyOfT, HashFunc<K>>::const_iterator const_iterator;pair<iterator,bool> insert(const pair<K, V>& kv){return _ht.Insert(kv);}iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}const_iterator begin()const{return _ht.begin();}const_iterator end()const{return _ht.end();}V& operator[](const K& key){auto tmp = _ht.Insert(make_pair(key,V()));return tmp.first->second;}const V& operator[](const K& key)const{auto tmp = _ht.Insert(make_pair(key, V()));return tmp.first->second;}bool erase(const K& key){return _ht.Erase(key);}iterator find(const K& key){return _ht.Find(key);}void clear(){_ht.Clear();}size_t size(){return _ht.Size();}void swap(unordered_map<K,V>& um){_ht.Swap(um._ht);}private:// unordered_map中K是不能被改变的hash_bucket::hash_table <K, pair<const K, V>, MapKeyOfT , HashFunc<K>> _ht;};void test_unordered_map1(){unordered_map<int, int> um;um.insert(make_pair(1, 1));um.insert(make_pair(2, 2));um.insert(make_pair(3, 3));um.insert(make_pair(4, 4));unordered_map<int, int>::iterator it = um.begin();while (it != um.end()){cout << it->first << ' ' << it->second << endl;++it;}}void test_unordered_map2(){unordered_map<string, string> dict;dict.insert(make_pair("sort", "排序"));dict.insert(make_pair("insert", "插入"));dict.insert(make_pair("string", "字符串"));for (auto& kv : dict){// kv.first += 'x';kv.second += 'x';cout << kv.first << ":" << kv.second << endl;}cout << endl;string arr[] = { "香蕉", "甜瓜","苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };unordered_map<string, int> count_map;for (auto& e : arr){count_map[e]++;}for (auto& kv : count_map){cout << kv.first << ":" << kv.second << endl;}cout << endl;}
}

结尾

到目前已经将哈希的大部分内容讲述完了,那么下一篇文章将继续完善哈希,讲述位图和布隆过滤器。

如果有什么建议和疑问,或是有什么错误,大家可以在评论区中提出。
希望大家以后也能和我一起进步!!🌹🌹
如果这篇文章对你有用的话,希望大家给一个三连支持一下!!🌹🌹

在这里插入图片描述

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

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

相关文章

[笔试训练](三十六)106:提取不重复的整数107:哈夫曼编码108:abb

目录 106:提取不重复的整数 107:哈夫曼编码 108:abb 106:提取不重复的整数 题目链接:提取不重复的整数_牛客题霸_牛客网 (nowcoder.com) 题目: ​ 题解: #include <iostream> #include <string> using namespace std; int n0; int cnt[10]; int ret0; int mai…

【pytorch18】Logistic Regression

回忆线性回归 for continuous:y xwbfor probability output:yσ(xwb) σ:sigmoid or logistic 线性回归是简单的线性模型&#xff0c;输入是x&#xff0c;网络参数是w和b&#xff0c;输出是连续的y的值 如何把它转化为分类问题?加了sigmoid函数&#xff0c;输出的值不再是…

Python精神病算法和自我认知异类数学模型

&#x1f3af;要点 &#x1f3af;空间不确定性和动态相互作用自我认知异类模型 | &#x1f3af;精神病神经元算法推理 | &#x1f3af;集体信念催化个人行动力数学模型 | &#x1f3af;物种基因进化关系网络算法 | &#x1f3af;电路噪声低功耗容错解码算法 &#x1f4dc;和-…

动手学深度学习(Pytorch版)代码实践 -循环神经网络-55循环神经网络的从零开始实现和简洁实现

55循环神经网络的实现 1.从零开始实现 import math import torch from torch import nn from torch.nn import functional as F from d2l import torch as d2l import matplotlib.pyplot as plt import liliPytorch as lp# 读取H.G.Wells的时光机器数据集 batch_size, num_ste…

C语言中的数组:掌握数据的有序集合【一维数组,二维数组,字符串数组,直方图打印,计算全排列,字符数组常用函数】

目录 C语言中的数组&#xff1a;掌握数据的有序集合【一维数组&#xff0c;二维数组&#xff0c;字符串数组】一维数组一维数组的创建数组的七种初始化完全初始化&#xff1a;部分初始化&#xff1a;字符数组的初始化&#xff1a;自动初始化为0&#xff1a;使用memset函数初始化…

『大模型笔记』GraphRAG:用于复杂数据发现的新工具现已在GitHub上发布

GraphRAG:用于复杂数据发现的新工具现已在GitHub上发布 文章目录 一. GraphRAG:用于复杂数据发现的新工具现已在GitHub上发布1. 评估和结果2. 研究见解和未来方向二. 参考文献一. GraphRAG:用于复杂数据发现的新工具现已在GitHub上发布 下载 GraphRAG今年早些时候,我们介绍…

博客建站3 - 购买域名

1. 本网站的系统架构2. 选择域名 2.1. 确定域名关键词2.2. 保持简洁易记2.3. 检查域名可用性 3. 域名注册商 3.1. 海外的提供商 3.1.1. GoDaddy3.1.2. Namecheap3.1.3. Google Domains 3.2. 国内的提供商 3.2.1. 阿里云&#xff08;Alibaba Cloud&#xff09;3.2.2. 腾讯云&…

0502STM32EXTI中断项目代码实现

STM32EXTI中断函数代码实现 对射式红外传感器&旋转编码器计次配置外部中断的步骤&#xff1a;AFIO相关函数&GPIO的一个函数EXTI相关函数代码NVIC中断函数启动文件里的中断函数名字中断编程的建议&#xff1a; 对射式红外传感器&旋转编码器计次 一般一个模块要写的…

SpringBoot:SpringBoot中如何实现对Http接口进行监控

一、前言 Spring Boot Actuator是Spring Boot提供的一个模块&#xff0c;用于监控和管理Spring Boot应用程序的运行时信息。它提供了一组监控端点&#xff08;endpoints&#xff09;&#xff0c;用于获取应用程序的健康状态、性能指标、配置信息等&#xff0c;并支持通过 HTTP …

windows下使用编译opencv在qt中使用

记录一下&#xff1a;在windows下qt使用opencv 1、涉及需要下载的软件 CMake 下载地址opecnv下载地址mingw(需要配置环境变量) 这个在下载qt的时候可以直接安装一般在qt的安装路径下的tool里比如我的安装路径 (C:\zz\ProgramFiles\QT5.12\Tools\mingw730_64) 2、在安装好CMake…

ChatGPT对话:Scratch编程中一个单词,如balloon,每个字母行为一致,如何优化编程

【编者按】balloon 7个字母具有相同的行为&#xff0c;根据ChatGPT提供的方法&#xff0c;优化了代码&#xff0c;方便代码维护与复用。初学者可以使用7个字母精灵&#xff0c;复制代码到不同精灵&#xff0c;也能完成这个功能&#xff0c;但不是优化方法&#xff0c;也没有提高…

ENSP软件中DHCP的相关配置以及终端通过域名访问服务器

新建拓扑 配置路由器网关IP 设备配置命令&#xff1a;<Huawei> Huawei部分为设备名 <>代表当下所在的模式&#xff0c;不同模式下具有不同的配置权限<Huawei> 第一级模式&#xff0c;最低级模式 查看所有参数<Huawei>system-view 键入系统视图…

Python中的null是什么?

在知乎上遇到一个问题&#xff0c;说&#xff1a;计算机中的「null」怎么读&#xff1f; null正确的发音是/n^l/&#xff0c;有点类似四声‘纳儿’&#xff0c;在计算机中null是一种类型&#xff0c;代表空字符&#xff0c;没有与任何一个值绑定并且存储空间也没有存储值。 P…

STM32的独立看门狗详解

目录 1.独立看门狗是什么&#xff1f; 2.独立看门狗的作用 3.独立看门狗的实现原理 4.独立看门狗用到的寄存器 4.1 IWDG_KR &#xff08;关键字计时器&#xff09; 4.2 IWDG_PR&#xff08;预分频寄存器&#xff09; 4.3 IWDG_RLR&#xff08;重装载寄存器&#xff09…

程序的控制结构——if-else语句(双分支结构)【互三互三】

目录 &#x1f341; 引言 &#x1f341;if-else语句&#xff08;双分支结构&#xff09; &#x1f449;格式1&#xff1a; &#x1f449;功能&#xff1a; &#x1f449;程序设计风格提示&#xff1a; &#x1f449;例题 &#x1f449;格式2&#xff1a; &#x1f449;…

ENSP防火墙综合配置

综合拓扑&#xff1a; 实验要求&#xff1a; 要求一 生产区的安全策略配置 办公区的安全策略 要求二 生产区的安全策略 游客和办公区的安全策略 因为ISP返回的数据包会被防火墙最后的默认安全策略给拒绝&#xff0c;所以&#xff0c;把要ISP返回的数据给允许通过 要求三 增加…

《基于 Kafka + Flink + ES 实现危急值处理措施推荐和范围校准》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; 近期刚转战 CSDN&#xff0c;会严格把控文章质量&#xff0c;绝不滥竽充数&#xff0c;欢迎多多交流。&am…

location匹配的优先级和重定向

nginx的重定向&#xff08;rewrite&#xff09; location 匹配 location匹配的就是后面的uri /wordpress 192.168.233.10/wordpress location匹配的分类和优先级 1.精确匹配 location / 对字符串进行完全匹配&#xff0c;必须完全符合 2.正则匹配 ^-前缀级别&#xff…

【MYSQL】如何解决 bin log 与 redo log 的一致性问题

该问题问的其实就是redo log 的两阶段提交 为什么说redo log 具有崩溃恢复的能力 MySQL Server 层拥有的 bin log 只能用于归档&#xff0c;不足以实现崩溃恢复&#xff08;crash-safe&#xff09;&#xff0c;需要借助 InnoDB 引擎的 redo log 才能拥有崩溃恢复的能力。所谓崩…

Java毕业设计 基于SSM vue电影订票系统小程序 微信小程序

Java毕业设计 基于SSM vue电影订票系统小程序 微信小程序 SSM 电影订票系统小程序 功能介绍 用户 登录 注册 忘记密码 首页 图片轮播 电影信息 电影详情 评论 收藏 预订 电影资讯 资讯详情 用户信息修改 电影评价 我的收藏管理 用户充值 在线客服 我的订单 管理员 登录 个人…