容器库(10)-std::unordered_set

unordered_set是以key为元素无序的关联容器,搜索、移除和插入操作是平均常数的时间复杂度。unordered_set在内部没有按任何顺序排列,而是放在桶当中的,放进哪个桶是通过计算key的hash值来决定的。

template<class Key,class Hash = std::hash<Key>,class KeyEqual = std::equal_to<Key>,class Allocator = std::allocator<Key>
> class unordered_set;

本文章的代码库:

https://gitee.com/gamestorm577/CppStd

成员函数

构造、析构和赋值

构造函数

可以构造一个空的unordered_set,也可以用迭代器、另一个unordered_set或者元素列表来构造一个unordered_set。构造的时候还可以指定最小桶数、hash函数、比较函数或者分配器。代码示例:

std::vector<int> tmp{1, 2, 3, 4};std::unordered_set<int> s1;
std::unordered_set<int> s2(tmp.begin(), tmp.end());
std::unordered_set<int> s3(s2);
std::unordered_set<int> s4{1, 2, 3};std::cout << "s1 size = " << s1.size() << std::endl;
std::cout << "s2 size = " << s2.size() << std::endl;
std::cout << "s3 size = " << s3.size() << std::endl;
std::cout << "s4 size = " << s4.size() << std::endl;

输出结果:

s1 size = 0
s2 size = 4
s3 size = 4
s4 size = 3

对于自定义的类型,需要定义hash函数以及比较函数。代码示例:

struct MyStruct
{int Num1;double Num2;
};struct MyHash
{std::size_t operator()(const MyStruct& val) const{return std::hash<int>()(val.Num1) + std::hash<double>()(val.Num2);}
};struct MyEqual
{bool operator()(const MyStruct& lhs, const MyStruct& rhs) const{return true;}
};std::unordered_set<MyStruct, MyHash, MyEqual> s;

析构函数

销毁unordered_set时,会调用各元素的析构函数。代码示例:

struct MyStruct
{MyStruct(int i): Num(i){}~MyStruct(){std::cout << "destruct, Num = " << Num << std::endl;}int Num = 0;
};struct MyHash
{std::size_t operator()(const MyStruct& val) const{return std::hash<int>()(val.Num);}
};struct MyEqual
{bool operator()(const MyStruct& lhs, const MyStruct& rhs) const{return lhs.Num == rhs.Num;}
};std::unordered_set<MyStruct, MyHash, MyEqual> s{1, 2, 3};
std::cout << "end" << std::endl;

输出结果:

destruct, Num = 3
destruct, Num = 2
destruct, Num = 1
end
destruct, Num = 3
destruct, Num = 2
destruct, Num = 1

赋值函数

可以用另一个unordered_set或者元素列表给unordered_set赋值。代码示例:

std::unordered_set<int> tmp{1, 2, 3};
std::unordered_set<int> s1;
std::unordered_set<int> s2;
s1 = tmp;
s2 = {1, 2, 3, 4};
std::cout << "s1 size = " << s1.size() << std::endl;
std::cout << "s2 size = " << s2.size() << std::endl;

输出结果:

s1 size = 3
s2 size = 4

迭代器

接口begin、cbegin指向unordered_set起始的迭代器,end、cend指向末尾的迭代器。无论什么迭代器都不能修改元素的值。代码示例:

std::unordered_set<int> s{1, 2, 3};
for (auto iter = s.begin(); iter != s.end(); ++iter)
{std::cout << "num = " << *iter << std::endl;
}

输出结果:

num = 3
num = 2
num = 1

容量

empty

检查unordered_set是否为空。代码示例:

std::unordered_set<int> s1{1, 2, 3};
std::unordered_set<int> s2;
std::cout << std::boolalpha;
std::cout << "s1 empty: " << s1.empty() << std::endl;
std::cout << "s2 empty: " << s2.empty() << std::endl;

输出结果:

s1 empty: false
s2 empty: true

size

获取unordered_set的元素个数。代码示例:

std::unordered_set<int> s1{1, 2, 3};
std::unordered_set<int> s2;
std::cout << "s1 size: " << s1.size() << std::endl;
std::cout << "s2 size: " << s2.size() << std::endl;

输出结果:

s1 size: 3
s2 size: 0

max_size

返回可以容纳的最大元素个数。代码示例:

std::unordered_set<char> s1;
std::unordered_set<std::string> s2;
std::cout << "s1 max size = " << s1.max_size() << std::endl;
std::cout << "s2 max size = " << s2.max_size() << std::endl;

输出结果:

s1 max size = 768614336404564650
s2 max size = 461168601842738790

修改器

clear

清除所有的元素。代码示例:

std::unordered_set<int> s{1, 2, 3, 4};
std::cout << "s size = " << s.size() << std::endl;
s.clear();
std::cout << "s size = " << s.size() << std::endl;

输出结果:

s size = 4
s size = 0

insert

插入元素,参数可以是元素、迭代器或者元素节点。代码示例:

std::unordered_set<int> m;m.insert(1);
m.insert(2);
std::cout << "m size = " << m.size() << std::endl;std::vector<int> tmp{3, 4};
m.insert(tmp.begin(), tmp.end());
std::cout << "m size = " << m.size() << std::endl;

输出结果:

m size = 2
m size = 4

emplace

构造一个元素到unordered_set中。代码示例:

struct MyStruct
{MyStruct(int num1, int num2): Num1(num1), Num2(num2){std::cout << "construct: " << num1 << " " << num2 << std::endl;}int Num1 = 0;int Num2 = 0;
};struct MyHash
{std::size_t operator()(const MyStruct& val) const{return std::hash<int>()(val.Num1) + std::hash<int>()(val.Num2);}
};struct MyEqual
{bool operator()(const MyStruct& lhs, const MyStruct& rhs) const{return (lhs.Num1 == rhs.Num1) && (lhs.Num2 == rhs.Num2);}
};std::unordered_set<MyStruct, MyHash, MyEqual> s;
s.emplace(1, 2);
s.emplace(3, 4);

输出结果:

construct: 1 2
construct: 3 4

emplace_hint

向unordered_set中尽可能靠近hint之前的位置插入新元素:

template <class... Args>
iterator emplace_hint(const_iterator hint, Args&&... args);

不同的hint会导致插入元素的效率不同。代码示例:

auto timer = [](std::function<std::size_t()> func, std::string tag) -> void
{auto start = std::chrono::system_clock::now();std::size_t size = func();auto end = std::chrono::system_clock::now();std::chrono::duration<double, std::milli> time = end - start;std::cout << tag << ", size: " << size << ", use time: " << time.count()<< std::endl;
};const int count = 3000000;auto unordered_set_emplace = [=]() -> std::size_t
{std::unordered_set<int> m;for (int i = 0; i < count; ++i){m.emplace(i);}return m.size();
};auto unordered_set_emplace_hint1 = [=]() -> std::size_t
{std::unordered_set<int> m;auto iter = m.begin();for (int i = 0; i < count; ++i){m.emplace_hint(iter, i);iter = m.end();}return m.size();
};auto unordered_set_emplace_hint2 = [=]() -> std::size_t
{std::unordered_set<int> m;auto iter = m.begin();for (int i = 0; i < count; ++i){m.emplace_hint(iter, i);iter = m.begin();}return m.size();
};auto unordered_set_emplace_hint3 = [=]() -> std::size_t
{std::unordered_set<int> m;auto iter = m.begin();for (int i = 0; i < count; ++i){iter = m.emplace_hint(iter, i);}return m.size();
};timer(unordered_set_emplace, "unordered_set_emplace");
timer(unordered_set_emplace_hint1, "unordered_set_emplace_hint1");
timer(unordered_set_emplace_hint2, "unordered_set_emplace_hint2");
timer(unordered_set_emplace_hint3, "unordered_set_emplace_hint3");

输出结果:

unordered_set_emplace, size: 3000000, use time: 490.632
unordered_set_emplace_hint1, size: 3000000, use time: 492.086
unordered_set_emplace_hint2, size: 3000000, use time: 508.571
unordered_set_emplace_hint3, size: 3000000, use time: 457.981

erase

移除指定位置的元素或者移除指定的值。代码示例:

std::unordered_set<int> s{1, 2, 3, 4, 5, 6, 7, 8, 9};
std::cout << "s size = " << s.size() << std::endl;
s.erase(s.begin());
std::cout << "s size = " << s.size() << std::endl;
s.erase(s.begin(), std::next(s.begin(), 3));
std::cout << "s size = " << s.size() << std::endl;
s.erase(*s.begin());
std::cout << "s size = " << s.size() << std::endl;

输出结果:

s size = 9
s size = 8
s size = 5
s size = 4

swap

和另一个unordered_set交换元素内容。代码示例:

std::unordered_set<int> s1{1, 2, 3, 4};
std::unordered_set<int> s2{1, 2};
s1.swap(s2);
std::cout << "s1 size = " << s1.size() << std::endl;
std::cout << "s2 size = " << s2.size() << std::endl;

输出结果:

s1 size = 2
s2 size = 4

extract

提取unordered_set中的某个元素节点,提取后unordered_set不再拥有该元素。代码示例:

std::unordered_set<int> s{1, 2, 3, 4, 5, 6, 7, 8, 9};
auto node1 = s.extract(1);
std::cout << "s size = " << s.size() << std::endl;
auto node2 = s.extract(s.begin());
std::cout << "s size = " << s.size() << ", node2 = " << node2.value() << std::endl;
s.insert(std::move(node2));
std::cout << "s size = " << s.size() << std::endl;

输出结果:

s size = 8
s size = 7, node2 = 9
s size = 8

merge

合并另一个unordered_set或者unordered_multiset中的元素。代码示例:

std::unordered_set<int> s1{1, 2, 3};
std::unordered_set<int> s2{3, 4};
s1.merge(s2);
std::cout << "s1 size = " << s1.size() << std::endl;

输出结果:

s1 size = 4

查找

count

获取给定key值的元素数量。由于unordered_set的元素是不重复的,结果只能是0或者1。代码示例:

std::unordered_set<int> s{1, 2, 3};
std::cout << "elment 1 count = " << s.count(1) << std::endl;
std::cout << "elment 3 count = " << s.count(4) << std::endl;

输出结果:

elment 1 count = 1
elment 3 count = 0

find

获取指定key值的元素的迭代器。代码示例:

std::unordered_set<int> s{1, 2, 3};
auto iter1 = s.find(1);
auto iter2 = s.find(4);
std::cout << std::boolalpha;
std::cout << "elment has 1: " << (iter1 == s.end()) << std::endl;
std::cout << "elment has 3: " << (iter2 == s.end()) << std::endl;

输出结果:

elment has 1: false
elment has 3: true

contains

检查是否包含特定的元素。代码示例:

std::unordered_set<int> s{1, 2, 3};
std::cout << std::boolalpha;
std::cout << "contain 1: " << s.contains(1) << std::endl;
std::cout << "contain 3: " << s.contains(4) << std::endl;

输出结果:

contain 1: true
contain 3: false

equal_range

获取容器中等于给定key值的元素范围。返回第一个迭代器指向范围的首元素,第二个迭代器指向范围的最后一个元素。代码示例:

std::unordered_set<int> s{1, 2, 3, 4, 5, 6, 7, 8};
for (auto item : s)
{std::cout << item << " ";
}
std::cout << std::endl;auto [iter1, iter2] = s.equal_range(3);
std::cout << "iter1 = " << *iter1 << std::endl;
std::cout << "iter2 = " << *iter2 << std::endl;

输出结果:

8 7 6 5 4 3 2 1 
iter1 = 3
iter2 = 2

桶接口

bucket_count

返回unordered_set的桶数量。代码示例:

std::unordered_set<int> s{1, 2, 3, 4, 5, 6, 7, 8};
std::cout << "bucket count = " << s.bucket_count() << std::endl;

输出结果:

bucket count = 11

max_bucket_count

返回unordered_set可以容纳的最大桶数量。代码示例:

std::unordered_set<int> s;
std::cout << "max bucket count = " << s.max_bucket_count() << std::endl;

输出结果:

max bucket count = 768614336404564650

bucket_size

范围特定桶中的元素数量。代码示例:

std::unordered_set<int> s{1, 2, 3, 4, 5, 6, 7, 8};
for (int i = 0; i < s.bucket_count(); ++i)
{std::cout << "bucket " << i << " has item num " << s.bucket_size(i)<< std::endl;
}

输出结果:

bucket 0 has item num 0
bucket 1 has item num 1
bucket 2 has item num 1
bucket 3 has item num 1
bucket 4 has item num 1
bucket 5 has item num 1
bucket 6 has item num 1
bucket 7 has item num 1
bucket 8 has item num 1
bucket 9 has item num 0
bucket 10 has item num 0

bucket

返回给定key值的元素所在桶的索引。代码示例:

std::unordered_set<int> s{11, 12, 13, 14, 15, 16, 17, 18};
auto n = s.bucket(13);
std::cout << "item 13 is in bucket " << n << std::endl;

输出结果:

item 13 is in bucket 2

begin、cbegin、end、cend

begin和cbegin返回索引为n的桶中的首个元素的迭代器。end和cend返回索引为n的桶中的末尾迭代器。代码示例:

std::unordered_set<int> s{11, 12, 13, 14};
auto cnt = s.bucket(13);
auto iter_begin = s.begin(cnt);
auto iter_end = s.end(cnt);
for (auto iter = iter_begin; iter != iter_end; ++iter)
{std::cout << "num = " << *iter << std::endl;
}

输出结果:

num = 13

散列策略

load_factor

返回每个桶的平均元素数量。代码示例:

std::unordered_set<int> s{11, 12, 13, 14};
float num = s.load_factor();
std::cout << "load factor is: " << num << std::endl;

输出结果:

load factor is: 0.8

max_load_factor

没有参数的情况下返回最大平均桶数。参数为float类型时设置平均最大桶数,如果超出了该数量,容器就会自己增加桶数。代码示例:

int n_count = 200;std::unordered_set<int> s1;
s1.max_load_factor(1);
for (int i = 0; i < n_count; ++i)
{s1.insert(i);
}
std::cout << "s1 max load factor is: " << s1.max_load_factor() << std::endl;
std::cout << "s1 bucket count: " << s1.bucket_count() << std::endl;std::unordered_set<int> s2;
s2.max_load_factor(20);
for (int i = 0; i < n_count; ++i)
{s2.insert(i);
}
std::cout << "s2 max load factor is: " << s2.max_load_factor() << std::endl;
std::cout << "s2 bucket count: " << s2.bucket_count() << std::endl;

输出结果:

s1 max load factor is: 1
s1 bucket count: 397
s2 max load factor is: 20
s2 bucket count: 11

rehash

设置桶的最小数量并重新散列容器。代码示例:

std::unordered_set<int> s;
for (int i = 0; i < 200; ++i)
{s.insert(i);
}std::cout << "bucket cnt: " << s.bucket_count() << std::endl;
s.rehash(s.bucket_count() / 2);
std::cout << "bucket cnt: " << s.bucket_count() << std::endl;
s.rehash(s.bucket_count() * 4);
std::cout << "bucket cnt: " << s.bucket_count() << std::endl;

输出结果:

bucket cnt: 397
bucket cnt: 211
bucket cnt: 853

reserve

设置桶的最小元素个数,并重新散列容器。重新散列后的容器的平均桶数不能超过设定的值。代码示例:

std::unordered_set<int> s;
for (int i = 0; i < 200; ++i)
{s.insert(i);
}
std::cout << "bucket cnt: " << s.load_factor() << std::endl;s.rehash(5);
std::cout << "bucket cnt: " << s.load_factor() << std::endl;

观察器

hash_function

返回hash计算的函数。代码示例:

std::unordered_set<std::string> s;
auto hash_func = s.hash_function();
std::cout << "hash hello world is: " << hash_func("hello world") << std::endl;

输出结果:

hash hello world is: 12386028635079221413

key_eq

返回用于比较key相等性的函数。代码示例:

std::unordered_set<int> s;
auto key_eq_func = s.key_eq();
std::cout << std::boolalpha;
std::cout << key_eq_func(1, 1) << std::endl;
std::cout << key_eq_func(1, 2) << std::endl;

输出结果:

true
false

非成员函数

比较运算符

比较两个unordered_set是否相等。代码示例:

std::unordered_set<int> s1{1, 2, 3};
std::unordered_set<int> s2{1, 2};
std::cout << std::boolalpha;
std::cout << "s1 == s2: " << (s1 == s2) << std::endl;
std::cout << "s1 != s2: " << (s1 != s2) << std::endl;

输出结果:

s1 == s2: false
s1 != s2: true

swap

交换两个unordered_set。代码示例:

std::unordered_set<int> s1{1, 2, 3};
std::unordered_set<int> s2{1, 2};
std::swap(s1, s2);
std::cout << "s1 size = " << s1.size() << std::endl;
std::cout << "s2 size = " << s2.size() << std::endl;

输出结果:

s1 size = 2
s2 size = 3

erase_if

删除满足条件的元素。代码示例:

std::unordered_set<int> s = {1, 2, 3, 4};
std::cout << "s size = " << s.size() << std::endl;
std::erase_if(s,[](int a){return a > 2;});
std::cout << "s size = " << s.size() << std::endl;

输出结果:

s size = 4
s size = 2

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

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

相关文章

Wireshark过滤DNS协议包语法实战

背景 现网DNS服务器发现CPU突增&#xff0c;发现有可能是客户恶意发起的随机子域名扫描&#xff0c;对服务器进行抓包分析&#xff0c;记录下当时的操作。 抓包 执行命令 tcpdump -iany port 53 and host $ip -nnv -w $ip.pcap进行抓包导出到本地&#xff0c;使用Wireshark进…

人工智能|深度学习——基于数字图像处理和深度学习的车牌定位

1.研究背景及研究目的和意义 车牌识别Vehicle License Plate Recognition VLPR) 是从一张或一系列数字图片中自动定位车牌区域并提取车牌信息的图像识别技术。车牌识别 以数字图像处理、模式识别、计算机视觉等技术为基础&#xff0c;是现代智能交通系统的重要组成部分&#xf…

前端项目docker部署

以react项目为例&#xff0c;理论上vue项目也支持。 打包。最好在package.json 里加上"homepage": "."&#xff0c;打包好后&#xff0c;会生成build目录将build目录下的所有文件上传到服务器&#xff0c;假设放在/root/service/shop-h5/public 目录下编写…

C#知识点-16(计算器插件开发、事件、递归、XML)

计算器插件开发 1、Calculator.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace Calculator_DLL {//用来明确所有插件开发人员的开发规范public abstract class Calculator{public int N…

2024-02-21 算法: 测试链表是否有环

点击 <C 语言编程核心突破> 快速C语言入门 算法: 测试链表是否有环 前言一、双指针 ( 快慢指针 )二、代码总结 前言 要解决问题: 一道简单的算法题, 测试链表是否含有环. 想到的思路: 哈希表, 将链表指针强制转换为整型, 利用求余法建立哈希函数. 太复杂, 内存效率不高…

MyBatis的注解式开发

MyBatis的注解式开发 一、准备开发环境1.添加依赖2.jdbc.properties3.mybatis-config.xml4.Article实体类5.SqlSessionUtil工具类 二、Insert三、Delete四、Update五、Select mybatis 中也提供了注解式开发⽅式&#xff0c;采⽤注解可以减少 Sql 映射⽂件的配置。使⽤注解式开发…

设计模式浅析(六) ·命令模式

设计模式浅析(六) 命令模式 日常叨逼叨 java设计模式浅析&#xff0c;如果觉得对你有帮助&#xff0c;记得一键三连&#xff0c;谢谢各位观众老爷&#x1f601;&#x1f601; 命令模式 概念 命令模式&#xff08;Command Pattern&#xff09;是一种行为设计模式&#xff0c…

YOLOv5代码解读[02] models/yolov5l.yaml文件解析

文章目录 YOLOv5代码解读[02] models/yolov5l.yaml文件解析yolov5l.yaml文件检测头1--->耦合头检测头2--->解耦头检测头3--->ASFF检测头Model类解析parse_model函数 YOLOv5代码解读[02] models/yolov5l.yaml文件解析 yolov5l.yaml文件 # YOLOv5 &#x1f680; by Ult…

FPGA SERDESE2 (SDR收发仿真)

高速 Serdes 环路测试 高速串行通信优势非常巨大,只需要很少的IO引脚就可以实现高速通信,这也是当今FPGA高速接口的核心 技术。比如XILINX的7代FPGA,GTX可以达到10.3125Gbps,ultrascale FPGA的GTH可以达到16Gbps。目前国产FPGA还难以达到这么高的接口速度。 高速串行通信经…

社区分享|中华保险基于MeterSphere开展接口自动化测试

中华联合保险集团股份有限公司&#xff08;以下简称为“中华保险”&#xff09;始创于1986年&#xff0c;是全国唯一一家以“中华”冠名的国有控股保险公司。截至2022年12月底&#xff0c;中华保险总资产为1006.06亿元&#xff0c;在全国拥有超过2900个营业网点&#xff0c;员工…

Servlet中的请求与响应

Request和Response 1.Request和Response的概述2.Request对象2.1 Request继承体系2.2 Request获取请求数据2.3 解决post请求乱码问题 *2.4 Request请求转发(-&#xff0c;*)2.5 request的生命周期 3.HTTP响应详解(理解)1.使用抓包查看响应报文协议内容2.HTTP响应报文协议介绍 4.…

汇编英文全称

mov move mvn Mov Negative ldr LoaD Register str Store Register lsl Logic Shift Left lsr Logic Shift Right asr Arithmetic Shift Right 算数右移 ror Rotate right 循环右移…

人工智能讲师AI讲师大模型讲师叶梓介绍及大语言模型技术原理与实践提纲

叶梓&#xff0c;上海交通大学计算机专业博士毕业&#xff0c;高级工程师。主研方向&#xff1a;数据挖掘、机器学习、人工智能。历任国内知名上市IT企业的AI技术总监、资深技术专家&#xff0c;市级行业大数据平台技术负责人。 长期负责城市信息化智能平台的建设工作&#xff…

angular-引用本地json文件

angular-引用json文件&#xff0c;本地模拟数据时使用 在assets目录下存放json文件 大佬们的说法是&#xff1a;angular配置限定了资源文件的所在地&#xff08;就是assets的路径&#xff09;&#xff0c;放在其他文件夹中&#xff0c;angular在编译过程中会忽略&#xff0c;会…

云计算的两地三中心和灾备介绍

两地三中心是指在不同的地理位置建立两个数据中心和一个灾备中心&#xff0c;其中一个数据中心为主数据中心&#xff0c;另一个数据中心为备用数据中心&#xff0c;灾备中心则用于备份数据和在主数据中心或备用数据中心发生故障或灾难时提供应急支持。 异地灾备则是指在不同的地…

Docker之查看并获取最新Ubuntu镜像(十)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

基于springboot+vue的教学资源库系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

Nginx配置组成与性能调优

目录 一、Nginx配置介绍 1. 模块组成 2. 图示 3. 相关框架 二. 配置调优 1. 全局配置 1.1 关闭版本和修改版本 1.2 修改启动的进程数 1.3 cpu与work进程绑定 1.4 pid路径 1.5 nginx进程的优先级&#xff08;work进程的优先级&#xff09; 1.6 调试work进程打开的文…

利用System.Web.HttpRuntime.Cache制作缓存工具类

用到的依赖介绍 当谈到 ASP.NET 中的缓存管理时&#xff0c;常涉及到以下三个类&#xff1a;CacheDependency、HttpRuntime.Cache 和 System.Web.Caching。 CacheDependency&#xff08;缓存依赖项&#xff09;&#xff1a; CacheDependency 类用于指定一个或多个文件或目录作…

问题:Spark SQL 读不到 Flink 写入 Hudi 表的新数据,打开新 Session 才可见

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…