本条笔记出自
https://leetcode.cn/problems/rotting-oranges/leetcode第994题,腐烂的橘子(矩阵坐标点放了好橘子,坏橘子,坏橘子会感染好橘子,用多源广度搜索求出腐化完成的时间)
在这一题第一次学习容器queue的使用
首先,queue要存二维坐标怎么办?当然是创建pair
queue<pair<int, int>> myQueue;
然后最基础的queue的成员函数,有3个,做题应该就足够:
1.push()
添加元素,没什么好说的,比如直接写myQueue.push({1,2});
但这个最基础的操作好像有点捞,因为这样写需要用{},相当于临时创建了一个pair,然后把{1,2}传递给myQueue
而更快的写法是myQueue.emplace(1,2),这样直接把1和2两个元素传递进去,由容器自己把这两个int数组成pair元素。
2.front()
返回最前面的元素的值。
3.pop()
删除最前面的元素(显然front和pop组成连招,取出,删除,先进先出)。
front的返回值存在哪里?最公式化的写法当然是创建一个pair(另外强调一下,pair不是变量类型,而是模板类型)。
pair<int, int> temp = myQueue.front();
int x = temp.first;
int y = temp.second;
但推荐的写法是,加上const和&,const pair<int, int> &temp = myQueue.front();
这是本条笔记的关键:容器取出元素,const和&的意义?
1.std::pair<int, int> firstElement = Q.front();
这里,firstElement 是一个 std::pair<int, int> 类型的对象,它是通过拷贝队列 Q 的第一个元素来初始化的。这意味着 firstElement 和队列中的第一个元素是两个独立的对象,修改 firstElement 不会影响队列中的元素。
2.const std::pair<int, int> firstElement = Q.front();
在这里,firstElement 是一个常量对象,它的值不能被修改。这意味着你不能改变 firstElement 中的 first 或 second 成员的值。即使你想,编译器也会阻止你这样做。但是,firstElement 仍然是通过拷贝队列 Q 的第一个元素来初始化的,所以它不会影响队列中的元素。
3.std::pair<int, int>& firstElement = Q.front();
这里,firstElement 是对队列 Q 中第一个元素的引用。这意味着 firstElement 和队列中的第一个元素是同一个对象的两个名字。通过 firstElement 修改的任何值都会反映到队列中的元素上。但是,需要注意的是,虽然你可以通过引用修改元素的值,但你不能让 firstElement 引用另一个对象(即你不能重新分配引用)。
4.const std::pair<int, int>& firstElement = Q.front();
最后,这种情况结合了前两者的特性。firstElement 是对队列 Q 中第一个元素的常量引用。这意味着你可以通过 firstElement 访问元素的值,但不能修改它。同时,由于 firstElement 是一个引用,它直接指向队列中的元素,而不是该元素的拷贝。
说简单一点,前两种写法,即不带&的两种写法,只有特殊情况会使用(比如可能需要记下容器中元素在某个时间点的值,但是又要修改它,比较前后两个值),因为它们都是要拷贝一份数值,直接导致了不可能修改原本容器里的元素,而且拷贝一份元素需要更多时间空间。
而主要是在后两种之中选择,因为使用&可以直接调用,避免拷贝,更加快速,而且加上const可以防止元素被修改,不加const就可以修改元素。(但第四种显然是公式化的最优写法,看起来又快又安全)
所以,目前我的结论是,无脑加&,根据是否需要改值,再决定是否用const。
当然仅在这一道题目里面,是不需要考虑这么多的,因为根本不会去改myQueue中的元素值,只需要取出来用一下就删掉了,而且官方答案给出了更简洁的写法auto [x,y] = myQueue.front(); 一下就把前面的三行用一个auto简化到一起了。