当前位置: 首页 > news >正文

【C++】开散列实现unordered_map与unordered_set的封装

本文主要介绍unordered_map与unordered_set的封装,此次封装主要用上文所说到的开散列,通过开散列的一些改造来实现unordered_map与unordered_set的封装

文章目录

    • 一、模板参数
    • 二、string的特化
    • 三、正向迭代器
    • 四、构造与析构
    • 五、[]的实现
    • 六、unordered_map的实现
    • 七、unordered_set的实现
    • 八、哈希表代码

一、模板参数

由于unordered_set 是 K 模型的容器,而 unordered_map 是 KV 模型的容器,所以需要对结点的参数进行改造,unordered_set可以使用,unordered_map也可以使用,改为T _data即可

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

T模板参数可能是键值Key,也可能是Key和Value构成的键值对。如果是unordered_map容器,那么它传入底层哈希表的模板参数就是Key和Key和Value构成的键值对,如果是unordered_set容器,那么它传入底层哈希表的模板参数就是Key和Key

	template<class K,class V,class Hash=HashFunc<K>>class unordered_map{private:buckethash::HashTable<K, pair<const K, V>, Hash, MapKeyOfT> _ht;};
	template<class K,class Hash = HashFunc<K>>class unordered_set{private: buckethash::HashTable<K, K, Hash, SetKeyOfT> _ht;};

如此就可以实现泛型了,如果是unordered_set,结点当中存储的是键值Key;如果是unordered_map,结点当中存储的就是<Key, Value>键值对:

image-20230301073400540

哈希表仿函数的支持:KeyOfT👇

我们通过哈希计算出对应的哈希地址:但是插入的时候就不能直接用data去进行比较了

对于unordered_set:data是key是可以比较的,对于unordered_map:data是键值对,我们需要取出键值对的first。而data既可以是unordered_set的,也可以是unordered_map的,所以我们需要仿函数来实现不同容器所对应的需求,然后传入:

unordered_map返回kv.first

template<class K,class V,class Hash=HashFunc<K>>class unordered_map{struct MapKeyOfT{const K& operator()(const pair<const K, V>& kv){return kv.first;}};}private:buckethash::HashTable<K, pair<const K, V>, Hash, MapKeyOfT> _ht;};

unordered_set返回key:

template<class K,class Hash = HashFunc<K>>class unordered_set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};private: buckethash::HashTable<K, K, Hash, SetKeyOfT> _ht;};

这也就是Hashtable需要KeyOfT的原因所在。

二、string的特化

字符串无法取模,在这里重新写一遍,字符串无法取模的问题写库的大神们早就想到了

image-20230301074411165

预留一个模板参数,无论上层容器是unordered_set还是unordered_map,我们都能够通过上层容器提供的仿函数获取到元素的键值

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 ch : key){hash *= 131;//顺序?abc,cbahash += ch;}return hash;}
};

string的特化:符合string类型的优先走string类型

template<class K,class V,class Hash=HashFunc<K>>
class unordered_map
template<class K,class Hash = HashFunc<K>>
class unordered_set

三、正向迭代器

哈希表的正向迭代器对哈希表指针和结点指针进行了封装,++运算符重载,可以访问下一个非空的桶,所以每个正向迭代器里面存的是哈希表地址。

template<class K, class T, class Hash, class KeyOfT>
class HashTable;template<class K,class T,class Hash,class KeyOfT>struct __HTIterator{typedef HashNode<T> Node;typedef __HTIterator<K, T, Hash, KeyOfT> Self;typedef HashTable<K, T, Hash, KeyOfT> HT;Node* _node;HT* _ht;}

所以我们构造迭代器的时候需要知道节点的地址和哈希表的地址

	__HTIterator(Node*node,HT*ht):_node(node),_ht(ht){}

++运算符重载的实现:如果当前的桶还有节点,那么++就是当前桶下一个节点,如果当前元素是所在的桶的最后一个元素,那么++就是下一个非空的桶了

image-20230301080113773

如何去找下一个非空桶:其实很简单,通过当前节点的值算出当前桶的hashi,然后++hashi就是下一个桶了,找到下一个非空桶即可

		T& operator*(){return _node->_data;}T* operator->(){return &_node->_data;}bool operator !=(const Self& s) const{return _node != s._node;}Self& operator++(){if (_node->_next)//当前桶还有节点{_node = _node->_next;}//找下一个非空的桶else{KeyOfT kot;Hash hash;size_t hashi = hash(kot(_node->_data)) % _ht->_tables.size();//当前桶的哈希地址++hashi;while (hashi < _ht->_tables.size()){if (_ht->_tables[hashi])//非空桶{_node = _ht->_tables[hashi];break;}else{++hashi;}}if (hashi == _ht->_tables.size()){_node = nullptr;}}return *this;}};

–问题:哈希表中的迭代器是单向迭代器,并没有反向迭代器,所以没有实现–-运算符的重载,若是想让哈希表支持双向遍历,可以考虑将哈希桶中存储的单链表结构换为双链表结构。

存在的小细节:👇

	template<class K,class T,class Hash,class KeyOfT>class HashTable{typedef HashNode<T> Node;template<class K,class T,class Hash,class KeyOfT>friend struct __HTIterator;public:typedef __HTIterator<K, T, Hash, KeyOfT> iterator;iterator begin(){for (size_t i = 0; i < _tables.size(); i++){if (_tables[i]){return iterator(_tables[i], this);}}return iterator(nullptr, this);}iterator end(){return iterator(nullptr, this);}private:vector<Node*> _tables;size_t _n = 0;};

++运算符重载去寻找下一个结点时,会访问_tables,而_tables是哈希表中的私有成员,所以我们需要把迭代器__HTIterator声明为哈希表的友元

正向迭代器__HTIterator的typedef放在了public,这是为了外部能够使用我们的typedef之后的正向迭代器

还需要注意的是,哈希表的 const 迭代器不能复用普通迭代器的代码,我们查看源码:

image-20230301210902049

这与我们之前所复用的不同,上面stl源码中可以看到并没有用以前的复用:

这是因为如果使用const版本,那么_tables使用[]返回的就是const版本,那么Node*就相当于是const Node*,就会导致权限放大,无法构造;如果改成const HT* _ht; const Node* _node;,又会导致[]不能修改的问题:

image-20230301212422965

四、构造与析构

默认构造

HashTable():_n(0){_tables.resize(__stl_next_prime(0));}

析构函数

哈希表当中存储的结点都是new出来的,所以哈希表被析构时必须delete。在析构哈希表时我们只需要遍历取出非空的哈希桶,遍历哈希桶当中的结点并进行释放即可👇

		~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;}}

五、[]的实现

要想实现[],我们需要先把Insert的返回值修改成pair<iterator,bool>,最后的返回值也要一起修改

如果有重复的元素就返回这个找到it迭代器
没有重复的就返回newnode迭代器

		pair<iterator, bool> Insert(const T&data){KeyOfT kot;iterator it = Find(kot(data));if (it != end()){return make_pair(it, false);}if (_tables.size() == _n){vector<Node*> newTables;newTables.resize(__stl_next_prime(_tables.size()), nullptr);for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){Node* next = cur->_next;size_t hashi = Hash()(kot(cur->_data))% newTables.size();cur->_next = newTables[hashi];newTables[hashi] = cur;cur = next;}_tables[i] = nullptr;}_tables.swap(newTables);}size_t hashi = Hash()(kot(data)) % _tables.size();Node* newnode = new Node(data);newnode->_next = _tables[hashi];_tables[hashi] = newnode;++_n;return make_pair(iterator(newnode,this),true);}

六、unordered_map的实现

#pragma once#include "HashTable.h"
namespace hwc
{template<class K,class V,class Hash=HashFunc<K>>class unordered_map{struct MapKeyOfT{const K& operator()(const pair<const K, V>& kv){return kv.first;}};public:typedef typename buckethash::HashTable<K, pair<const K, V>, Hash, MapKeyOfT>::iterator iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}pair<iterator, bool> insert(const pair<K, V> data){return _ht.Insert(data);}V& operator[](const K& key){pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));return ret.first->second;}private:buckethash::HashTable<K, pair<const K, V>, Hash, MapKeyOfT> _ht;};void test_unordered_map(){string arr[] = { "苹果","香蕉","苹果","西瓜","哈密瓜"};unordered_map<string, int> countMap;for (auto& e : arr){countMap[e]++;}for (const auto& kv : countMap){cout << kv.first << ":" << kv.second << endl;}}
}

七、unordered_set的实现

#pragma once#include "HashTable.h"namespace hwc
{template<class K,class Hash = HashFunc<K>>class unordered_set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename buckethash::HashTable<K, K, Hash, SetKeyOfT>::iterator iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}pair<iterator, bool> insert(const K& key){return _ht.Insert(key);}private: buckethash::HashTable<K, K, Hash, SetKeyOfT> _ht;};void test_unordered_set(){unordered_set<int> us;us.insert(13);us.insert(3);us.insert(23);us.insert(5);us.insert(5);us.insert(6);us.insert(15);us.insert(223342);us.insert(22);unordered_set<int>::iterator it = us.begin();while (it != us.end()){cout << *it << " ";++it;}cout << endl;for (auto e : us){cout << e << " ";}cout << endl;}
}

八、哈希表代码

#pragma once
#pragma once#include <iostream>
#include <string>
#include <vector>
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 ch : key){hash *= 131;//顺序?abc,cbahash += ch;}return hash;}
};//开散列
namespace buckethash
{template<class T>struct HashNode{T _data;HashNode<T>* _next;HashNode(const T& data):_data(data), _next(nullptr){}};template<class K, class T, class Hash, class KeyOfT>class HashTable;template<class K,class T,class Hash,class KeyOfT>struct __HTIterator{typedef HashNode<T> Node;typedef __HTIterator<K, T, Hash, KeyOfT> Self;typedef HashTable<K, T, Hash, KeyOfT> HT;Node* _node;HT* _ht;__HTIterator(Node*node,HT*ht):_node(node),_ht(ht){}T& operator*(){return _node->_data;}T* operator->(){return &_node->_data;}bool operator !=(const Self& s) const{return _node != s._node;}Self& operator++(){if (_node->_next){_node = _node->_next;}else{KeyOfT kot;Hash hash;size_t hashi = hash(kot(_node->_data)) % _ht->_tables.size();++hashi;while (hashi < _ht->_tables.size()){if (_ht->_tables[hashi]){_node = _ht->_tables[hashi];break;}else{++hashi;}}if (hashi == _ht->_tables.size()){_node = nullptr;}}return *this;}};template<class K,class T,class Hash,class KeyOfT>class HashTable{typedef HashNode<T> Node;template<class K,class T,class Hash,class KeyOfT>friend struct __HTIterator;public:typedef __HTIterator<K, T, Hash, KeyOfT> iterator;iterator begin(){for (size_t i = 0; i < _tables.size(); i++){if (_tables[i]){return iterator(_tables[i], this);}}return iterator(nullptr, this);}iterator end(){return iterator(nullptr, this);}HashTable():_n(0){_tables.resize(__stl_next_prime(0));}~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){KeyOfT kot;iterator it = Find(kot(data));if (it != end()){return make_pair(it, false);}if (_tables.size() == _n){vector<Node*> newTables;newTables.resize(__stl_next_prime(_tables.size()), nullptr);for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){Node* next = cur->_next;size_t hashi = Hash()(kot(cur->_data))% newTables.size();cur->_next = newTables[hashi];newTables[hashi] = cur;cur = next;}_tables[i] = nullptr;}_tables.swap(newTables);}size_t hashi = Hash()(kot(data)) % _tables.size();Node* newnode = new Node(data);newnode->_next = _tables[hashi];_tables[hashi] = newnode;++_n;return make_pair(iterator(newnode,this),true);}iterator Find(const K& key){KeyOfT kot;size_t hashi = Hash()(key) % _tables.size();Node* cur = _tables[hashi];while (cur){if (kot(cur->_data) == key){return iterator(cur, this);}else{cur = cur->_next;}}return end();}bool Erase(const K& key){size_t hashi = Hash()(key) % _tables.size();Node* prev = nullptr;Node* cur = _tables[hashi];while (cur){if (cur->_kv.first == key){if (cur == _tables[hashi]){_tables[hashi] = cur->_next;}else{prev->_next = cur->_next;}delete cur;--_n;return true;}else{prev = cur;cur = cur->_next;}}return false;}inline unsigned long __stl_next_prime(unsigned long n){static const int __stl_num_primes = 28;static const unsigned long __stl_prime_list[__stl_num_primes] ={53, 97, 193, 389, 769,1543, 3079, 6151, 12289, 24593,49157, 98317, 196613, 393241, 786433,1572869, 3145739, 6291469, 12582917, 25165843,50331653, 100663319, 201326611, 402653189, 805306457,1610612741, 3221225473, 4294967291};for (int i = 0; i < __stl_num_primes; ++i){if (__stl_prime_list[i] > n){return __stl_prime_list[i];}}return __stl_prime_list[__stl_num_primes - 1];}private:vector<Node*> _tables;size_t _n = 0;};
}

本篇到此结束…

相关文章:

【C++】开散列实现unordered_map与unordered_set的封装

本文主要介绍unordered_map与unordered_set的封装&#xff0c;此次封装主要用上文所说到的开散列,通过开散列的一些改造来实现unordered_map与unordered_set的封装 文章目录一、模板参数二、string的特化三、正向迭代器四、构造与析构五、[]的实现六、unordered_map的实现七、u…...

华为OD机试真题Python实现【删除指定目录】真题+解题思路+代码(20222023)

删除指定目录 题目 某文件系统中有 N 个目录, 每个目录都一个独一无二的 ID。 每个目录只有一个付目录, 但每个目录下可以有零个或多个子目录, 目录结构呈树状结构。 假设 根目录的 ID 为0,且根目录没有父目录 ID 用唯一的正整数表示,并统一编号 现给定目录 ID 和其付目…...

CSS选择器大全(上)

基础选择器&#xff1a; id选择器&#xff1a;#id{} 类选择器&#xff1a; .class{} 标签选择器&#xff1a; h1{} 复合选择器&#xff1a; 交集选择器&#xff1a;作用&#xff1a;选中同时符合多个条件的元素 语法&#xff1a;选择器1选择器2选择器3选择器n{} 注意&#xff…...

JavaScript 俄罗斯方块 - setTimeout和rAF

本节内容需要有些基础知识,如进程和线程,队列数据结构 一、setTimeout和setInterval 只要使用过JavaScript的朋友,对setTimeout和setInterval应该不会默生,如果光说怎样去使用这个API,并不难,无非就是隔多少毫秒再执行某个函数,把变化的内容封装在函数中,就可以制作出动…...

LeetCode:构造最大二叉树;使用中序和后序数组构造二叉树;使用前序和中序数组遍历二叉树。

构造二叉树最好都是使用前序遍历&#xff1b;中左右的顺序。 654. 最大二叉树 中等 636 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建…...

nodejs实现jwt

jwt是json web token的简称&#xff0c;本文介绍它的原理&#xff0c;最后后端用nodejs自己实现如何为客户端生成令牌token和校验token 1.为什么需要会话管理 我们用nodejs为前端或者其他服务提供resful接口时&#xff0c;http协议他是一个无状态的协议&#xff0c;有时候我们…...

结构体占用内存大小如何确定?-->结构体字节对齐 | C语言

目录 一、什么是结构体 二、为什么需要结构体 三、结构体的字节对齐 3.1、示例1 3.2、示例2 3.3、示例3 3.4、示例4 3.5、示例5 四、结构体字节对齐总结 一、什么是结构体 结构体是将不同类型的数据按照一定的功能需 求进行整体封装&#xff0c;封装的数据类型与大小均…...

Vue和Uniapp:优缺点比较

Vue和Uniapp是两个流行的前端框架&#xff0c;都是用于开发跨平台应用程序的工具。虽然两者都有很多相似之处&#xff0c;但它们也有一些不同之处&#xff0c;这些不同之处可以影响你的选择。下面将对Vue和Uniapp的优缺点进行比较和分析&#xff0c;以帮助你做出更明智的决策。…...

AMBA-AXI(二)AXI的序,保序与乱序

&#x1f4a1;Note&#xff1a;本文是根据AXI协议IHI0022F_b_amba_axi_protocol_spec.pdf&#xff08;issue F&#xff09;整理的。主要是分享AXI3.0和4.0部分。如果内容有问题请大家在评论区中指出&#xff0c;有补充或者疑问也可以发在评论区&#xff0c;互相学习&#x1f64…...

APIs and Open Interface--非工单领、发料(含调拨)

表名 MTL_TRANSACTIONS_INTERFACEMTL_TRANSACTION_LOTS_INTERFACE序列 MTL_MATERIAL_TRANSACTIONS_S.NEXTVALAPIs INV_TXN_MANAGER_PUB.PROCESS_TRANSACTIONS案例 杂发/杂收&#xff08;代码&#xff09;Declare v_user_id number : fnd_global.user_id; v_login_id number …...

互联网医院系统软件开发|互联网医院管理系统开发的好处

互联网医院一直是现在的热门行业&#xff0c;很多的医院已经开发了互联网医院&#xff0c;并且已经在良好的运行中&#xff0c;而有一些医院和企业正在开发中&#xff0c;或者打算开发互联网医院系统&#xff0c;其实这些企业和医院还是很有远见的&#xff0c;因为他们知道并了…...

2.单例模式

基本概念 单例模式&#xff1a;保证一个类只有一个实例&#xff0c;并提供一个访问该实例的全局访问点 常见应用场景 读取配置文件的类一般设计为单例模式网站计数器应用程序的日志应用&#xff0c;因为共享日志文件一直处于打开状态&#xff0c;只能有一个实例去操作Spring…...

【保姆级】Java后端查询数据库结果导出xlsx文件+打印xlsx表格

目录前言一、需求一&#xff1a;数据库查询的数据导出成Excel表格1.1 Vue前端实现导出按钮点击事件1.2 后端根据数据库查询结果生成xlsx文件二、需求二&#xff1a;对生成的xlsx文件调用打印机打印2.1 Vue前端实现按钮事件2.2 后端实现打印前言 最近在弄一个需求&#xff0c;需…...

Java数据库部分(MySQL+JDBC)(二、JDBC超详细学习笔记)

文章目录1 JDBC&#xff08;Java Database Connectivity&#xff09;1.1 什么是 JDBC&#xff1f;1.2 JDBC 核心思想2 JDBC开发步骤【重点】2.0 环境准备2.1 注册数据库驱动2.2 获取数据库的连接2.3 获取数据库操作对象Statement2.4 通过Statement对象执行SQL语句2.5 处理返回结…...

vue3生命周期

一、Vue3中的生命周期 1、setup() : 开始创建组件之前&#xff0c;在 beforeCreate 和 created 之前执行&#xff0c;创建的是 data 和 method 2、onBeforeMount() : 组件挂载到节点上之前执行的函数&#xff1b; 3、onMounted() : 组件挂载完成后执行的函数&#xff1b; 4、…...

Python学习笔记10:开箱即用

开箱即用 模块 python系统路径 import sys, pprint pprint.pprint(sys.path) [,D:\\Program Files\\Python\\Lib\\idlelib,D:\\Program Files\\Python\\python310.zip,D:\\Program Files\\Python\\DLLs,D:\\Program Files\\Python\\lib,D:\\Program Files\\Python,D:\\Progr…...

详解JAVA反射

目录 1.概述 2.获取Class对象 3.API 3.1.实例化对象 3.2.方法 3.3.属性 1.概述 反射&#xff0c;JAVA提供的一种在运行时获取类的信息并动态操作类的能力。JAVA反射允许我们在运行时获取类的属性、方法、构造函数等信息&#xff0c;并能够动态地操作它们。 2.获取Class…...

在nestjs中进行typeorm cli迁移(migration)的配置

在nestjs中进行typeorm cli迁移(migration)的配置 在学习nestjs过程中发现typeorm的迁移配置十分麻烦,似乎许多方法都是旧版本的配置&#xff0c;无法直接使用. 花了挺长时间总算解决了这个配置问题. db.config.ts 先创建db.config.ts, 该文件export了两个对象&#xff0c;其…...

前端工程构建问题汇总

1.less less-loader安装失败问题 npm install less-loader --save --legacy-peer-deps 加上–legacy-peer-deps就可以了 在NPM v7中&#xff0c;现在默认安装peerDependencies&#xff0c;这会导致版本冲突&#xff0c;从而中断安装过程。 –legacy-peer-deps标志是在v7中引…...

某马程序员NodeJS速学笔记

文章目录前言一、什么是Node.js?二、fs文件系统模块三、Http模块四、模块化五、开发属于自己的包模块加载机制六、Express1.初识ExpressGET/POSTnodemon2.路由模块化3.中间件中间件分类自定义中间件4. 跨域问题七、Mysql模块安装与配置基本使用Web开发模式Session认证JWT八、m…...

SpringMVC DispatcherServlet源码(6) 完结 静态资源原理

阅读源码&#xff0c;分析静态资源处理器相关组件&#xff1a; 使用SimpleUrlHandlerMapping管理url -> 处理器映射关系spring mvc使用WebMvcConfigurationSupport注入SimpleUrlHandlerMapping组件DelegatingWebMvcConfiguration可以使用WebMvcConfigurer的配置静态资源url…...

2023年全国最新会计专业技术资格精选真题及答案9

百分百题库提供会计专业技术资格考试试题、会计考试预测题、会计专业技术资格考试真题、会计证考试题库等&#xff0c;提供在线做题刷题&#xff0c;在线模拟考试&#xff0c;助你考试轻松过关。 四、材料题 1.某企业为增值税一般纳税人&#xff0c;2019年12月初“应付职工薪酬…...

Web3中文|把Web3装进口袋,Solana手机Saga有何魔力?

2月23日&#xff0c;Solana Web3手机Saga发布新的消息&#xff0c;将推出NFT铸造应用程序Minty Fresh。在Minty Fresh&#xff0c;用户仅需轻点并完成拍摄&#xff0c;就可以直接在手机中进行NFT铸造&#xff0c;并在几秒钟内将其转换为链上NFT&#xff0c;NFT还可以发布在 Ins…...

【配电网优化】基于串行和并行ADMM算法的配电网优化研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

数据结构初阶 -- 顺序表

数据结构初阶 链表的讲解 目录 一. 线性表 1.1 定义 1.2 特点 二. 顺序表 2.1 定义 2.2 代码 2.3 功能需求 2.4 静态顺序表的特点以及缺点 2.5 动态的顺序表 2.6 动态顺序表接口的实现 三. 代码 头文件 主文件 一. 线性表 1.1 定义 线性表&#xff08;linear li…...

uniapp:3分钟搞定在线推送uni.createPushMessage,uni.onPushMessage

安卓端 在线推送功能演示&#xff1a; 1、dcloud后台申请开通uniPush dcloud后台 &#xff08;1&#xff09;&#xff1a;找到我的应用 &#xff08;2&#xff09;&#xff1a;点进去后&#xff0c;各平台信息&#xff0c;点击新增 &#xff08;3&#xff09;&#xff1a;填…...

C/C++开发,无可避免的多线程(篇一).跨平台并行编程姗姗来迟

一、编译环境准备 在正式进入c/c多线程编程系列之前&#xff0c;先来搭建支持多线程编译的编译环境。 1.1 MinGW&#xff08;win&#xff09; 进入Downloads - MinGW-w64下载页面&#xff0c;选择MinGW-w64-builds跳转下载&#xff0c; 再次进行跳转&#xff1a; 然后进入下载页…...

如何把照片的底色修改为想要的颜色

如何给照片更换底色&#xff1f;其实有可以一键给照片更换底色的 APP &#xff0c;但是几乎都要收费。如果想要免费的给照片更换底色的话&#xff0c;分享两种简单便捷的方法给你。掌握了这项技能&#xff0c;以后就不用店花钱处理啦&#xff01;1、免费&#xff01;线上快速 给…...

【高效办公】批量生成固定模板的文件夹名称

老师让你按照他的要求生成每位学生的文件夹,你是学委,让你马上完成该任务,但你又不想是手动一个一个码字,因此聪明的你就看到了本篇文章啦!!! 虽说一个人懒惰,并不是好的事情。 但这个似乎合情合理啊~ 然后,就动手想办法,一开始就真的打算码字了。。 思路 在实际开…...

redis的集群方式

1.主从复制 主从复制原理&#xff1a; 从服务器连接主服务器&#xff0c;发送SYNC命令&#xff1b; 主服务器接收到SYNC命名后&#xff0c;开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令&#xff1b; 主服务器BGSAVE执行完后&#xff0c;向所有从服务…...

wordpress 乱码/推广软文300字范文

硬件系统设计硬件平台基于ARM920T的处理器AT91RM9200&#xff0c;该处理器不仅有丰富的片上资源和标准接口&#xff0c;而且有低功耗、低成本、高性能、支持多种主要的嵌入式操作系统等特点&#xff0c;其采用5级整数流水线结构&#xff0c;性能高达200此方案的硬件系统结构设计…...

静态网站建设/dz论坛seo设置

前言&#xff1a;上一篇讲解了linux下使用命令行操作数据库&#xff0c;这篇继续讲解怎么使用c语言实现linux数据库的操作。使用c语言实现环境搭建&#xff1a;既然我们要使用c语言实现linux数据库操作&#xff0c;那么首先我们得先把数据库源码的文件打包成库文件.so放到ubunt…...

广西建设培训中心网站/软文自助发布平台系统

今天在用nobody跑 脚本时&#xff0c;报错&#xff1a;登录root su apache 报错&#xff1a; su: cannot set user id: 资源暂时不可用 以前也遇到过这种问题&#xff0c;apache账号突然不可用。当时找的原因是系统进程太多&#xff0c;kill几个进程就可以了。 根本原因是&…...

宁波网站seo报价/软文发稿网

1 摘要 本报告是在学习斯坦福大学机器学习课程前四节加上配套的讲义后的总结与认识。前四节主要讲述了回归问题&#xff0c;回归属于有监督学习中的一种方法。该方法的核心思想是从连续型统计数据中得到数学模型&#xff0c;然后将该数学模型用于预测或者分类。该方法处理的数据…...

网站未做安全隐患检测怎么拿shell/保定seo排名优化

编写 sublime-build 文件 在 Sublime Text 窗口中&#xff0c;找到菜单栏上的 Tools -> Build System -> New Build System…。点击之后&#xff0c;Sublime Text 会打开一个新文件&#xff0c;将如下内容复制进文件&#xff1a; C11 {"cmd": ["g"…...

小说网站制作公司/保健品的营销及推广方案

如何安全找回丢失数据的方法1. 下载并安装B计划数据恢复软件。2. 运行恢复软件&#xff0c;点击“深度扫描”。深度扫描是绕过文件系统直接从硬盘、U盘、SD卡等设备底层恢复数据&#xff0c;因此使用深度恢复能找回更多完整数据。同时我们要搞清楚物理硬盘和逻辑硬盘的区别。物…...