【C++】23. unordered_map和unordered_set的使用

article/2025/6/26 22:46:10

1. unordered_set系列的使用

1.1 unordered_set和unordered_multiset参考文档

https://legacy.cplusplus.com/reference/unordered_set/

1.2 unordered_set类的详细介绍

• unordered_set的声明模板如下:

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

其中Key就是unordered_set底层存储的关键字类型,其他三个模板参数都有默认值。

• 哈希函数要求:

  • 默认情况下要求Key类型能够转换为整型(std::hash支持基本类型和字符串)
  • 如果Key是自定义类型,可以通过两种方式处理:
    1. 特化std::hash模板
    2. 自定义哈希函数对象传入第二个参数
  • 示例:对于自定义结构体Point的哈希函数
    struct PointHash {size_t operator()(const Point& p) const {return std::hash<int>()(p.x) ^ std::hash<int>()(p.y);}
    };
    

• 键值相等比较:

  • 默认使用std::equal_to进行相等比较
  • 对于自定义类型,可以:
    1. 重载==运算符
    2. 自定义比较函数传入第三个参数
  • 示例:自定义比较函数
    struct PointEqual {bool operator()(const Point& p1, const Point& p2) const {return p1.x == p2.x && p1.y == p2.y;}
    };
    

• 内存分配器:

  • 默认使用std::allocator
  • 可以传入自定义内存池实现(如boost::pool_allocator)
  • 主要用于性能优化和特殊内存管理需求

• 实际使用建议:

  • 90%的使用场景只需要关注Key类型
  • 复杂场景才需要自定义哈希/比较函数
  • 更高级的内存管理需求才需要自定义分配器

• 底层实现特点:

  • 使用哈希表(开链法解决冲突)
  • 平均时间复杂度:
    • 插入:O(1)
    • 删除:O(1)
    • 查找:O(1)
  • 最坏情况下可能退化到O(n)
  • 遍历顺序不确定(取决于哈希函数和插入顺序)

1.3 unordered_set与set的使用区别

• 查阅文档可以发现,unordered_set和set都支持增删查操作,且接口使用方式完全相同,这里不再赘述具体使用方法。

• 两者的首要区别在于对key的要求不同:

  • std::set: 元素类型 Key 必须支持严格的弱序比较。要么定义 < 运算符,要么在构造 set 时提供一个自定义的比较函数对象 (Compare)。

  • std::unordered_set: 元素类型 Key 必须满足两个要求:

    1. 支持计算哈希值:要么有 std::hash 的特化(标准类型如 intstd::string 通常已有),要么在构造 unordered_set 时提供一个自定义的哈希函数对象 (Hash)。

    2. 支持相等比较:要么定义 == 运算符,要么在构造 unordered_set 时提供一个自定义的相等比较函数对象 (Pred)。

• 第二个区别体现在迭代器特性上:

  • 元素顺序:

    • std::set: 元素是有序的。元素总是按照其内部的严格弱序(默认是 < 运算符,或用户提供的比较函数 Compare)进行升序排序。当你遍历一个 set(例如使用迭代器)时,元素会按照这个排序顺序依次出现。

    • std::unordered_set: 元素是无序的。元素的存储顺序取决于它们的哈希值和哈希表的内部状态(桶)。遍历 unordered_set 得到的元素顺序是不确定的(通常看起来是随机的),并且可能随着插入和删除操作而改变。它不保证任何特定的顺序。

  • 内存开销:

    • std::set: 通常每个元素需要额外的指针(用于树结构中的左右子节点和父节点,以及可能的颜色信息),所以内存开销相对较高(每个元素大约需要额外 2-3 个指针的开销)。

    • std::unordered_set: 需要维护哈希表本身(桶数组)以及可能的链表(或其他解决冲突的结构)。为了保持低冲突率和 O(1) 的平均性能,哈希表通常需要比实际元素数量更多的桶(负载因子 < 1),因此也可能有较高的内存开销。具体开销取决于实现和负载因子。

  • 迭代器稳定性:

    • std::set: 迭代器在元素被删除时(除了被删除元素本身的迭代器失效),通常保持稳定。插入操作通常不会使现有迭代器失效(除非容器重组,这在平衡树中不是每次插入都发生)。

    • std::unordered_set: 插入操作可能导致重哈希(当元素数量增加导致负载因子超过阈值时,哈希表会重建一个更大的桶数组并重新映射所有元素)。重哈希会使所有迭代器失效。删除操作只使指向被删除元素的迭代器失效。

• 性能差异是第三个重要区别: 多数情况下,unordered_set的增删查改操作效率更高。这是因为:

  • 查找、插入和删除的平均时间复杂度:

    • std::set: 查找(find)、插入(insert)和删除(erase)操作的平均和最坏时间复杂度都是 O(log n),其中 n 是容器中元素的数量。这是因为平衡树的高度大约是 log n。

    • std::unordered_set: 在理想情况下(好的哈希函数、低冲突):

      • 查找、插入和删除的平均时间复杂度是 O(1)(常数时间)。这是哈希表的主要优势。

      • 然而,最坏情况下的时间复杂度是 O(n)。这发生在哈希函数产生大量冲突(很多元素被映射到同一个哈希桶)时,导致查找退化成在链表(或类似结构)中线性搜索。选择一个好的哈希函数和适当的桶数量可以降低这种风险。

总结对比表:

特性std::setstd::unordered_set
底层结构平衡二叉搜索树 (红黑树)哈希表
元素顺序有序 (按比较函数排序)无序
查找/插入/删除O(log n) (平均和最坏)O(1) (平均), O(n) (最坏)
内存开销较高 (每个元素多个指针)较高 (桶数组 + 冲突解决结构)
迭代器失效插入通常不失效 (除重组), 删除只失效被删元素插入可能因重哈希导致全部失效, 删除只失效被删元素
元素要求需要 Compare (严格弱序)需要 Hash (计算哈希) 和 Pred (相等比较)
典型用例需要元素有序遍历, 需要稳定迭代器, 元素不易哈希或需范围查询需要极快查找/插入/删除 (平均O(1)), 不关心顺序

如何选择?

  • 如果你需要元素按顺序存储和遍历,或者需要进行范围查询(如 lower_boundupper_bound),或者元素的类型不易定义良好的哈希函数,或者需要迭代器稳定性,那么选择 std::set

  • 如果你只关心元素是否存在(成员资格测试),对顺序没有要求,并且元素类型有良好、高效的哈希函数,追求平均情况下的常数时间查找、插入和删除性能,那么选择 std::unordered_set。这是更常用的集合类型,除非有明确的排序或范围查询需求。

简单来说:要顺序用 set,要速度(平均)用 unordered_set 选择时务必考虑你的具体需求(顺序、性能要求、元素类型特性、迭代器稳定性)。


请参考以下代码演示的对比差异:

#include<unordered_set>
#include<unordered_map>
#include<set>
#include<iostream>
using namespace std;
int test_set2()
{const size_t N = 1000000;unordered_set<int> us;set<int> s;vector<int> v;v.reserve(N);srand(time(0));for (size_t i = 0; i < N; ++i){v.push_back(rand()); // N比较大时,重复值比较多//v.push_back(rand() + i); // 重复值相对少//v.push_back(i); // 没有重复,有序}size_t begin1 = clock();for (auto e : v){s.insert(e);}size_t end1 = clock();cout << "set insert:" << end1 - begin1 << endl;size_t begin2 = clock();us.reserve(N);for (auto e : v){us.insert(e);}size_t end2 = clock();cout << "unordered_set insert:" << end2 - begin2 << endl;int m1 = 0;size_t begin3 = clock();for (auto e : v){auto ret = s.find(e);if (ret != s.end()){++m1;}}size_t end3 = clock();cout << "set find:" << end3 - begin3 << "->" << m1 << endl;int m2 = 0;size_t begin4 = clock();for (auto e : v){auto ret = us.find(e);if (ret != us.end()){++m2;}}size_t end4 = clock();cout << "unorered_set find:" << end4 - begin4 << "->" << m2 << endl;cout << "插入数据个数:" << s.size() << endl;cout << "插入数据个数:" << us.size() << endl << endl;size_t begin5 = clock();for (auto e : v){s.erase(e);}size_t end5 = clock();cout << "set erase:" << end5 - begin5 << endl;size_t begin6 = clock();for (auto e : v){us.erase(e);}size_t end6 = clock();cout << "unordered_set erase:" << end6 - begin6 << endl << endl;return 0;
}

1. 插入数据N比较大时,重复值比较多

运行结果:

2. 插入数据重复值相对少

运行结果:

3. 没有重复,有序

运行结果:

运行结果对比可以看出,只有在完全有序时,set性能才占优,其余情况都是unordered_set更具优势,另外以上代码均在release版本下运行


2. unordered_map系列的使用

2.1 unordered_set和unordered_multiset参考文档

https://legacy.cplusplus.com/reference/unordered_map/

2.2 unordered_set与set的使用区别

• 查看STL文档我们会发现unordered_map和map都支持增删查改等基本操作,它们的接口设计几乎相同,包括insert()、erase()、find()、operator[]等常用方法。例如:

std::map<int, string> m;
m.insert({1, "one"});
std::unordered_map<int, string> um;
um.insert({1, "one"});

由于两者的接口高度一致,本节将不再重复演示基本使用方法,而着重讨论它们的关键差异。

• unordered_map和map的第一个主要差异是对key类型的要求不同:

  • std::map: 键类型 Key 必须支持严格的弱序比较。要么定义 < 运算符,要么在构造 map 时提供自定义的比较函数对象 (Compare)。

  • std::unordered_map: 键类型 Key 必须满足两个要求:

    1. 可哈希: 要么有 std::hash 的特化(标准类型如 intstd::string 通常已有),要么在构造 unordered_map 时提供自定义的哈希函数对象 (Hash)。

    2. 可相等比较: 要么定义 == 运算符,要么在构造 unordered_map 时提供自定义的相等比较函数对象 (Pred)。 例如:

    struct MyKey {int id;bool operator==(const MyKey& other) const { return id == other.id; }
    };
    namespace std {template<> struct hash<MyKey> {size_t operator()(const MyKey& k) const { return hash<int>()(k.id); }};
    }

这种差异源于它们的底层实现机制:map基于红黑树,而unordered_map基于哈希表。

• unordered_map和map的第二个重要差异是迭代器特性:

  • map的迭代器是双向迭代器(bidirectional iterator),支持++和--操作,可以向前和向后遍历。由于底层是红黑树(一种二叉搜索树),采用中序遍历时元素是有序的,因此map迭代器遍历时会得到按键值升序排列的结果,并且自动去重。例如:
    map<int, string> m{{2,"b"}, {1,"a"}, {3,"c"}};
    for(auto it = m.begin(); it != m.end(); ++it) cout << it->first; // 输出顺序为1,2,3
    
  • unordered_map的迭代器是单向迭代器(forward iterator),只支持++操作。由于底层是哈希表,元素存储位置由哈希函数决定,因此迭代器遍历时是无序的(但仍保证去重)。例如:
    unordered_map<int, string> um{{2,"b"}, {1,"a"}, {3,"c"}};
    for(auto it = um.begin(); it != um.end(); ++it)cout << it->first; // 输出顺序不确定
    

• unordered_map和map的第三个关键差异是性能特点:

  • 查找、插入和删除的平均时间复杂度:

    • std::map: 查找 (find)、插入 (insert) 和删除 (erase) 操作的平均和最坏时间复杂度都是 O(log n)(n 是元素数量)。平衡树保证了稳定的对数时间复杂度。

    • std::unordered_map: 在理想情况下(好的哈希函数、低冲突):

      • 查找、插入和删除的平均时间复杂度是 O(1)(常数时间)。这是哈希表的核心优势。

      • 然而,最坏情况下的时间复杂度是 O(n)。当哈希函数产生大量冲突(许多键映射到同一个桶)时,性能会线性下降。良好的哈希函数和适当的桶大小管理至关重要。

总结对比表:

特性std::mapstd::unordered_map
底层结构平衡二叉搜索树 (红黑树)哈希表
键/元素顺序按键有序 (按比较函数排序)键无序
查找/插入/删除O(log n) (平均和最坏)O(1) (平均), O(n) (最坏)
内存开销较高 (每个元素多个指针)较高 (桶数组 + 冲突解决结构)
迭代器失效插入通常不失效 (除重组), 删除只失效被删元素插入可能因重哈希导致全部失效, 删除只失效被删元素
键要求需要 Compare (严格弱序)需要 Hash (计算哈希) 和 Pred (相等比较)
范围查询支持 (lower_boundupper_bound等)不支持 (只能精确查找或遍历)
典型用例需要按键有序遍历/范围查询, 需要稳定迭代器, 键不易哈希需要极快查找/插入/删除 (平均O(1)), 不关心键顺序, 键有良好哈希

如何选择?

  • 选择 std::map 当:

    • 你需要按键排序遍历元素。

    • 你需要进行范围查询(例如,“找出所有键在 A 和 B 之间的元素”)。

    • 键的类型不易或无法定义良好的哈希函数

    • 你需要迭代器在插入操作后保持相对稳定

    • 你能接受 O(log n) 的查找/插入/删除时间。

  • 选择 std::unordered_map 当:

    • 只关心通过键快速查找、插入和删除值,对键的顺序完全不在意

    • 键的类型有高效、低冲突的哈希函数可用。

    • 平均情况下的常数时间 (O(1)) 性能是你的首要目标。

    • 你不需要范围查询。

    • 迭代器失效(尤其是插入可能导致的重哈希)在你的使用场景中可以接受或容易管理。

简单来说:需要键有序遍历或范围查询用 map;需要最快的平均查找速度且不关心顺序用 unordered_map 根据你的具体应用场景(对顺序、性能、键类型、迭代器稳定性的要求)做出选择。unordered_map 因其平均 O(1) 的访问速度,在不需要顺序的场景下通常是首选。


请参考以下代码演示的对比差异:

int test_set1()
{const size_t N = 1000000;unordered_map<int, int> um;map<int, int> m;vector<int> v;v.reserve(N);srand(time(0));for (size_t i = 0; i < N; ++i){v.push_back(rand()); // N比较大时,重复值比较多//v.push_back(rand() + i); // 重复值相对少//v.push_back(i); // 没有重复,有序}size_t begin1 = clock();for (auto e : v){m.insert({e, e});}size_t end1 = clock();cout << "map insert:" << end1 - begin1 << endl;size_t begin2 = clock();um.reserve(N);for (auto e : v){um.insert({e, e});}size_t end2 = clock();cout << "unordered_map insert:" << end2 - begin2 << endl;int m1 = 0;size_t begin3 = clock();for (auto e : v){auto ret = m.find(e);if (ret != m.end()){++m1;}}size_t end3 = clock();cout << "map find:" << end3 - begin3 << "->" << m1 << endl;int m2 = 0;size_t begin4 = clock();for (auto e : v){auto ret = um.find(e);if (ret != um.end()){++m2;}}size_t end4 = clock();cout << "unorered_map find:" << end4 - begin4 << "->" << m2 << endl;cout << "插入数据个数:" << m.size() << endl;cout << "插入数据个数:" << um.size() << endl << endl;size_t begin5 = clock();for (auto e : v){m.erase(e);}size_t end5 = clock();cout << "map erase:" << end5 - begin5 << endl;size_t begin6 = clock();for (auto e : v){um.erase(e);}size_t end6 = clock();cout << "unordered_map erase:" << end6 - begin6 << endl << endl;return 0;
}

 1. 插入数据N比较大时,重复值比较多

运行结果:

2. 插入数据重复值相对少

运行结果:

3. 没有重复,有序

运行结果:

测试结果显示,在大多数场景下unordered_map的操作速度更快。但需要注意:

  1. 哈希表性能受负载因子影响,可能需要rehash
  2. 在最坏情况下(大量哈希冲突),unordered_map性能会退化到O(N)
  3. map的优势在于能保持元素有序,且性能稳定

3. unordered_multimap/unordered_multiset

• 功能特性:与multimap/multiset类似,支持键值冗余存储

• 主要差异体现在以下三个方面:

  • 对键值(Key)的要求不同
  • 迭代器及遍历顺序的差异
  • 性能表现的区别

这里就不过多阐述


4. unordered_xxx的哈希相关接口

unordered_xxx容器提供了两类重要的哈希相关接口:

4.1 Buckets系列接口

这些接口主要用于操作和管理哈希桶(bucket),包括:

  • bucket_count(): 返回当前哈希表中桶的数量
  • bucket_size(n):返回第n个桶中的元素数量
  • bucket(key):返回给定键所在的桶编号
  • begin(n)/end(n):返回指向第n个桶首尾的迭代器

例如:

std::unordered_map<std::string, int> umap;
// 获取哈希表当前使用的桶数量
size_t bucket_num = umap.bucket_count(); 
// 获取键为"apple"的元素所在的桶编号
size_t bucket_idx = umap.bucket("apple");

4.2 Hash policy系列接口

这些接口用于管理哈希策略,特别是负载因子(load factor)相关设置:

  • load_factor(): 返回当前负载因子(元素数量/桶数量)
  • max_load_factor(): 获取或设置最大允许负载因子
  • rehash(n):将容器桶数量设置为至少n
  • reserve(n):预留至少n个元素的存储空间

例如可以通过以下方式调整哈希表性能:

// 设置最大负载因子为0.5
umap.max_load_factor(0.5f);
// 预留100个元素的存储空间
umap.reserve(100); 

从日常使用角度来说,我们不需要过多关注这些底层接口。当后续学习了哈希表底层实现原理后,这些接口的作用将会一目了然。哈希表的高效性很大程度上依赖于合理的桶数量和负载因子设置,但在大多数应用场景中,STL提供的默认值已经足够优化。


http://www.hkcw.cn/article/URZDuBNpky.shtml

相关文章

意识之谜 | 粒子组合与单一意识的诞生

注&#xff1a;本文为“脑意识”相关合辑。 略作重排&#xff0c;未做探析。 从粒子到意识&#xff1a;人类大脑单意识诞生之谜 一、单个粒子无意识的本质原因 单个粒子作为物质的基本单元&#xff0c;仅遵循物理化学规律进行运动和相互作用&#xff0c;其行为具有机械性与确…

【更新至2023年】2000-2023年上市公司绿色专利申请授权面板数据

2000-2023年上市公司绿色专利申请授权面板数据 1、时间&#xff1a;2000-2023年 2、来源&#xff1a;国家知识产权局、WPIO清单 3、指标&#xff1a;年份、股票代码、股票简称、行业名称、行业代码、省份、城市、区县、区县代码、上市状态、绿色专利申请总量、绿色发明专利申…

第4章:操作系统

操作系统目的是&#xff1a;为了填补人与机器之间的鸿沟&#xff0c;即建立用户与计算机之间的接口&#xff0c;而为裸机配置的一种系统软件。 系统软件&#xff1a;编辑程序、汇编程序、编译程序、数据库管理系统等 操作系统在计算机系统中的地位&#xff1a; 程序与进程 程…

可靠性方框图绘制说明

下载安装绘制软件&#xff08;Isograph&#xff09;&#xff1a; Isograph Reliability Workbench 14.0 链接&#xff1a;https://pan.baidu.com/s/1owsSJWLtkqAQhbpWdK8keA?pwd49iu 提取码&#xff1a;49iu 制作可靠性方框图 创建RBD&#xff08;可靠性方框图&#xff…

Nougat:用于学术文档的神经光学理解

摘要 科学知识主要以PDF形式存储于书籍和科学期刊中。然而&#xff0c;PDF格式会导致语义信息的丢失&#xff0c;尤其是在数学表达式方面。我们提出了Nougat&#xff08;Neural Optical Understanding for Academic Documents&#xff09;&#xff0c;这是一种Visual transfor…

移除3D对象的某些部分点云

1&#xff0c;目的 移除3D对象指定区域的点云。效果 2&#xff0c;原理。 通过投影剔除指定区域外的点云数据。 3&#xff0c;主要的算子。 3.1&#xff0c;gen_image_gray_ramp 是 Halcon 中用于生成‌线性灰度渐变图像‌的算子 功能概述‌ 数学原理‌ 生成的图像灰度值…

达芬奇(DaVinci Resolve)下载安装教程

目录 一、软件介绍 二、软件下载 2.1 浏览器访问官网 2.2 进行软件包下载 三、软件安装 3.1 解压软件包 3.2 安装软件 四、基本配置 4.1 语言设置 4.2 其他设置 一、软件介绍 达芬奇&#xff08;DaVinci Resolve&#xff09;视频调色软件。DaVinci Resolve汇集剪辑、…

教室门口160cm是小学生低头线 高中版引发热议

教室门口160cm是小学生低头线!5月27日,山东济宁某高中教室内发生了一件有趣的事情。课间休息时,一位老师注意到学生们普遍较高,旁边正好站着一个身高182厘米的男生,于是老师以他为参照,在教室门口贴上一条胶带作为身高线。结果发现,不少男生经过时都需要低头,这一现象迅…

印尼力邀中企深化产业下游化 共创可持续发展

在印尼谈到与中国的经贸合作,“下游化”是最常提到的词。印尼国土辽阔,镍矿资源的储量和产量皆名列全球第一。坐拥全球绿色能源转型的关键金属,印尼吸引了大量全球投资者。单纯出口原始矿藏对当地就业帮助甚少,且由于附加值低,对印尼财政增收贡献有限。为此,印尼近10年来…

《天下第一楼》迎第600场演出 经典传承再续辉煌

6月2日晚,由何冀平编剧,夏淳、顾威、闫锐导演的北京人艺经典话剧《天下第一楼》在首都剧场迎来第600场演出。北京人艺院长冯远征当天再次强调了“深入生活、体验生活”对创作者的重要性。这部作品讲述了上个世纪初北京城饮食界老字号饭庄“福聚德”在时代变迁中的兴衰史。自1…

2022年上半年软件设计师下午试题

答案&#xff1a; 试题一&#xff1a; 试题二&#xff1a; 试题三&#xff1a; 试题四&#xff1a; 试题五: 试题六&#xff1a;

前端高频面试题2:JavaScript/TypeScript

1.什么是类数组对象 一个拥有 length 属性和若干索引属性的对象就可以被称为类数组对象&#xff0c;类数组对象和数组类似&#xff0c;但是不能调用数组的方法。常见的类数组对象有 arguments 和 DOM 方法的返回结果&#xff0c;还有一个函数也可以被看作是类数组对象&#xff…

花卉目标检测数据集介绍(共 12 类,10490 张图像)

在计算机视觉与智能农业快速发展的背景下&#xff0c;基于深度学习的花卉识别与检测技术正被广泛应用于植物分类、智能园艺、自动监测与生态研究等多个领域。为了推动花卉类目标检测任务的发展&#xff0c;本文介绍一个包含 12 种常见花卉类别的目标检测数据集&#xff0c;总计…

linux学习第18天(fork函数)

pid_t fork(void)&#xff1a;创建一个子进程 成功&#xff1a;父进程返回子进程pid 子进程返回0&#xff08;创建成功&#xff09; 失败&#xff1a;-1 getpid/getppid 举个例子&#xff0c;顺便演示getpid和getppid 子进程只能执行fork之后的代码&#xff0c;并且同时争夺c…

Pycharm的终端无法使用Anaconda命令行问题详细解决教程

很多初学者在Windows系统上安装了Anaconda后&#xff0c;在PyCharm终端中运行Conda命令时&#xff0c;会遇到以下错误&#xff1a; conda : 无法将“conda”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。 请检查名称的拼写&#xff0c;如果包括路径&#xff0c;请确保…

关税政策推进受阻 特朗普政府求助上诉法院

当地时间6月2日,美国特朗普政府请求联邦上诉法院阻止此前哥伦比亚特区联邦地区法院裁定其关税政策“违法”的命令。当地时间5月29日,位于首都华盛顿的哥伦比亚特区联邦地区法院就特朗普政府依据《国际紧急经济权力法》对多国加征的关税措施发布初步禁令。该裁决针对美国两家小…

如何看待乌称摧毁大量俄战略轰炸机 俄方反驳称战果夸大

乌克兰国家安全局6月1日在社交媒体上宣布,对位于西伯利亚地区的俄罗斯轰炸机基地进行了袭击。乌方表示,此次行动目标精准,约34%的俄罗斯战略轰炸机遭到攻击,俄方战略航空兵损失高达70亿美元。行动由乌克兰总统泽连斯基亲自协调,安全局局长马柳克率队实施。泽连斯基高度评价…

刘若钒:很遗憾因伤不能和大家一起并肩战斗了,兄弟们加油 伤病阻挡国家队梦想

北京时间6月2日,中国男足公布了出征印尼客场的25人名单,刘若钒因伤未能入选。刘若钒在社交媒体上表达了遗憾:“重回国家队是对我这半年在海港表现的认可,但很遗憾因伤不能和大家一起并肩战斗了。”他同时表示,为国家队比赛一直是他的梦想,希望队友们加油,为中国队助威。…

俄乌谈判草草结束 细看条件都够狠 双方态度强硬

乌克兰在发动无人机袭击后,与俄罗斯在土耳其进行了第二轮和谈。谈判持续了大约一个小时便匆匆结束。土耳其方面表示,谈判以“非消极”的方式结束。5月16日进行了第一轮谈判,6月2日进行了第二轮谈判。预计第三轮谈判将在两周后进行,期间双方可能还会继续交战。双方态度都十分…

山东10岁失联男孩确认溺水身亡 搜救努力未果

6月2日,滕州市公安局发布警情通报。5月31日22时35分许,孔某某报警称其外孙赵某某(10岁)于当日17时许离家后失联。接警后,公安机关迅速调阅监控、走访群众,并联合当地政府和社会救援力量,采用搜救警犬和无人机等手段持续开展搜寻。6月2日15时许,在邻村一河道内发现赵某某…