c++--Map和Set的简单封装

1.Map和Set的简单介绍

Map和set没有多大区别,它俩都是键值对容器,即该结构中一般只包含两个成员key,value,key代表键值,value表示与key对应的信息。并且这两个容器为树型结构的关联式容器,这两种容器的共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列。

Set的介绍:

  •  set是按照一定次序存储元素的容器。
  •  在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。
  • set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。
  • 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。
  • set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对子集进行直接迭代。
  • set在底层是用二叉搜索树(红黑树)实现的。

注意:

  • 与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放value,但在底层实际存放的是由<value, value>构成的键值对。
  • set中插入元素时,只需要插入value即可,不需要构造键值对。
  • set中的元素不可以重复(因此可以使用set进行去重)。
  • 使用set的迭代器遍历set中的元素,可以得到有序序列
  • set中的元素默认按照小于来比较
  • set中查找某个元素,时间复杂度为:$log_2 n$
  • set中的元素不允许修改
  • set中的底层使用二叉搜索树(红黑树)来实现

Map的介绍:

  • map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素。
  • 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型
  • value_type绑定在一起,为其取别名称为pair:
  • typedef pair<const key, T> value_type;
  • 在内部,map中的元素总是按照键值key进行比较排序的。
  • map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
  • map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
  •  map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。
     

2.Map和Set的实现

由于Map和Set的底层都为红黑树,所以Map和Set的实现通过对红黑树的封装来实现,Set为一个参数,Map为两个参数,所以通过改变模板来实现Map和Set的同时封装。

Set的简单封装:

namespace sss
{template<class K>class Set{struct SetKeyofT{const K& operator()(const K& date){return date;}};	public:typedef typename RedBlackTree<K, K, SetKeyofT>::iterator iterator;iterator begin(){return _S.begin();}iterator end(){return _S.end();}pair<iterator, bool> Insert(const K& date){return _S.insert(date);}private:RedBlackTree<K, K, SetKeyofT> _S;};//测试用例/*void text_set(){string str[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };Set<string> hash;for (auto sh : str){hash.Insert(sh);}auto it = hash.begin();while (it != hash.end()){cout << *it << endl;++it;}}*/}

Map的简单封装

namespace sss
{template<class K,class V> class Map{public:struct MapKeyofT{const K& operator()(const pair<K, V>& date){return date.first;}};typedef typename RedBlackTree<K, pair<K, V>, MapKeyofT>::iterator iterator;//t//ypedef RedBlackTree<K, pair<K, V>, MapKeyofT> RedBlackTree;iterator begin()  {return _T.begin();}iterator end(){return _T.end();}pair<iterator, bool> Insert(const pair<K,V>& date){return _T.insert(date);}V& operator[](const K& key){pair<iterator, bool> ret = Insert(make_pair(key, V()));return ret.first->second;}private:RedBlackTree<K,pair<K,V>, MapKeyofT> _T;};//测试用例//void text_map()//{//	Map<int, int> hash1;//	hash1.Insert(make_pair(1,1));//	cout<<hash1[1];//	Map<string, int> hash2;//	string str[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };//	for (auto sh:str)//	{//		hash2[sh]++;//	}//	Map<string, int>::iterator it = hash2.begin();//	while (it != hash2.end())//	{//		cout << it->first << ":" << it->second << endl;//		++it;//	}//	for (auto& kv : hash2)//	{//		cout << kv.first << ":" << kv.second << endl;//	}//	//hash1 = hash2;//	//}
}

底层实现:

namespace sss
{enum Color{red,black};template<class T>struct RedBlackTreeNode{RedBlackTreeNode<T>* _left;RedBlackTreeNode<T>* _right;RedBlackTreeNode<T>* _parent;//pair<K, V> _date;T _date;Color _col;RedBlackTreeNode(const T& date=T()):_left(nullptr),_right(nullptr),_parent(nullptr),_date(date)//, _col(black){}};template<class T, class Ref, class Ptr>struct __RBTreeIterator{typedef RedBlackTreeNode<T> Node;typedef __RBTreeIterator<T, Ref, Ptr> Self;Node* _node;__RBTreeIterator(Node* node):_node(node){}Ref operator*(){return _node->_date;}Ptr operator->(){return &_node->_date;}bool operator!=(const Self& _t){return _node != _t._node;}bool operator==(const Self& _t){return _node == _t._node;}Self* operator++(){if (_node->_right){Node* cur = _node;cur = cur->_right;while (cur->_left){cur = cur->_left;}_node=cur;}else{Node* parent = _node->_parent;Node* cur = _node;while (parent && cur == parent->_right){cur = cur->_parent;parent = parent->_parent;}_node=parent;}return this;}Self* operator--(){if (_node->_left){Node* cur = _node;cur = cur->_left;while (cur->_right){cur = cur->_right;}_node=cur;}else{Node* parent = _node->_parent;Node* cur = _node;while (parent && cur == parent->left){parent = parent->_parent;cur = parent;}_node= parent;}return this;}};template<class K, class T, class KeyofT>class RedBlackTree{typedef RedBlackTreeNode<T> Node;public:		typedef __RBTreeIterator<T, T&, T*> iterator;iterator begin(){Node* left = _root;while (left && left->_left){left = left->_left;}return iterator(left);}iterator end(){return iterator(nullptr);}//插入pair<iterator,bool> insert(const T& date){KeyofT _com;if (_root == nullptr){_root = new Node(date);_root->_col = black;return make_pair(iterator(_root), true);}Node* parent = nullptr;Node* cur = _root;while (cur){if (_com(cur->_date)< _com(date)){parent = cur;cur = cur->_right;}else if (_com(cur->_date) > _com(date)){parent = cur;cur = cur->_left;}else{return make_pair(iterator(cur), false);}}cur = new Node(date);cur->_col = red;if (_com(parent->_date)  < _com(date)){parent->_right = cur;}else {parent->_left = cur;}cur->_parent = parent;//Node* uncle=parent->_parent->while(parent && parent->_col == red){Node* grandfater = parent->_parent;assert(grandfater);assert(grandfater->_col==black);if (parent == grandfater->_left){Node* uncle = grandfater->_right;// 情况一 : uncle存在且为红,变色+继续往上处理if (uncle && uncle->_col == red){parent->_col = uncle->_col = black;grandfater->_col = red;// 继续往上处理cur = grandfater;parent = cur->_parent;}// 情况二+三:uncle不存在 + 存在且为黑else{// 情况二:右单旋+变色//     g //   p   u// cif (cur == parent->_left){RotateR(grandfater);parent->_col = black;grandfater->_col = red;}else{// 情况三:左右单旋+变色//     g //   p   u//     cRotateL(parent);RotateR(grandfater);cur->_col = black;grandfater->_col = red;}break;}}else{Node* uncle = grandfater->_left;// 情况一if (uncle && uncle->_col == red){parent->_col = uncle->_col = black;grandfater->_col = red;// 继续往上处理cur = grandfater;parent = cur->_parent;}else{// 情况二:左单旋+变色//     g //   u   p//         cif (cur == parent->_right){RotateL(grandfater);parent->_col = black;grandfater->_col = red;}else{// 情况三:右左单旋+变色//     g //   u   p//     cRotateR(parent);RotateL(grandfater);cur->_col = black;grandfater->_col = red;}break;}}}_root->_col = black;return make_pair(iterator(cur), true);}void Inorder(){_Inorder(_root);}private://右旋void RotateR(Node* parent){Node* subl = parent->_left;Node* sublr = subl->_right;Node* prev = parent->_parent;parent->_left = sublr;if (sublr)sublr->_parent = parent;parent->_parent = subl;subl->_right = parent;if (_root == parent){_root = subl;subl->_parent = nullptr;}else{if (prev->_left == parent){subl->_parent = prev;prev->_left = subl;}else{subl->_parent = prev;prev->_right = subl;}}}//左旋void RotateL(Node* parent){Node* subr = parent->_right;Node* subrl = subr->_left;Node* prev = parent->_parent;parent->_right = subrl;if (subrl)subrl->_parent = parent;subr->_left = parent;parent->_parent = subr;if (_root == parent){_root = subr;subr->_parent = nullptr;}else{if (prev->_left == parent){subr->_parent = prev;prev->_left = subr;}else{subr->_parent = prev;prev->_right = subr;}}}//遍历void _Inorder(Node* _root){if (_root == nullptr)return;_Inorder(_root->_left);cout << _root->_date.first << " " << _root->_date.second << endl;_Inorder(_root->_right);}private:Node* _root = nullptr;};}

完整代码:

//在不同平台下需加不同头文件
#pragma once
using namespace std;
#include <iostream>
#include <assert.h>
#include "RedBlackTree.h"
#include <string>namespace sss
{template<class K>class Set{struct SetKeyofT{const K& operator()(const K& date){return date;}};	public:typedef typename RedBlackTree<K, K, SetKeyofT>::iterator iterator;iterator begin(){return _S.begin();}iterator end(){return _S.end();}pair<iterator, bool> Insert(const K& date){return _S.insert(date);}private:RedBlackTree<K, K, SetKeyofT> _S;};//测试用例/*void text_set(){string str[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };Set<string> hash;for (auto sh : str){hash.Insert(sh);}auto it = hash.begin();while (it != hash.end()){cout << *it << endl;++it;}}*/}namespace sss
{template<class K,class V> class Map{public:struct MapKeyofT{const K& operator()(const pair<K, V>& date){return date.first;}};typedef typename RedBlackTree<K, pair<K, V>, MapKeyofT>::iterator iterator;//t//ypedef RedBlackTree<K, pair<K, V>, MapKeyofT> RedBlackTree;iterator begin()  {return _T.begin();}iterator end(){return _T.end();}pair<iterator, bool> Insert(const pair<K,V>& date){return _T.insert(date);}V& operator[](const K& key){pair<iterator, bool> ret = Insert(make_pair(key, V()));return ret.first->second;}private:RedBlackTree<K,pair<K,V>, MapKeyofT> _T;};//测试用例//void text_map()//{//	Map<int, int> hash1;//	hash1.Insert(make_pair(1,1));//	cout<<hash1[1];//	Map<string, int> hash2;//	string str[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };//	for (auto sh:str)//	{//		hash2[sh]++;//	}//	Map<string, int>::iterator it = hash2.begin();//	while (it != hash2.end())//	{//		cout << it->first << ":" << it->second << endl;//		++it;//	}//	for (auto& kv : hash2)//	{//		cout << kv.first << ":" << kv.second << endl;//	}//	//hash1 = hash2;//	//}
}namespace sss
{enum Color{red,black};template<class T>struct RedBlackTreeNode{RedBlackTreeNode<T>* _left;RedBlackTreeNode<T>* _right;RedBlackTreeNode<T>* _parent;//pair<K, V> _date;T _date;Color _col;RedBlackTreeNode(const T& date=T()):_left(nullptr),_right(nullptr),_parent(nullptr),_date(date)//, _col(black){}};template<class T, class Ref, class Ptr>struct __RBTreeIterator{typedef RedBlackTreeNode<T> Node;typedef __RBTreeIterator<T, Ref, Ptr> Self;Node* _node;__RBTreeIterator(Node* node):_node(node){}Ref operator*(){return _node->_date;}Ptr operator->(){return &_node->_date;}bool operator!=(const Self& _t){return _node != _t._node;}bool operator==(const Self& _t){return _node == _t._node;}Self* operator++(){if (_node->_right){Node* cur = _node;cur = cur->_right;while (cur->_left){cur = cur->_left;}_node=cur;}else{Node* parent = _node->_parent;Node* cur = _node;while (parent && cur == parent->_right){cur = cur->_parent;parent = parent->_parent;}_node=parent;}return this;}Self* operator--(){if (_node->_left){Node* cur = _node;cur = cur->_left;while (cur->_right){cur = cur->_right;}_node=cur;}else{Node* parent = _node->_parent;Node* cur = _node;while (parent && cur == parent->left){parent = parent->_parent;cur = parent;}_node= parent;}return this;}};template<class K, class T, class KeyofT>class RedBlackTree{typedef RedBlackTreeNode<T> Node;public:		typedef __RBTreeIterator<T, T&, T*> iterator;iterator begin(){Node* left = _root;while (left && left->_left){left = left->_left;}return iterator(left);}iterator end(){return iterator(nullptr);}//插入pair<iterator,bool> insert(const T& date){KeyofT _com;if (_root == nullptr){_root = new Node(date);_root->_col = black;return make_pair(iterator(_root), true);}Node* parent = nullptr;Node* cur = _root;while (cur){if (_com(cur->_date)< _com(date)){parent = cur;cur = cur->_right;}else if (_com(cur->_date) > _com(date)){parent = cur;cur = cur->_left;}else{return make_pair(iterator(cur), false);}}cur = new Node(date);cur->_col = red;if (_com(parent->_date)  < _com(date)){parent->_right = cur;}else {parent->_left = cur;}cur->_parent = parent;//Node* uncle=parent->_parent->while(parent && parent->_col == red){Node* grandfater = parent->_parent;assert(grandfater);assert(grandfater->_col==black);if (parent == grandfater->_left){Node* uncle = grandfater->_right;// 情况一 : uncle存在且为红,变色+继续往上处理if (uncle && uncle->_col == red){parent->_col = uncle->_col = black;grandfater->_col = red;// 继续往上处理cur = grandfater;parent = cur->_parent;}// 情况二+三:uncle不存在 + 存在且为黑else{// 情况二:右单旋+变色//     g //   p   u// cif (cur == parent->_left){RotateR(grandfater);parent->_col = black;grandfater->_col = red;}else{// 情况三:左右单旋+变色//     g //   p   u//     cRotateL(parent);RotateR(grandfater);cur->_col = black;grandfater->_col = red;}break;}}else{Node* uncle = grandfater->_left;// 情况一if (uncle && uncle->_col == red){parent->_col = uncle->_col = black;grandfater->_col = red;// 继续往上处理cur = grandfater;parent = cur->_parent;}else{// 情况二:左单旋+变色//     g //   u   p//         cif (cur == parent->_right){RotateL(grandfater);parent->_col = black;grandfater->_col = red;}else{// 情况三:右左单旋+变色//     g //   u   p//     cRotateR(parent);RotateL(grandfater);cur->_col = black;grandfater->_col = red;}break;}}}_root->_col = black;return make_pair(iterator(cur), true);}void Inorder(){_Inorder(_root);}private://右旋void RotateR(Node* parent){Node* subl = parent->_left;Node* sublr = subl->_right;Node* prev = parent->_parent;parent->_left = sublr;if (sublr)sublr->_parent = parent;parent->_parent = subl;subl->_right = parent;if (_root == parent){_root = subl;subl->_parent = nullptr;}else{if (prev->_left == parent){subl->_parent = prev;prev->_left = subl;}else{subl->_parent = prev;prev->_right = subl;}}}//左旋void RotateL(Node* parent){Node* subr = parent->_right;Node* subrl = subr->_left;Node* prev = parent->_parent;parent->_right = subrl;if (subrl)subrl->_parent = parent;subr->_left = parent;parent->_parent = subr;if (_root == parent){_root = subr;subr->_parent = nullptr;}else{if (prev->_left == parent){subr->_parent = prev;prev->_left = subr;}else{subr->_parent = prev;prev->_right = subr;}}}//遍历void _Inorder(Node* _root){if (_root == nullptr)return;_Inorder(_root->_left);cout << _root->_date.first << " " << _root->_date.second << endl;_Inorder(_root->_right);}private:Node* _root = nullptr;};}

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

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

相关文章

docker基础

本地安装 ①卸载旧版 sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine podman runc 保证虚机无安装包冲突 ②在新主机上首次安装 Docker 引擎之前&#xff0c;您需…

运行flutter doctor命令窗口直接闪退

在cmd中输入flutter doctor后闪退了。 使用高速摄像机可以看到报错信息。 报错信息的意思是git的文件夹不能删掉&#xff0c;请保留flutter中git文件。

[机器学习]特征工程:主成分分析

目录 主成分分析 1、简介 2、帮助理解 3、API调用 4、案例 本文介绍主成分分析的概述以及python如何实现算法&#xff0c;关于主成分分析算法数学原理讲解的文章&#xff0c;请看这一篇&#xff1a; 探究主成分分析方法数学原理_逐梦苍穹的博客-CSDN博客https://blog.csdn.…

css 实现电梯导航

实现原理&#xff1a;利用css实现电梯导航很简单&#xff0c;基本原理就是通过a标签绑定跳转目标的id来实现的 html代码&#xff1a; <div class"body"><div class"top" id"top"></div><div class"con1" id"…

线性代数的学习和整理5: 矩阵的加减乘除及其几何意义(未完成,建设ing)

目录 1 矩阵加法 1.1 矩阵加法的定义 1.2 加法的属性 1.2.1 只有同类型&#xff0c;相同n*m的矩阵才可以相加 1.2.1 矩阵加法的可交换律&#xff1a; 1.2.2 矩阵加法的可结合律&#xff1a; 1.3矩阵加法的几何意义 2 矩阵的减法 2.1 矩阵减法定义和原理基本同 矩阵的…

【C++】extern

目录 1. 变量声明和定义的关系 2. 默认状态下&#xff0c;const对象仅在文件内有效 3. 链接指示&#xff1a;extern "C" 3.1 声明一个非C的函数 3.2 链接指示与头文件 3.3 指向extern "C"函数的指针 3.4 链接指示对整个声明都有效 3.5 导出C函数到…

Linux命令200例:tail用来显示文件的末尾内容(常用)

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌。CSDN专家博主&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &…

HCIP之VLAN实验

目录 一、实验题目 二、实验思路 三、实验步骤 3.1 将接口划入vlan&#xff0c;设置trunk干道 3.2 启动DHCP服务&#xff0c;下发地址 四、测试 一、实验题目 实验要求&#xff1a; 1&#xff0c;PC1/3的接口均为access模式&#xff0c;且属于vlan2&#xff0c;处于同一…

Flink的Standalone集群部署

在上篇进行单机的Standalone部署-Flink的Standalone部署实战&#xff0c;本篇介绍Flink的Standalone集群部署。 Flink集群为主从架构&#xff0c;主是JobManager&#xff0c;从为TaskManager&#xff0c;支持一主多从。 本次搭建环境为3台机器&#xff0c;信息如下表所示。 IP…

NLP中的RNN、Seq2Seq与attention注意力机制

目录 NLP自然语言处理 的RNN、Seq2Seq与attention注意力机制 RNN循环神经网络 前馈网络入门 前馈网络 循环网络 多层感知器架构示例 循环神经网络的运作原理 展开 RNN seq2seq模型 Attention&#xff08;注意力机制&#xff09; 总结 引用 NLP自然语言处理 的RNN、…

Ubuntu20.04搭建OpenGL环境(glfw+glad)

Ubuntu20.04搭建OpenGL环境(glfwglad) Linux环境搭建 本文在VMware安装Ubuntu20.04桌面版的环境下搭建OpenGL&#xff0c;按照本文搭建完成后可以执行LearnOpenGL网站上的demo。 关于VMware可自行到VMware Workstation Pro | CN下载 关于Ubuntu20.04桌面版可自行到官网或In…

轮腿机器人的PID控制

1 PID介绍 PID&#xff08;Proportional Integral Derivative&#xff09;控制系统。其实质是根据输入的偏差值&#xff0c;按比例、积分、微分的函数关系进行运算&#xff0c;运算结果用以输出进行控制。它是在长期的工程实践中总结出来的一套控制方法&#xff0c;实际运行经…

【C++】做一个飞机空战小游戏(十一)——游戏过关、通关、结束的设置

[导读]本系列博文内容链接如下&#xff1a; 【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动【C】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动 【C】做一个飞…

STM32F4X USART串口使用

STM32F4X USART串口使用 串口概念起始位波特率数据位停止位校验位串口间接线 STM32F4串口使用步骤GPIO引脚复用函数串口初始化函数串口例程 串口概念 串口是MCU与外部通信的重要通信接口&#xff0c;也是MCU在开发过程中的调试利器。串口通信有几个重要的参数&#xff0c;分别…

【Linux】进程信号篇Ⅰ:信号的产生(signal、kill、raise、abort、alarm)、信号的保存(core dump)

文章目录 一、 signal 函数&#xff1a;用户自定义捕捉信号二、信号的产生1. 通过中断按键产生信号2. 调用系统函数向进程发信号2.1 kill 函数&#xff1a;给任意进程发送任意信号2.2 raise 函数&#xff1a;给调用进程发送任意信号2.3 abort 函数&#xff1a;给调用进程发送 6…

CloudQuery:更好地管理你的 OceanBase 数据库

前言&#xff1a;作为 OceanBase 的生态合作伙伴&#xff0c;CloudQuery&#xff08;简称“CQ”&#xff09; 最新发布的社区版 2.2.0 新增了 OceanBase 数据库&#xff0c;为企业使用 OceanBase 数据库提供全面的支持。包括连接与认证、查询与分析、数据安全与权限管理&#x…

perl下载与安装教程【工具使用】

Perl是一个高阶程式语言&#xff0c;由 Larry Wall和其他许多人所写&#xff0c;融合了许多语言的特性。它主要是由无所不在的 C语言&#xff0c;其次由 sed、awk&#xff0c;UNIX shell 和至少十数种其他的工具和语言所演化而来。Perl对 process、档案&#xff0c;和文字有很强…

深度探索ChatGPT:如何进行专业提问以获取精确答案

ChatGPT&#xff0c;作为OpenAI的先锋&#xff0c;已经展示出其惊人的交流和理解能力。但如何才能充分利用其潜能&#xff0c;并与之进行更深入、更专业的交流呢? 下面&#xff0c;我们将从专业的角度探讨一些提问策略&#xff0c;并附上实际案例&#xff0c;让你更加熟练地与…

单片机模块化编程文件创建流程

一、在工程文件夹下创建一个新的文件夹&#xff0c;命名为“ModulesCodesFiles”&#xff0c;译为“模块化代码文件”&#xff0c;用于存放所有模块化代码文件。 二、在“ModulesCodesFiles”文件夹下为每个模块创建一个新的文件夹&#xff0c;命名为模块的名称&#xff0c;例…

Gin+微服务实现抖音视频上传到七牛云

文章目录 安装获取凭证Gin处理微服务处理 如果你对Gin和微服务有一定了解&#xff0c;看本文较容易。 安装 执行命令&#xff1a; go get github.com/qiniu/go-sdk/v7获取凭证 Go SDK 的所有的功能&#xff0c;都需要合法的授权。授权凭证的签算需要七牛账号下的一对有效的A…