顺序容器||C++初级读本第五版练习9.22

Sequential Containers || C++ Primer Fifth Edition Exercise 9.22

本文关键字:五版 练习 C++ 初级读本 顺序      更新时间:2023-10-16

我对这个练习感到困惑。

练习9.22:假设iv是int的向量,下面的程序有什么问题?您如何纠正问题?

vector<int>::iterator iter = iv.begin(),
                      mid  = iv.begin() + iv.size()/2;
while(iter != mid)     
    if(*iter == some_val)
        iv.insert(iter, 2 * some_val)

我要做的第一件事就是去问这个项目的意图是什么。由于我不确定这本书的这一部分是谁写的,也不想因为一些可能微不足道的事情而打扰作者,我开始猜测。

我假设他们想在向量中插入第一个值的双精度,直到值位于在中间。

那么a)矢量会这样生长吗?

{1,2,3,4,5}
{(2),1,2,3,4,5}
{2,(2),1,2,3,4,5}
{2,2,(2),1,2,3,4,5}

这种情况下的第一个问题是,插入向量很可能会立即使迭代器无效。我们可以使用列表,但不能使用迭代器算法来计算mid。仅仅像示例中那样计算一次mid是不够的,因为在像a这样的列表中,它会指向3并一直指向3,仅仅因为我们调用了迭代器mid并用mid中的元素初始化了他,并不意味着在所有这些插入之后它仍然指向mid。

以下是我所做的:

vector<int>::iterator iter=iv.begin();
while(iter!=iv.begin()+iv.size()/2){    //calculating mid each time
    if(*iter==some_val)
        iv.insert(iter,2*some_val);
    iter=iv.begin();                        //revalidate iter
    while(*iter!=some_val)                  //find the original first element
        ++iter;
}

我看到了这个练习是如何迫使你思考使用哪个顺序容器以及迭代器在不断增长的容器中的行为的,但这个练习的呈现方式仍然让我感到困惑。我错过了一些明显的要点吗?

附言:由于整章都是关于顺序容器的,我没有关注while循环中条件出现的问题(就像他们忘记了几章前教的所有内容一样)。

让我们一步一步地完成程序,并将代码样式更新为现代C++:

auto iter = iv.begin(); // type will be std::vector<int>::iterator
const auto mid  = iv.begin() + iv.size()/2; // type will be std::vector<int>::iterator
while(iter != mid)
{
  if(*iter == some_val)
    iv.insert(iter, 2 * some_val);
}

前两行创建迭代器对。循环进行迭代,直到到达向量的中间。循环内的条件检查iter所指向的位置处的值是否等于某个预定义值someval。下一行代码将一个新项插入到向量中,该项等于some_val值的两倍。

现在回答您的问题:插入行确实使所有迭代器无效,这确实是程序中的问题。此外,迭代器不进行迭代,因为它从不递增。通过使用insert调用的返回值使iter有效并可再次使用,可以解决一个无效问题:

iter = iv.insert(iter, 2*some_val);

但这仍然给我们留下了mid。在你的问题中没有足够的信息来解决这个问题,但可能的选择是:

while(std::distance(iter, iv.end()) > iv.size()) // shift the middle when the vector grows
const auto half = iv.size()/2;
while(std::distance(iter, iv.begin()) < half) // only iterate until iter is halfway the original length by insertion

因此,一个示例解决方案可能如下所示:

auto iter = iv.begin();
while(std::distance(iter, iv.begin()) < iv.size()/2) // iterate until halfway the current vector
{
  if(*iter == some_val)
    iter = iv.insert(iter, 2 * some_val);
  else
    ++iter;
}

但这当然可能不是预期的解决方案。

原始代码不会前进并使所有使用的迭代器无效。

 vector<int>::iterator iter = iv.begin(),
                          mid  = iv.begin() + iv.size()/2;
 while(iter != mid)
         if(*iter == some_val)
                  iv.instert(iter, 2 * some_val);

还有更多问题

vector<int>::iterator iter = iv.begin(),
                      mid  = iv.begin() + iv.size()/2;
int s = iv.size()/2; // assuming we should stop at the original position
while(iter != iv.begin() + s) { // update end condition if that is the intended function
     if(*iter == some_val) {
              iter = iv.instert(iter, 2 * some_val); // gets new valid iter
              ++s; // update position of mid 
              ++iter; // skips the inserted
     }
     ++iter; // advance in vector.
}