Является ли std :: string size () операцией O (1)?
Реализация STL, которую я использую, встроена в VC++.





size_type __CLR_OR_THIS_CALL size() const
{ // return length of sequence
return (_Mysize);
}
Так что в конечном итоге может быть так, но никогда нельзя быть уверенным.
Перефразирования не вижу. Для меня ответ все еще остается загадочным. «... в конце концов, это может быть так»? Разве этот код не был взят из реальной реализации?
Да, std :: string :: size () равно O (1).
STL гарантирует производительность как минимум O (N) для контейнеров, однако многие контейнеры, включая std :: string, могут реализовать это как O (1) и будут. Обычно он либо возвращает простую переменную, либо выполняет что-то вроде _End - _Begin и возвращает это.
См. Таблицу 65 в Разделе 23.1 Стандарта. «a.size ()» отображается как «(Примечание A)», что говорит о том, что «Эти записи ... должны иметь постоянную сложность».
В разделе 21.3 говорится, что строки соответствуют требованиям последовательности (23.1), ipso facto size () является постоянным временем.
Если вы спрашиваете, имеет ли реализация MSVC string :: size () постоянную сложность, то ответ - да. Но Дон Уэйкфилд упомянул Таблицу 65 в 23.1 Стандарта C++, где говорится, что сложность size() должна соответствовать тому, что сказано в «Примечании A». Примечание A говорит:
Those entries marked ‘‘(Note A)’’ should have constant complexity.
Однако это не означает, что эти записи должен имеют постоянную сложность. В стандартах используется очень специфическая терминология, и «следует» означает, что это не обязательно.
«Примечание A» было добавлено к стандарту специально для того, чтобы успокоить тех, кто считал, что size() должен иметь линейную сложность, чтобы не было необходимости сохранять размер при модификации контейнеров.
Таким образом, вы не можете полагаться на то, что size() имеет постоянную сложность, но я, честно говоря, не уверен, есть ли какие-либо реализации, которые не имеют постоянного string::size().
В качестве примечания, тем не менее, можно получить размер строки как операцию O (1) стандартным способом: (end() - begin()). Это гарантированно будет [амортизировано] O (1), потому что и begin(), и end() должны быть O (1) (требования к контейнеру), итераторы строк имеют произвольный доступ (требования к строкам), а operator- должны быть O (1) для итераторов, которые поддержать его (требования к итератору).
... и длина строки не может быть вычислена из содержимого, поскольку нет ограничений на значения, которые могут быть сохранены. Это означает, что он должен управляться извне по отношению к содержимому и, таким образом, не зависит от N., то есть он должен быть О (1). Тот факт, что O(1) не является требованием к контейнерам все, не означает, что это может быть O(N) в контейнерах, только то, что может быть хотя бы один контейнер, для которого он не является постоянным, например std::list<>.
@ DavidRodríguez-dribeas: Хммм, возможно, можно использовать «кодировку» строки, чтобы избежать явного хранения длины где-либо. Например. используйте 0-байт в качестве escape-символа, значение которого зависит от следующего байта: 0 означает «конец строки», ненулевое значение означает «столько 0-байтов». Однако возможно, что другие требования std::string запрещают это (например, это означает, что индексирование массива больше не может быть O (1)).
@j_random_hacker: Вы говорите о гипотетическом языке или C++? Говоря гипотетическим языком, я полагаю, что вы могли бы. В C++ стандарт 03 при описании std::basic_string<>::size() ссылается на требования к контейнеру (т.е. рекомендуемый постоянный размер), в стандарте 11 требование явное: Сложность: постоянное время.
@ DavidRodríguez-dribeas: Ты прав! В стандарте 03 21.3 / 2 говорится: «Шаблон класса basic_string соответствует требованиям Последовательности, как указано в (23.1.1)», а Последовательность - это тип контейнера (23.1.1 / 1), а контейнер требует постоянного времени begin() и end() (таблица 65 в 23.1). Рад слышать, что они сделали это явным в C++ 11.
Строки @PavelMinaev не являются контейнерами. это известная причуда стандартизации. Я не верю, что ваша точка зрения остается в силе из-за этого.
@PavelMinaev согласно этому stackoverflow.com/a/17259940/893406 Я не прав. Может быть, я запутался с вектором <bool> ... тогда не обращайте на меня внимания.
Вот простой способ ответить на этот вопрос для msvC++.
Напишите код в проекте:
string happy;
happy.size();
Выделите вызов .size, щелкните правой кнопкой мыши, перейдите к определению.
При моей установке (vs2005sp1) это отправляет мне xstring: 1635, который выглядит так:
size_type __CLR_OR_THIS_CALL size() const
{ // return length of sequence
return (_Mysize);
}
Итак, похоже, что у строки есть член с именем _Mysize, и он просто возвращает его.
Другими словами, это реализация O (1).
Но вопрос в том, как рассчитывается этот _Mysize?
Это член данных, поэтому он не вычисляется в функции .size (), он просто возвращается. Он изменяется, когда строка устанавливается, очищается, добавляется к и т. д.
Для строки size() операция имеет должна быть постоянной для всех строковых реализаций, которые не используют веревки(1). В стандарте нет явного требования, которое требует, чтобы операция была O(1), наиболее близким является общее требование, чтобы size()должен был постоянным временем, но это оставляет место для любых других мер сложности.
Так почему должен это O (1)?
Это происходит из-за того, что размер не может быть вычислен из содержимого самой строки. В то время как в C вы используете терминатор NUL для определения конца строки, в C++ NUL так же действителен, как и любой другой символ в строке. Поскольку размер строки не может быть вычислен на основе content(2), он должен обрабатываться извне, независимо от фактического размера строки.
(1) Стандарт C++ 03 позволяет реализации использовать веревки в качестве реализации для строк, но факт в том, что ни одна из текущих реализаций стандартных библиотек не использует их.
(2) Если в реализации использовались веревки, операция могла бы зависеть от размера посредством количества блоков, из которых была построена веревка, если блоки были связаны через связанный список или аналогичную конструкцию, или если им было разрешено иметь разные размеры. Но веревки не используются ни в одной известной мне реализации стандартной библиотеки.
Сложность size()должен соответствует примечанию A. Это означает, что должен имеет постоянную сложность, то есть O (1). Хотя я не уверен в реализации, но итераторы в C++ действительно имеют связанные операции, такие как begin () и end (), которые указывают на контейнеры STL. Эти операции имеют постоянную временную сложность, поскольку они являются требованиями контейнера. Это означает, что begin() - end() также имеет постоянную сложность. Это означает, что size() - это операция O (1).
Я думаю, вы были отклонены, потому что вы не ответили на вопрос, вы потребовали от читателя соединить точки. К тому же ваш ответ непонятен.