Почему объединение всего списка или диапазона линейно для std :: forward_list?

Объединение диапазона из одного списка в другой может быть выполнено за постоянное время за счет 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

9

Решение

В случае forward_list, как бы вы сделали диапазон splice_after постоянным временем? В списке источников у вас есть только итераторы. Чтобы удалить узлы из исходного связанного списка, вам понадобится узел непосредственно перед last, поэтому вам нужно искать источник линейно для этого узла связанного списка. Следовательно, почему это линейно на расстоянии между first а также last

Версия, которая использует весь список источников, все еще нуждается в поиске узла непосредственно перед концом источника, чтобы его можно было изменить, чтобы он указывал на элемент после соединения в месте назначения. Так что это также требует линейного времени в размере источника.

2

Другие решения

Сращивание диапазона является единственной причиной size не было бы постоянного времени в предыдущих стандартах C ++. На самом деле компилятор Sun CC решил сделать size постоянное время и все версии splice линейно.

Сплайсинг всего списка пересылок является линейным, потому что вы должны пройти список, который вы объединяете, чтобы иметь возможность связать его последний узел обратно в список, в который вы склеиваете. Я не могу понять, почему сращивание диапазона является линейным, хотя.

РЕДАКТИРОВАТЬ: Как @Xeo указывает, версия на основе диапазона также требует линейного времени, потому что last не входит в диапазон, и его нужно искать из first найти итератор до last,

1

По вопросам рекламы [email protected]