Объединение диапазона из одного списка в другой может быть выполнено за постоянное время за счет size()
Сложность линейная.
C ++ 11 изменил это в случае std::list
требуя size()
быть постоянным временем. Это сломало, например, реализацию gcc, см. [C ++ 0x] std :: list :: размер сложности.
Помимо ассортимента splice()
, есть ли другая причина, почему size()
не мог быть сделан постоянным временем в более раннем, C ++ 03 в соответствии std::list
реализации?
Почему сплайсинг всего списка или линейного диапазона для std::forward_list
?
Увидеть splice_after()
, случаи (1) и (3). См. Также 23.3.4.6 операции forward_list [forwardlist.ops] в стандартная тяга N3485. std::forward_list
даже не реализует size()
,
Я знаю, что forward_list — это односвязный список, но я не понимаю, почему нельзя сделать диапазон splice_after()
в постоянное время. Я, наверное, упускаю что-то тривиальное здесь …
РЕДАКТИРОВАТЬ: Хорошо, это было по крайней мере частично мое недоразумение, я ожидал, что 4 будет не остаться в списке источников. Код:
#include <algorithm>
#include <iostream>
#include <forward_list>
using namespace std;
void dump_list(const forward_list<char>& l) {
for(char c : l)
cout << c << ' ';
cout << '\n';
}
int main()
{
forward_list<char> trg = {'a','b','c'};
forward_list<char> src = {'1','2','3','4'};
auto first = src.begin();
auto last = find(src.begin(), src.end(), '4');
cout << "first = " << *first << ", last = " << *last << "\n\n";
trg.splice_after(trg.begin(), src, first, last);
cout << "Target after splice:\n";
dump_list(trg);
cout << "Source after splice:\n";
dump_list(src);
cout << endl;
return 0;
}
Выход:
first = 1, last = 4
Target after splice:
a 2 3 b c
Source after splice:
1 4
В случае forward_list, как бы вы сделали диапазон splice_after постоянным временем? В списке источников у вас есть только итераторы. Чтобы удалить узлы из исходного связанного списка, вам понадобится узел непосредственно перед last
, поэтому вам нужно искать источник линейно для этого узла связанного списка. Следовательно, почему это линейно на расстоянии между first
а также last
Версия, которая использует весь список источников, все еще нуждается в поиске узла непосредственно перед концом источника, чтобы его можно было изменить, чтобы он указывал на элемент после соединения в месте назначения. Так что это также требует линейного времени в размере источника.
Сращивание диапазона является единственной причиной size
не было бы постоянного времени в предыдущих стандартах C ++. На самом деле компилятор Sun CC решил сделать size
постоянное время и все версии splice
линейно.
Сплайсинг всего списка пересылок является линейным, потому что вы должны пройти список, который вы объединяете, чтобы иметь возможность связать его последний узел обратно в список, в который вы склеиваете. Я не могу понять, почему сращивание диапазона является линейным, хотя.
РЕДАКТИРОВАТЬ: Как @Xeo указывает, версия на основе диапазона также требует линейного времени, потому что last
не входит в диапазон, и его нужно искать из first
найти итератор до last
,