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

重学C++ | std::set 的原理

std::set 是C++标准库中的容器之一,它基于红黑树实现。std::set 利用红黑树的特性来实现有序的插入、查找和删除操作,并且具有较好的平均和最坏情况下的时间复杂度。
当向 std::set 插入元素时,它会按照特定的比较函数(bool less<T>::operator() const(const T &lhs, const T & rhs))将新元素插入到红黑树的适当位置,以保持树的有序性质。插入操作的平均时间复杂度为 O ( log ⁡ n ) O(\log n) O(logn),其中 n n nstd::set 中元素的数量。查找操作(find())使用红黑树的性质,通过比较函数在树中进行二分查找,查找操作的平均时间复杂度为 O ( log ⁡ n ) O(\log n) O(logn)

但是当我们把 struct 放入 std::set 会有什么后果呢?因为 std::set 需要在插入到时候排序,所以需要重载 struct 的比较运算符,这个时候就出现问题了,首先我们定义一个结构体 Person

struct Person {Person(int _ID, string _name, int _age) : ID(_ID), age(_age), name(_name) {}int ID;int age;string name;
};

当我们直接插入到 std::set<Person> 中时,会报 complier error 的错误,因此简单补写一个比较运算符重载,如下:

bool operator<(const Person &lhs, const Person &rhs) {return lhs.age < rhs.age;
}

OK,编译起来没有问题,但是我们运行测试一下下面的find操作就会发现问题

#include <iostream>
#include <set>using namespace std;struct Person {Person(int _ID, string _name, int _age) : ID(_ID), age(_age), name(_name) {}int ID;int age;string name;
};bool operator<(const Person &lhs, const Person &rhs) {return lhs.age < rhs.age;
}int main() {set<Person> person;for (int i = 0; i < 1000; ++i) {Person p_tmp(i, "sxj", 10);person.insert(p_tmp);}Person p(2000, "sxj", 10);auto it = person.find(p);if (it != person.end())cout << "Find Person --- ID: " << it->ID << "  name: " << it->name << "  age: " << it->age;elsecout << "Can't find" << endl;return 0;
}

运行结果

明明不在set中的 ID-2000Person也可以被找到。造成这个结果的原因是我们所提供的 operator<() ,当Person p1、p2,在 p1<p2 与 p2<p2 都不成立时,find 就会判断 p1 和 p2 是同一个 Person ,因此会造成这样的错误结果。

解决方案就是补充完整我们的比较运算符重载,完整代码如下

#include <iostream>
#include <set>using namespace std;struct Person {Person(int _ID, string _name, int _age) : ID(_ID), age(_age), name(_name) {}int ID;int age;string name;
};bool operator<(const Person &lhs, const Person &rhs) {if (lhs.ID < rhs.ID) return true;if (lhs.ID > rhs.ID) return false;if (lhs.name < rhs.name) return true;if (lhs.name > rhs.name) return false;return lhs.age < rhs.age;
}int main() {set<Person> person;for (int i = 0; i < 1000; ++i) {Person p_tmp(i, "sxj", 10);person.insert(p_tmp);}Person p(2000, "sxj", 10);auto it = person.find(p);if (it != person.end())cout << "Find Person --- ID: " << it->ID << "  name: " << it->name << "  age: " << it->age;elsecout << "Can't find" << endl;return 0;
}
http://www.lryc.cn/news/176890.html

相关文章:

  • AnV-X6使用及总结
  • Go 围炉札记
  • 数据分析回头看2——重复值检查/元素替换/异常值筛选
  • 什么是OSPF?为什么需要OSPF
  • 轻量级的日志采集组件 Filebeat 讲解与实战操作
  • C# 委托和事件
  • 数据结构与算法之字典: Leetcode 349. 两个数组的交集 (Typescript版)
  • day-56 代码随想录算法训练营(19)动态规划 part 16
  • 蓝桥等考Python组别四级005
  • 【Linux】diff 命令
  • 【51单片机】9-定时器和计数器
  • 2023年海南省职业院校技能大赛(高职组)信息安全管理与评估赛项规程
  • 大模型深挖数据要素价值:算法、算力之后,存储载体价值凸显
  • AI文章,AI文章生成工具
  • mac有必要用清理软件吗?有哪些免费的清理工具
  • React 全栈体系(十八)
  • TCP/UDP
  • c++内存对齐
  • leetcode 33. 搜索旋转排序数组
  • VCS flow学习
  • 微信扫码关注公众号登录功能php实战分享
  • Git 精简快速使用
  • 线性约束最小方差准则(LCMV)波束形成算法仿真
  • 什么是内容运营?
  • 搭建安信可小安派Windows 开发环境
  • XML文件反序列化读取
  • 会议剪影 | 思腾合力受邀参加2023第二届世界元宇宙大会并作主题演讲
  • 加密算法、哈希算法及其区别+国密简介
  • LeetCode算法二叉树—222. 完全二叉树的节点个数
  • Scrapy-应对反爬虫机制