哈希(Hash)

文章目录

    • 1.stl提供的哈希容器
      • 1.1unordered_map和unordered_set容器
        • 1.1.1定义
        • 1.1.2这些容器和map和set的区别在于**:
        • 1.1.3物理结构
    • 2 哈希(实现哈希)
      • 2.1本质:哈希表
      • 2.2底层原理:哈希概念
        • 2.2.1哈希方法
        • 2.2.2 哈希函数(映射方法,解决数据分散,空间过大问题)
        • 2.2.3 哈希冲突(映射出现多个数据站一个坑问题)
        • 2.2.4 哈希冲突解决
          • 2.2.4.1 闭散列
          • 闭散列哈希的实现(包含增删查找)
          • 2.2.4.2 开散列(哈希桶/拉链法)
        • 2.2.5思考
          • 1. 负载因子(解决哈希表空间不足问题,本质扩容)
          • 2.解决哈希关键字是负数的映射问题
          • 3.对于关键字是string类型的哈希如何进行哈希函数
    • 3.unordered_map和unordered_set 的模拟实现

1.stl提供的哈希容器

在c++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到log2(N),这个容器在在数据过大时,查询时间过高;于是stl提供了4个unordered系列关联式容器(底层使用哈希),unordered系列关联式容器包含4个包括:unordered_map和unordered_set,unordered_multimap和unordered_multiset
这里我们只讲:unordered_map和unordered_set,

1.1unordered_map和unordered_set容器

1.1.1定义

unordered_map的文档
unordered_set在线文档说明
在这里插入图片描述

1.1.2这些容器和map和set的区别在于**:

1.迭代器只可以向后遍历(++),不可向前遍历(- );
2.该容器是无序的;不会像map和set升序排序;他只会按插入顺序排序;
3.运行速度高于map和set的速度;
在这里插入图片描述
rand()是重复较多的随机数;
rand()+1是重复较少的随机数;
1是没有重发的,有序数;
这里得出结论:unordered较快;除了“1”时map和set比unordered快;

1.1.3物理结构

在这里插入图片描述
这里的二维结构:第一层是每个元素的key 第二层是每个元素的value

2 哈希(实现哈希)

2.1本质:哈希表

哈希表:哈希表就是在关键字和存储位置之间建立对应关系,使得元素的查找可以以O(1)的效率进行, 其中关键字和存储位置之间是通过散列函数建立关系;
所以哈希表的本质:数组
举个例子:
使用哈希表来查找单词中出现一次的字母;
在这里插入图片描述

2.2底层原理:哈希概念

哈希表内:有哈希方法

2.2.1哈希方法

插入元素
根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放
搜索元素
对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键码相等,则搜索成功

2.2.2 哈希函数(映射方法,解决数据分散,空间过大问题)

引起哈希冲突的一个原因可能是:哈希函数设计不够合理
哈希函数设计原则:
哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值
域必须在0到m-1之间
哈希函数计算出来的地址能均匀分布在整个空间中
哈希函数应该比较简单
解决方法

  1. 直接定址法–(常用)
    取关键字的某个线性函数为散列地址:Hash(Key)= Key
  2. 除留余数法–(常用)
    设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,(p是数组大小)
    按照哈希函数:Hash(key) = key% p(p<=m),将关键码转换成哈希地址
    除留余数法例子

例如:数据集合{1,7,6,4,5,9};
哈希函数设置为:hash(key) = key % 容器名。size(); **容器名。size()**为存储元素底层空间总的大小。
在这里插入图片描述

2.2.3 哈希冲突(映射出现多个数据站一个坑问题)

对于两个数据元素的关键字 k i k_i ki k j k_j kj(i != j),有 k i k_i ki != k j k_j kj,但有:Hash( k i k_i ki) ==
Hash( k j k_j kj),即:不同关键字通过相同哈希函数计算出相同的哈希地址,该种现象称为哈希冲突
或哈希碰撞。
在这里插入图片描述

发生哈希冲突该如何处理呢?
使用闭散列和开散列,下下个知识点;

2.2.4 哈希冲突解决

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

2.2.4.1 闭散列

闭散列:也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把key存放到冲突位置中的“下一个” 空位置中去。那如何寻找下一个空位置呢?
在这里插入图片描述
闭散列实现哈希(这里使用线性探测举例)
原理:
在这里插入图片描述
使用除留余数法出现哈希冲突时,在原哈希函数计算的位置向后找空位置,知道找到空位置;

体现:
这里线性探测体现在插入 查找 删除这几个哈希方法上

闭散列哈希的实现(包含增删查找)
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<utility>
#include<vector>
#include<string>
namespace bit
{enum Status{EMPTY,EXIST,DELETE};template<class K, class V>struct HashData{pair<K, V> _kv;Status _s;          //状态};template<class k>struct HashFunc{size_t operator()(const k& key){return (size_t)key;}};//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<>struct HashFunc<string>{size_t operator()(const string& key){// BKDRsize_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 (_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){//下面如果不检查_tables的s是否是EXIST,那么后面的删除操作会将已经删除的元素当成hi存在if (_tables[hashi]._s == EXIST && _tables[hashi]._kv.first == key){return &_tables[hashi];}hashi++;hashi %= _tables.size();}return NULL;}bool Erase(const K& key){HashData<K, V>* ret = Find(key);if (ret){ret->_s = DELETE;--_n;return true;}elsereturn 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; // 存储的关键字的个数};void TestHT1(){HashTable<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.Print();ht.Erase(3);ht.Print();if (ht.Find(3)){cout << "3存在" << endl;}else{cout << "3不存在" << endl;}ht.Insert(make_pair(3, 3));ht.Insert(make_pair(23, 3));ht.Print();}}
2.2.4.2 开散列(哈希桶/拉链法)

在这里插入图片描述
将使用哈希函数结果相同的元素用链表链接;
当元素过多时,使用二叉树来存储元素;代替链表;
代码实现

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<utility>
#include<vector>
#include<string>
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& key)
//	{
//		size_t hash = 0;
//		for (auto e :key)
//		{
//			hash *= 31;
//			hash += e;
//		}
//		cout << key << ":" << hash << endl;
//		return hash;
//	}
template<>
struct HashFunc<string>
{size_t operator()(const string& key){// BKDRsize_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;// vector<Node*> * _ptb;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{// 当前桶已经走完了,找下一个桶开始//KeyOfT kot;//Hash hf;//size_t hashi = hf(kot(_node->_data)) % _pht._tables.size();++_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;}};template<class K,class T,class KeyOfT ,class Hash>class HashTable{template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>friend struct __HTIterator;typedef HashNode<T> Node;public:/*typedef _HTIterator<K, T, T&, T*, KeyOfT, Hash> iterator;*///类型typdef的位值决定了这个类型是否可以在类外使用用来定义;public类型可以在类外定义,private只可以在类内使用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);}if (_n == _tables.size()){   //这种输入对内存消耗大,需要重新定义链表				size_t newSize = _tables.size() * 2;/*HashTable<K, V>newHT;newHT._tables.resize(newSize);for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){newHT.Insert(cur->_kv);cur = cur->_next;}}_tables.swap(newHT._tables);*/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(cur->_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;size_t hashi = hf(key) % _tables.size();Node* prev = nullptr;Node* cur = _tables[hashi];KeyOfT kot;while (cur){if (kot(cur->_data) == key){if (prev == nullptr)_tables[hashi] = cur->_next;elseprev->_next = cur->_next;delete cur;return true;}prev = cur;cur = cur->_next;}return false;}private:vector<Node*>_tables;size_t _n = 0;};}
2.2.5思考
1. 负载因子(解决哈希表空间不足问题,本质扩容)

负载因子:存储数据的个数/表的大小
使用在上面的插入中;

2.解决哈希关键字是负数的映射问题

这里不需要做出改变的原因:
除留余数法–(常用)
Hash(key) = key% p(p<=m),
这里的p是一个无符号整型;所以hash会强制转化为正数

3.对于关键字是string类型的哈希如何进行哈希函数

这种哈希无法使用除留余数法
hash(key) = key % **容器名。size()

3.unordered_map和unordered_set 的模拟实现

模板类:hafuma.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<utility>
#include<vector>
#include<string>
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& key)
//	{
//		size_t hash = 0;
//		for (auto e :key)
//		{
//			hash *= 31;
//			hash += e;
//		}
//		cout << key << ":" << hash << endl;
//		return hash;
//	}
template<>
struct HashFunc<string>
{size_t operator()(const string& key){// BKDRsize_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;// vector<Node*> * _ptb;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{// 当前桶已经走完了,找下一个桶开始//KeyOfT kot;//Hash hf;//size_t hashi = hf(kot(_node->_data)) % _pht._tables.size();++_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;}};template<class K,class T,class KeyOfT ,class Hash>class HashTable{template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>friend struct __HTIterator;typedef HashNode<T> Node;public:/*typedef _HTIterator<K, T, T&, T*, KeyOfT, Hash> iterator;*///类型typdef的位值决定了这个类型是否可以在类外使用用来定义;public类型可以在类外定义,private只可以在类内使用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);}if (_n == _tables.size()){   //这种输入对内存消耗大,需要重新定义链表				size_t newSize = _tables.size() * 2;/*HashTable<K, V>newHT;newHT._tables.resize(newSize);for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){newHT.Insert(cur->_kv);cur = cur->_next;}}_tables.swap(newHT._tables);*/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(cur->_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;size_t hashi = hf(key) % _tables.size();Node* prev = nullptr;Node* cur = _tables[hashi];KeyOfT kot;while (cur){if (kot(cur->_data) == key){if (prev == nullptr)_tables[hashi] = cur->_next;elseprev->_next = cur->_next;delete cur;return true;}prev = cur;cur = cur->_next;}return false;}private:vector<Node*>_tables;size_t _n = 0;};}

unordered_map.h

#pragma once
#include"hafuma.h"
namespace bit
{template<class K,class V, class Hash = HashFunc<K>>class unordered_map{struct MapKeyOfT{const K& operator() (const pair<K,V>& key){return key.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>& key){return _ht.Insert(key);}iterator find(const K& key){return _ht.Find(key);}bool erase(const K& key){return _ht.Erase(key);}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;}private:hash_bucket::HashTable<K, pair<const K,V>, MapKeyOfT,Hash>_ht;};void test_map(){unordered_map<string, string> dict;dict.insert(make_pair("sort", ""));dict.insert(make_pair("string", "ַ"));dict.insert(make_pair("insert", ""));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;}}

unordered_set.h

#pragma once
#include"hafuma.h"
namespace bit
{template<class K,class Hash=HashFunc<K>>class unordered_set{struct SetKeyOfT{const K& operator() (const K& key){return key;}};public :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;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);}const_iterator begin() const{return _ht.begin();}const_iterator end() const{return _ht.end();}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;};void test_set(){unordered_set<int> us;us.insert(5);us.insert(15);}
}

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

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

相关文章

分布式锁之RedissonLock

什么是Redisson&#xff1f; 俗话说他就是看门狗&#xff0c;看门狗机制是一种用于保持Redis连接活跃性的方法&#xff0c;通常用于分布式锁的场景。看门狗的工作原理是&#xff1a;当客户端获取到锁之后&#xff0c;会对Redis中的一个特定的键设置一个有限的过期时间&#xff…

立聪堂助听器29周年暨第九届助听使者活动圆满落幕

5月10日对于立聪堂来说是个特别的日子&#xff0c;这家专注于听力健康领域的公司迎来了29周年。同时&#xff0c;立聪堂第九届助听使者代表及其家人也受邀参观立聪堂南京总部&#xff0c;共庆29周年。 易被忽视的老人听力健康 大数据显示&#xff0c;我国65岁以上老人&#x…

第六节笔记及作业----Lagent AgentLego 智能体应用搭建

关于 Agent 的相关理论 大语言模型存在一些局限性&#xff0c;比如会出现幻觉问题、有时效性问题以及可靠性问题。智能体的定义是具备感知、决策和行动能力的实体。智能体主要由感知部分、大脑部分和动作部分组成。智能体有多种类型&#xff0c;如 ReAct 类型&#xff08;侧重…

如何使用 ArcGIS Pro 计算容积率

容积率是指地上建筑物的总面积与用地面积的比率&#xff0c;数值越小越舒适&#xff0c;这里为大家介绍一下如何使用ArcGIS Pro 计算容积率&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载的建筑和小区数据&#xff0c;除了建筑和小区数据&am…

【联通官网及APP注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞 …

使用Flink SQL实时入湖Hudi/Hive

文章目录 1 Hudi 简介2 COW和MOR3 接入COW模式Hudi表4 使用Flink SQL查看新接表5 使用Hive查看新接表6 总结 1 Hudi 简介 Hudi是一个流式数据湖平台&#xff0c;使用Hudi可以直接打通数据库与数据仓库&#xff0c;连通大数据平台&#xff0c;支持对数据增删改查。Hudi还支持同…

软件设计中的数字:7

“ 使软件更易理解的秘密&#xff1a;米勒法则” 小游戏 学习之前先一起玩一个小游戏。 3秒钟时间&#xff0c;看看下面的图片中有多少个小块&#xff1f; 3秒到了&#xff0c;数出来了吗&#xff1f;22个。 没数出来也没关系&#xff0c;我也没数出来o(╥﹏╥)o 现在&…

[AIGC] 压缩列表了解吗?快速列表 quicklist 了解吗?

文章目录 压缩列表了解吗&#xff1f;快速列表 quicklist 了解吗&#xff1f; 压缩列表了解吗&#xff1f; 压缩列表是 Redis 为了节约内存 而使用的一种数据结构&#xff0c;是由一系列特殊编码的连续内存快组成的顺序型数据结构。 一个压缩列表可以包含任意多个节点&#xf…

3D分子生成的定制扩散框架 MolDiff - 评测

MolDiff模型是一种考虑分子键生成的3D分子生成的新模型。MolDiff是清华大学智能产业研究院马剑竹课题组发表在PMLR 2023的工作&#xff0c;第一作者是Xingang Peng&#xff0c;文章题目为&#xff1a;《 Addressing the Atom-Bond Inconsistency Problem in 3D Molecule Genera…

Mac安装jadx

1、使用命令brew安装 : brew install jadx 输入完命令,等待安装完毕 备注&#xff08;关于Homebrew &#xff09;&#xff1a; Homebrew 是 MacOS 下的包管理工具&#xff0c;类似 apt-get/apt 之于 Linux&#xff0c;yum 之于 CentOS。如果一款软件发布时支持了 homebrew 安…

STM32 PWM 计数器模式和对齐

STM32 PWM 计数器模式和对齐 1. TIM高级定时器简介2. TIM计数模式2.1 向上计数2.2 向下计数2.3 中心对齐模式&#xff08;向上/向下计数&#xff09;2.4 重复计数 3. PWM输出模式3.1 举例看下PWM中心对齐模式&#xff0c;设置参数如下&#xff1a; 4. FOC中PWM相关设置说明4.1 …

Docker学习(带图详细)

一、安装docker 参考官方文档&#xff1a;https://docs.docker.com/engine/install/centos/ 查看系统版本 [rootlocalhost ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) [rootlocalhost ~]# [rootlocalhost ~]# uname -a Linux localhost.localdomai…

华为OD机试 - 密码输入检测(Java 2024 C卷 100分)

华为OD机试 2024C卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测试…

后端项目开发笔记

Maven打包与JDK版本不对应解决方法 我这里使用jdk8。 <build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configurat…

【适用全主题】WordPress原创插件:弹窗通知插件 支持内容自定义

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 适用于所有WordPress主题的弹窗插件 一款WordPress原创插件&#xff1a;弹窗通知插件 支持内容自定义 二、效果展示 1.部分代码 代码如下&#xff08;示例&#xff09;&#xff1…

BGP学习二:BGP通告原则,BGP反射器,BGP路径属性细致讲解,新手小白无负担

目录 一.AS号 二.BGP路由生成 1.network 2.import-route引入 三.BGP通告原则 1.只发布最优且有效的路由 2.从EBGP获取的路由&#xff0c;会发布给所有对等体 3.水平分割原则 4.IBGP学习BGP默认不发送给EBGP&#xff0c;但如果也从IGP学习到了这条路由&#xff0c;就发…

4. 分布式链路追踪客户端工具包Starter设计

前言 本文将从零搭建分布式链路追踪客户端工具包的Starter&#xff0c;并将在后续文章中逐步丰富支持的场景。这里首先将搭建一个最基础的Starter&#xff0c;能提供的功能和1. 看完这篇文章我奶奶都懂Opentracing了一文中的示例demo类似。 相关版本依赖如下。 opentracing-…

生成ssl证书并配置到nginx

生成ssl证书并配置到nginx 安装证书生成工具 apt-get update apt install software-properties-common add-apt-repository ppa:certbot/certbot apt-get update apt-get install certbot python3-certbot-nginx生成证书 首先在新网上创建一个A链接&#xff0c;域名与服务器做…

vue3 自定义国际化、elementPlus 国际化

自定义国际化 1. 引入 vue-i18n 插件 pnpm install vue-i18nnext 2. 页面添加语言文件目录&#xff0c;添加自定义的语言文件 3.语言目录里添加 index.ts&#xff0c; 内容如下 import { createI18n } from "vue-i18n";// 自定义语言文件 import zhCN from "…

WordPress中插入视频的两种方法详解

最近我在建设WordPress网站的时候需要上传视频&#xff0c;我使用的是Hostease的主机安装的WordPress&#xff0c;随后在咨询了他们的技术支持后获得了一些解决方法。下面将介绍WordPress中插入视频的两种方法&#xff1a;本地上传和外部引用。 本地上传视频 使用WordPress的古…