我有一个虚假的问题。我总是读到C ++ std::list
容器在开头,结尾和中间插入元素的时间是恒定的:
哪个是直接在std::list
中间插入元素的正确方法?
可能是这个吗?
std::list<int> l;
l.push_back(10);
l.push_back(20);
l.push_back(30);
l.push_back(40);
l.push_back(50);
l.push_back(60);
l.insert( l.end()- l.begin() /2 ); //? is this
// inserting directly in the middle?
当我们说'插入中间'时,我们是否真的意味着我们保存从列表开头到所需点的线性时间(逐个遍历所有链接元素)?
答案 0 :(得分:12)
你可以像这样执行迭代器数学:
std::list<int>::iterator it = l.begin();
std::advance(it, std::distance(l.begin(), l.end())/2);
l.insert(it, value);
这适用于任何迭代器类型(OutputIterator或InputIterator除外)
当然方式更有效率来说
std::advance(it, l.size()/2);
l.insert(it, value);
不幸的是,l.insert(l.begin + (l.size()/2), value)
不起作用,因为列表迭代器不是随机访问,因此没有定义operator+
(以防止性能意外!)。请记住,std::advance()
可能是代价高昂的操作,具体取决于迭代器类型(对于仅向前容器上实现的反向迭代器,它会很慢)
答案 1 :(得分:5)
这里,“中间”表示列表中的任意点,只要您已经有一个指向该点的迭代器即可。鉴于此,插入只是修改插入点周围的几个指针。
如果你还没有插入点的迭代器,并且它不像开头或结尾那样简单,那么需要线性时间来遍历列表才能找到它。
答案 2 :(得分:1)
当我们说'插入中间'时,我们是否真的意味着我们保存从列表开头到所需点的线性时间(逐个遍历所有链接元素)?
是。
基本上,这意味着列表需要更改指针以插入新元素而不导航整个列表或复制内容等。因为不需要遍历列表或复制容器等,所以插入是恒定时间。
答案 3 :(得分:1)
不,当我们说“插入中间”时,我们并不是指“根据遍历列表的整个或不确定部分的任何标准找到插入点”。
答案 4 :(得分:1)
插入列表的“中间”意味着插入除开头或结尾之外的某个位置。但是插入需要插入点的迭代器。一旦你有了这样的迭代器,插入时间就是不变的,但是首先得到这样一个迭代器是一个单独的问题。