czl666吧 关注:13贴子:270
  • 4回复贴,共1

有关C++的容器的一些细节

只看楼主收藏回复

不知道怎么起标题,但总之在贴吧搜索能搜到关键词就可以,只当是一张大草稿纸用
如果以后有时间再试着按顺序整理到一起(但其实只要不影响搜索,该搜到的都能搜到,肯定就懒得整理了)
下面直接开写!


IP属地:四川1楼2024-05-13 20:30回复
    本条笔记出自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简化到一起了。


    IP属地:四川2楼2024-05-13 21:00
    回复
      本条笔记与上条关联,主要有两点。
      1.迭代器指向元素怎么返回值?
      上面讲到pair就不得不讲到,如果用迭代器指向了pair模板类型元素的时候,要调用里面的数值,就要用到->而不是.了。
      迭代器iterator不是指针,但是不管,只管记住用它的时候有这个类似指针的规则。
      比如创建一个哈希表,键值对map
      unordered_map<int, int> table;
      std::unordered_map<int, int>::iterator iter; //迭代器是一个抽象概念,不是一个指针,而是操作工具
      iter = table.find(x); //注意这个find()是map的成员函数,规定好了map中的find()只能对first有作用,所以只会查找first中等于x的值。
      int a = iter->first; //这就是第1个要点,iter和->配合使用
      2.①unordered_map<int, int> table;与②queue<int, int> myQueue;与③queue<pair<int, int>> myQueue;
      首先,第②个是错误写法。
      为什么①和③是正确的,因为map天生就是用来存键值对,所以只管,规定!
      按照规定,就应该给map两个变量,然后map自动把它们转为pair(但其实我认为挺蠢的,因为在使用map的成员函数insert()的时候,还是需要用pair先把两个int数框好,比如写table.insert({a,b});或者写table.insert(pair(a.b));)。
      所以同样按照规定,应该给queue一个变量,所以只能把两个int先组合到一起,写成queue<pair<int, int>>。
      最后,不要想着去像查哈希表一样查找queue<pair<int, int>>中的元素,特别是例如找(first == 0)它天生就不是干这个的,查起来会很麻烦。


      IP属地:四川3楼2024-05-13 21:26
      收起回复


        IP属地:四川来自iPhone客户端4楼2024-06-03 14:27
        回复