使用红黑树封装map和set

news/2024/5/7 12:40:49/文章来源:https://blog.csdn.net/m0_57249790/article/details/130037761

目录

一、set和map的底层结构

使用模板区分map和set

 使用仿函数来比较大小

二、红黑树中set和map的迭代器

end和begin迭代器

operator++迭代器

operator--

三、set与map中的迭代器和const迭代器

四、迭代器的拷贝构造

五、完整代码

set.h

map.h 

RBTree.h


一、set和map的底层结构

使用模板区分map和set

set:

 map:

我们通过去看源码,我们能发现无论是set还是map使用的是同一颗红黑树。并且set中key_type和value_type中其实使用的都是key,然而map中key_type是key,value_type却是pair<key,value>。

也就是通过传过去的value_type来区分我们用的是map还是set。由于为了区分value与pair<key,value>我们吧pair<key,value>在模板中用T来表示。

template<class T>
struct RBTreeNode
{T _data;RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;Colour _col;RBTreeNode(const T& data):_data(data), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED){}
};

 使用仿函数来比较大小

在set中我们比较大小时,是直接使用key来比较大小的。可是我们map中封装的是pair<K,V>,pair<K,V>的比较大小是先比较first,first比较完之后还要比较s0econd。因此不符合我们期望的比较规则,我们需要实现一个仿函数来改变pair的比较规则。

template<class K>class set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};template<class K,class V>class map{struct MapKeyOfT{const K& operator()(const pair<const K,V>& kv){return kv.first;} };

仿函数实现过后,我们使用红黑树的时候直接让该仿函数的结构体作为参数传到红黑树里面。然后使用该结构体定义一个对象,对这个对象进行传参来完成区分map和set的比较。

二、红黑树中set和map的迭代器

end和begin迭代器

template<class T>
struct _RBTreeIterator
{typedef RBTreeNode<T> Node;
}typedef _RBTreeIterator<T> iterator;//提供这个普通迭代器版本是为了与map中的value能改动做照应
//最左结点作为红黑树的begin
iterator begin()
{Node* left = _root;while (left && left->_left){left = left->_left;}return iterator(left);
}//最右结点的右结点(即nullptr)作为红黑树的end
iterator end()
{return iterator(nullptr);
}

operator++迭代器

由于我们的红黑树是一个平衡二叉树的结构,当我们++的时候其实是去访问该结点中序遍历后的下一个结点,详细解释在下边代码的注释中。

typedef _RBTreeIterator<T> iterator;
iterator& operator++(){//如果该结点的右不为空,那么++就是走到该结点右子树的最左结点if (_node->_right){Node* min = _node->_right;while (min->_left){min = min->_left;}_node = min;}//如果该结点的右为空,且本身是其父节点的左孩子//那么其父节点就是我们需要找的结点// //如果其本身是父节点的右孩子//那么将顺着根节点往上去找,直到找到其结点是父结点左孩子的结点//然后父结点就是我们需要找的结点else{Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_right == cur){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;//this结点其实就是本身}

operator--

operator--与operator++相反,其实就是返回中序遍历的前一个结点。具体解释在下边代码的注释中。

typedef _RBTreeIterator<T> iterator;
iterator& operator--(){//如果该结点的左结点不为空,那么就去找左子树的最右结点if (_node->_left){Node* max = _node->_left;while (max->_right){max = max->_right;}_node = max;}//如果该结点的左结点为空//且该结点是父节点的右孩子,那么其父节点就是我们需要找的结点////如果该结点是父节点的左孩子,那么需要顺着根节点去找//结点是父节点的右孩子的结点//该父节点就是我们需要找的结点else{Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_left == cur){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}

三、set与map中的迭代器和const迭代器

set:

首先我们要明白,set是不允许改变当前结点的值的(具体原因是因为set底层是红黑树(是特殊的平衡二叉树,也满足平衡二叉树的性质),如果轻易去改变结点的值会造成该树不满足平衡二叉树的性质,如果实在需要改变,应该先删除,再插入)因此在set中,无论是普通迭代器iterator还是cosnt迭代器cosnt_iterator都需要封装成const迭代器。

//因为这个类模板没有进行实例化所以需要加上typename来说明 
//RBTree<K, pair<const K, V>, MapKeyOfT> 是个类型 等实例化后会自动去将模板参数填充
//由于set的key和value都不能改变,所以我们效仿底层将set的const迭代器和普通迭代器全部封装为const迭代器
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
iterator begin() const
{return _t.begin();//返回红黑树中的begin
}iterator end() const
{return _t.end();//返回红黑树中的end
}

map:

在map中key是不可以改变的,但是value是可以改变的。因此我们不仅要实现普通迭代器,还要实现const迭代器。

//因为这个类模板没有进行实例化所以需要加上typename来说明 
//RBTree<K, pair<const K, V>, MapKeyOfT> 是个类型 等实例化后会自动去将模板参数填充
//由于map的value是可以改变的所以我们对map的迭代器要分清楚const迭代器和普通迭代器
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator;
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;
iterator begin()
{return _t.begin();
}
iterator end()
{return _t.end();
}const_iterator begin() const
{return _t.begin();
}
const_iterator end() const
{return _t.end();
}

四、迭代器的拷贝构造

在自定义类型中我们就学过,普通类型的值是可以赋给const类型的值的。因为这是权限的缩小。

cosnt int a=3;
int b=2;
a=b;

但是const类型的值是不可以赋给普通类型的值的。因为这是权限的放大。

a =2;
cosnt b=3;
a=b;//会报错,因为b的权限比a的权限大

迭代器亦是如此,因此我们要满足普通迭代器可以赋给const迭代器,然而const迭代器不可以赋给普通迭代器。

template<class T, class Ref, class Ptr>
struct _RBTreeIterator
{typedef RBTreeNode<T> Node;typedef _RBTreeIterator<T, Ref, Ptr> Self;//无论传过来的是T& T* 还是const T& , const T*  //iterator都是普通迭代器 为了满足const迭代器去构造普通迭代器typedef _RBTreeIterator<T, T&, T*> iterator;Node* _node;//迭代器结构体中存放的只有一个结点的成员变量//构造函数_RBTreeIterator(Node* node):_node(node){}//普通迭代器的时候,他是拷贝构造//const迭代器的时候,他是构造,支持用普通迭代器构造cosnt迭代器_RBTreeIterator(const iterator& s):_node(s._node){}
}

五、完整代码

其中还包含了一些我没有单独拿出来解释的一些知识,但是都在完整代码中注释中一一解释。

set.h

#pragma once
#include"RBTree.h"namespace bit
{template<class K>class set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public://因为这个类模板没有进行实例化所以需要加上typename来说明 //RBTree<K, pair<const K, V>, MapKeyOfT> 是个类型 等实例化后会自动去将模板参数填充//由于set的key和value都不能改变,所以我们效仿底层将set的const迭代器和普通迭代器全部封装为const迭代器typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;iterator begin() const{return _t.begin();//返回红黑树中的begin}iterator end() const{return _t.end();//返回红黑树中的end}pair<iterator, bool> insert(const K& key){pair<typename RBTree<K, K, SetKeyOfT>::iterator, bool>ret = _t.Insert(key);return pair<iterator, bool>(ret.first, ret.second);}private:RBTree<K, K, SetKeyOfT> _t;};void test_set(){int a[] = { 1,2,3,4,5,6,7,8};set<int> s;for (auto e : a){s.insert(e);}set<int>::iterator it = s.begin();while (it != s.end()){cout << *it << " ";++it;}cout << endl;for (auto e : s){cout << e << " ";}cout << endl;}
}

map.h 

#pragma once
#include"RBTree.h"namespace bit
{template<class K>class set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public://因为这个类模板没有进行实例化所以需要加上typename来说明 //RBTree<K, pair<const K, V>, MapKeyOfT> 是个类型 等实例化后会自动去将模板参数填充//由于set的key和value都不能改变,所以我们效仿底层将set的const迭代器和普通迭代器全部封装为const迭代器typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;iterator begin() const{return _t.begin();//返回红黑树中的begin}iterator end() const{return _t.end();//返回红黑树中的end}pair<iterator, bool> insert(const K& key){pair<typename RBTree<K, K, SetKeyOfT>::iterator, bool>ret = _t.Insert(key);return pair<iterator, bool>(ret.first, ret.second);}private:RBTree<K, K, SetKeyOfT> _t;};void test_set(){int a[] = { 1,2,3,4,5,6,7,8};set<int> s;for (auto e : a){s.insert(e);}set<int>::iterator it = s.begin();while (it != s.end()){cout << *it << " ";++it;}cout << endl;for (auto e : s){cout << e << " ";}cout << endl;}
}

RBTree.h

#pragma once//给出枚举变量,以便于方便区分红黑结点
enum Colour
{RED,BLACK,
};template<class T>
struct RBTreeNode
{T _data;RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;Colour _col;RBTreeNode(const T& data):_data(data), _left(nullptr), _right(nullptr), _parent(nullptr), _col(RED){}
};
//template<class T>
//struct _RBTreeIterator
//{
//	typedef RBTreeNode<T> Node;
//}
template<class T, class Ref, class Ptr>
struct _RBTreeIterator
{typedef RBTreeNode<T> Node;typedef _RBTreeIterator<T, Ref, Ptr> Self;//无论传过来的是T& T* 还是const T& , const T*  //iterator都是普通迭代器 为了满足const迭代器去构造普通迭代器typedef _RBTreeIterator<T, T&, T*> iterator;Node* _node;//迭代器结构体中存放的只有一个结点的成员变量//构造函数_RBTreeIterator(Node* node):_node(node){}//普通迭代器的时候,他是拷贝构造//const迭代器的时候,他是构造,支持用普通迭代器构造cosnt迭代器_RBTreeIterator(const iterator& s):_node(s._node){}// *就是解引用因此返回该结点的成员变量Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}//typedef _RBTreeIterator<T, Ref, Ptr> Self;//重载的是前置++Self& operator++(){//如果该结点的右不为空,那么++就是走到该结点右子树的最左结点if (_node->_right){Node* min = _node->_right;while (min->_left){min = min->_left;}_node = min;}//如果该结点的右为空,且本身是其父节点的左孩子//那么其父节点就是我们需要找的结点// //如果其本身是父节点的右孩子//那么将顺着根节点往上去找,直到找到其结点是父结点左孩子的结点//然后父结点就是我们需要找的结点else{Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_right == cur){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;//this结点其实就是本身}Self& operator--(){//如果该结点的左结点不为空,那么就去找左子树的最右结点if (_node->_left){Node* max = _node->_left;while (max->_right){max = max->_right;}_node = max;}//如果该结点的左结点为空//且该结点是父节点的右孩子,那么其父节点就是我们需要找的结点////如果该结点是父节点的左孩子,那么需要顺着根节点去找//结点是父节点的右孩子的结点//该父节点就是我们需要找的结点else{Node* cur = _node;Node* parent = cur->_parent;while (parent && parent->_left == cur){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}bool operator != (const Self& s) const{return _node != s._node;//其实_node为this._node只不过this省略了 本意就是返回自己的结点!=传入结构体的结点}bool operator == (const Self& s) const{return _node == s._node;//其实_node为this._node只不过this省略了 本意就是返回自己的结点==传入结构体的结点}};// map->RBTree<K, pair<const K,V>,MapKeyOfT> _t;
// set->RBTree<K, K,SetKeyOfT> _t;//增加一个KeyOfT是为了使用map的时候把pair中的key取出来
//T刚好是从map或者set传进来的VALUE map--pair<K,V>  set--K
template<class K, class T, class KeyOfT>
class RBTree
{typedef RBTreeNode<T> Node;
public:typedef _RBTreeIterator<T, T&, T*> iterator;typedef _RBTreeIterator<T, const T&, const T*> const_iterator;//提供这个普通迭代器版本是为了与map中的value能改动做照应//最左结点作为红黑树的beginiterator begin(){Node* left = _root;while (left && left->_left){left = left->_left;}return iterator(left);}//最右结点的右结点(即nullptr)作为红黑树的enditerator end(){return iterator(nullptr);}//const版本的  begin和end 迭代器const_iterator begin() const{Node* left = _root;while (left && left->_left){left = left->_left;}return const_iterator(left);}const_iterator end() const{return const_iterator(nullptr);}//如果这个值在,那么这个insert充当的就是查找我们就返回这个结点的迭代器//pair<iterator,bool> Insert(const T& data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return make_pair(iterator(_root),true);}//利用从map或者set中传过来的类定义一个kot对象//由于该类中重载了"()" 所以kot()其实就是调用了operator()函数//往kot()括号中传递参数就是给operator()()第二个括号里面传递参数KeyOfT kot;Node* parent = nullptr;Node* cur = _root;while (cur){if (kot(cur->_data) < kot(data)){parent = cur;cur = cur->_right;}else if (kot(cur->_data) > kot(data)){parent = cur;cur = cur->_left;}else{return make_pair(iterator(cur), false);;}}cur = new Node(data);Node* newnode = cur;cur->_col = RED;if (kot(parent->_data) < kot(data)){parent->_right = cur;cur->_parent = parent;}else{parent->_left = cur;cur->_parent = parent;}//调整while (parent && parent->_col == RED){Node* grandfater = parent->_parent;if (grandfater->_left == parent){Node* uncle = grandfater->_right;if (uncle && uncle->_col == RED){parent->_col = BLACK;uncle->_col = BLACK;grandfater->_col = RED;cur = grandfater;parent = cur->_parent;}else{if (cur == parent->_left)//无论是否有uncle 都这样旋转     //直线{RotateR(grandfater);parent->_col = BLACK;grandfater->_col = RED;}else{RotateL(parent);RotateR(grandfater);cur->_col = BLACK;grandfater->_col = RED;}break;}}else{Node* uncle = grandfater->_left;if (uncle && uncle->_col == RED){parent->_col = BLACK;uncle->_col = BLACK;grandfater->_col = RED;cur = grandfater;parent = cur->_parent;}else{if (cur == parent->_right)//无论是否有uncle 都这样旋转     //直线{RotateL(grandfater);parent->_col = BLACK;grandfater->_col = RED;}else{RotateR(parent);RotateL(grandfater);cur->_col = BLACK;grandfater->_col = RED;}break;}}}_root->_col = BLACK;return make_pair(iterator(newnode), true);;}void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;Node* ppNode = parent->_parent;subR->_left = parent;parent->_parent = subR;if (ppNode == nullptr){_root = subR;_root->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subR;}else{ppNode->_right = subR;}subR->_parent = ppNode;}}void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR){subLR->_parent = parent;}Node* ppNode = parent->_parent;subL->_right = parent;parent->_parent = subL;//if (_root == parent)if (ppNode == nullptr){_root = subL;_root->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subL;}else{ppNode->_right = subL;}subL->_parent = ppNode;}}void Inorder(){_Inorder(_root);}void _Inorder(Node* root){if (root == nullptr)return;_Inorder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_Inorder(root->_right);}bool Check(Node* root, int blackNum, const int ref){if (root == nullptr){//cout << blackNum << endl;if (blackNum != ref){cout << "违反规则:本条路径的黑色节点的数量跟最左路径不相等" << endl;return false;}return true;}if (root->_col == RED && root->_parent->_col == RED){cout << "违反规则:出现连续红色节点" << endl;return false;}if (root->_col == BLACK){++blackNum;}return Check(root->_left, blackNum, ref)&& Check(root->_right, blackNum, ref);}bool IsBalance(){if (_root == nullptr){return true;}if (_root->_col != BLACK){return false;}int ref = 0;Node* left = _root;while (left){if (left->_col == BLACK){++ref;}left = left->_left;}return Check(_root, 0, ref);}private:Node* _root = nullptr;
};template<class K>
struct SetKeyOfT
{const K& operator()(const K& key){return key;}
}; 
void testRBTree()
{//不能让普通迭代器给给const迭代器 因为这是权限的放大/*const RBTree<int, int, SetKeyOfT<int>> t;RBTree<int, int, SetKeyOfT<int>>::iterator it = t.begin();*///可以让const迭代器给给普通迭代器 因为这是权限的缩小RBTree<int, int, SetKeyOfT<int>> t;RBTree<int, int, SetKeyOfT<int>>::const_iterator it = t.begin();list<int>::iterator sit;list<int>::const_iterator cit = sit;}

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

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

相关文章

UE4 C++编写自定义动画蓝图节点

UE中自带的动画蓝图节点有限&#xff0c;在实现一些功能时需要通过C编写一些自定义的动画蓝图节点&#xff0c;本文就来讲解其基础实现&#xff0c;自定义节点最终效果如下&#xff1a; 源文件下载&#xff1a;https://download.csdn.net/download/grayrail/87654290 1.流程简…

linux 服务器 docker 安装 mysql 8.0.32 常用命令

我的Docker专栏 https://blog.csdn.net/weixin_45580378/category_12276045.html docker 镜像 https://registry.hub.docker.com/_/mysql/tags 1.版本号可不写 不写就是最新版本 最好写上 docker pull mysql:版本号2.查看镜像是否安装成功 如下图 docker images3.创建文件…

活动送票福利|Jina AI x PyCon US 2023!

作为一家总部位于德国柏林的国际化公司&#xff0c;Jina AI 拥有来自 10 不同国家的团队成员&#xff0c;在中国&#xff08;北京、深圳&#xff09;、美国&#xff08;圣何塞&#xff09;均设有办公室。全球化基因深植于 Jina AI 团队&#xff0c;我们也非常注重国际化社区的建…

shardingsphere-jdbc 整合 springboot

shardingsphere官网地址 https://shardingsphere.apache.org/document/5.2.0/cn/user-manual/shardingsphere-jdbc/spring-boot-starter/rules/sharding/ 当前我们演示的是水平分表 1、基础环境配置以及依赖管理 1.1 创建数据库表结构 CREATE TABLE address_0 (id bigint(…

linux 服务器 docker 安装 jdk jre java 1.8 环境 常用命令

我的Docker专栏 https://blog.csdn.net/weixin_45580378/category_12276045.html docker jdk 镜像 https://hub.docker.com/_/java/tags 1.下载JDK镜像 注&#xff1a;后面如果不写版本的话 就是最新版 建议写上 docker pull java:8u111-jdk2.查看镜像是否下载成功 docker…

家装产业的数字化,正在成为越来越多人的新共识

一场数字化的浪潮&#xff0c;正在各行各业上演着。家装行业&#xff0c;亦不例外。可以说&#xff0c;家装产业的数字化&#xff0c;正在成为越来越多人的新共识。如何借助数字化的手段改造家装行业&#xff0c;如何乘着数字化的东风实现家装行业的全面转型升级&#xff0c;正…

CF区间DP作业题解

1. Recovering BST 由于互质关系不是传递的&#xff0c;所以尽量挂在树的最下面&#xff0c;刚好构成二叉树 f[i][j][0]f[i][j][0]f[i][j][0] 表示区间 [i,j][i,j][i,j] 以 iii 为根&#xff0c;是否可以构成一棵树。 f[i][j][1]f[i][j][1]f[i][j][1] 表示区间 [i,j][i,j][i,j…

基于非线性权重因子和纵横交叉策略的麻雀搜索算法

目录 1 主要内容 非惯性权重模型 纵横交叉策略模型 2 部分程序 3 程序结果 4 程序链接 1 主要内容 该程序参考文献《基于Sobol序列和纵横交叉策略的麻雀搜索算法》对麻雀搜索算法进行改进&#xff0c;实现了基于纵横交叉策略和非线性权重因子的麻雀搜索算法 改进SSA算法【…

webpack配置本地TypeScript编译环境和开启本地服务

目录 1.创建一个文件夹 2.初始化一个package.json文件对我们安装包进行记录 3.安装webpack 4.配置webpack.config.js文件 1.创建一个文件夹 2.初始化一个package.json文件对我们安装包进行记录 执行npm init&#xff0c;文件命名为ts_demo&#xff0c;然后一直回车。 3.安装…

ImageIO 支持webp格式

TwelveMonkeys 提供了很多图片格式的支持&#xff0c;其中也包括了webp&#xff0c;但是其仅支持webp格式的读取&#xff0c;不支持webp格式的写出&#xff0c;这样的话如果想把图片转换成webp格式的图片就没办法实现了&#xff1b;下面我们使用 webp-imageio-core 对ImageIO图…

关键词采集工具可以帮助我们做那些方面的工作

针对搜索引擎的关键词采集工具可以帮助我们做那些方面的工作&#xff0c;至少从10个工作场景说明&#xff0c;并列举详细的使用场景 Msray-plus&#xff0c;是一款企业级综合性爬虫/采集软件。 支持亿级数据存储、导入、重复判断等。无需使用复杂的命令&#xff0c;提供本地W…

ROS实践01 C++ Python基本实现

文章目录运行环境&#xff1a;1.1 vscode 环境配置&#xff1a;1&#xff09;ctrlshiftX 添加扩展插件&#xff1a;2&#xff09;ctrlshiftB 配置中更换为以下代码1.2 C代码实现1&#xff09;工作空间创建和编译2&#xff09;功能包创建和添加依赖3&#xff09;新建.cpp文件4&a…

新电脑装机——配置硬件、软件安装卸载、注册表、路径——介绍详解

装机工具、配置、路径&#xff0c;介绍详解电脑配置信息电脑历史记录黑色Window Top 加入黑色&#xff08;微信不能调成黑色背景&#xff09;edge浏览器的配置&#xff08;被edge恶心过的必看&#xff0c;有方法解决edge被管理、不能新建标签&#xff09;设置【地址栏搜索】&am…

多元函数的基本概念——“高等数学”

各位CSDN的uu们你们好呀&#xff0c;今天&#xff0c;小雅兰的内容是多元函数的基本概念&#xff0c;下面&#xff0c;让我们一起进入多元函数的世界吧 平面点集 多元函数的概念 多元函数的极限 多元函数的连续性 有界闭区域上多元连续函数的性质 平面点集 第一个是坐标平…

RocketMQ 事务消息 详解

&#x1f34a; Java学习&#xff1a;Java从入门到精通总结 &#x1f34a; 深入浅出RocketMQ设计思想&#xff1a;深入浅出RocketMQ设计思想 &#x1f34a; 绝对不一样的职场干货&#xff1a;大厂最佳实践经验指南 &#x1f4c6; 最近更新&#xff1a;2023年4月9日 &#x1…

RSA非对称加密算法原理和代码实现 信息安全 密码学

一 欧拉数论定理 1. 欧拉函数 设n为一正整数&#xff0c;则欧拉函数φ(n)\varphi (n)φ(n)等于0∼n−10\sim n-10∼n−1中与n互素的整数个数 比如φ(5)4\varphi (5) 4φ(5)4&#xff0c;因为0~5中&#xff0c; 1,2,3,4均与5互素&#xff0c;即最大公约数为1 2. 欧拉定…

采集工具助力市场营销,让您的营销更加高效

随着市场竞争的日益激烈&#xff0c;企业的营销策略也在不断升级。而在这个信息爆炸的时代&#xff0c;采集数据成为了市场营销中不可或缺的一环。为了更好地服务客户&#xff0c;我们公司开发了一款高效、快捷的采集工具&#xff0c;为您的营销活动提供有力支持。 Msray-plus&…

计算机网络习题 | 第一章:计算机网络概述

文章目录概述1、以下关于OSI环境中数据传输的过程的描述中&#xff0c;错误的是&#xff08; &#xff09;2、以下关于广域网 WAN 特点的描述中 &#xff0c;错误的是&#xff08; &#xff09;3、以下关于计算机网络定义的描述中&#xff0c;错误的是&#xff08; &#xff09…

【分布式 论文】之 1. MapReduce——Simplified Data Processing on Large Clusters

文章目录1. 需求 / 现存问题2. 总述3. 实现3.1 概述1. 需求 / 现存问题 输入数据通常很大&#xff0c;为了在合理的时间内完成计算&#xff0c;必须将计算分布到数百或数千台机器上。 如何并行化计算、分发数据和处理故障等问题使得原本简单的计算变得晦涩难懂&#xff0c;需…

chatGPA的主要功能-chatGPT深度分析

ChatGPT功能介绍 ChatGPT是基于深度学习技术的自然语言处理算法&#xff0c;其主要用途是生成自然语言文本&#xff0c;能够应用于多个自然语言处理任务。以下是其主要功能介绍&#xff1a; 文本生成&#xff1a;ChatGPT能够生成高质量的自然语言文本&#xff0c;可以应用于大…