Если вы хотите проанализировать эти алгоритмы, вам нужно определить // dostuff, поскольку это действительно может изменить результат. Предположим, что dostuff требует постоянного O (1) числа операций.
Вот несколько примеров с этим новым обозначением:
Для вашего первого примера, линейный обход: это правильно!
НА):
for (int i = 0; i < myArray.length; i++) {
myArray[i] += 1;
}
Почему он линейный (O (n))? По мере добавления дополнительных элементов к входу (массиву) количество выполняемых операций увеличивается пропорционально количеству добавляемых элементов.
Поэтому, если для увеличения целого числа где-то в памяти требуется одна операция, мы можем смоделировать работу, которую цикл выполняет, с помощью f (x) = 5x = 5 дополнительных операций. Для 20 дополнительных элементов мы делаем 20 дополнительных операций. Один проход массива имеет тенденцию быть линейным. Так же как и алгоритмы сортировки по сегментам, которые могут использовать структуру данных для сортировки за один проход массива.
Ваш второй пример также будет правильным и выглядит так:
O (N ^ 2):
for (int i = 0; i < myArray.length; i++) {
for (int j = 0; j < myArray.length; j++) {
myArray[i][j] += 1;
}
}
В этом случае для каждого дополнительного элемента в первом массиве i мы должны обработать ВСЕ от j. Добавление 1 к i фактически добавляет (длину j) к j. Таким образом, вы правы! Это шаблон O (n ^ 2), или в нашем примере это фактически O (i * j) (или n ^ 2, если i == j, что часто имеет место с матричными операциями или квадратной структурой данных.
Ваш третий пример, где вещи меняются в зависимости от материала; Если код такой же, как написано, и делать вещи постоянными, то это фактически только O (n), потому что у нас есть 2 прохода массива размера n, а 2n уменьшается до n. Циклы, находящиеся вне друг друга, не являются ключевым фактором, который может генерировать 2 ^ n кода; Вот пример функции 2 ^ n:
var fibonacci = function (n) {
if (n == 1 || n == 2) {
return 1;
}
else {
return (fibonacci(n-2) + fibonacci(n-1));
}
}
Эта функция равна 2 ^ n, потому что каждый вызов функции вызывает два дополнительных вызова функции (Фибоначчи). Каждый раз, когда мы вызываем функцию, объем работы, которую мы должны выполнить, удваивается! Это растет очень быстро, как отрезание головы гидры и появление двух новых прорастаний каждый раз!
Для вашего последнего примера, если вы используете сортировку nlgn, такую как merge-sort, вы правы, что этот код будет O (nlgn). Однако вы можете использовать структуру данных для разработки более быстрых сортировок в определенных ситуациях (например, в пределах известного, ограниченного диапазона значений, например, от 1 до 100). Однако вы правы, считая, что код самого высокого порядка доминирует; таким образом, если сортировка O (nlgn) находится рядом с любой операцией, которая занимает меньше времени O (nlgn), общая сложность времени будет O (nlgn).
В JavaScript (по крайней мере, в Firefox) сортировкой по умолчанию в Array.prototype.sort () действительно является MergeSort, поэтому вы смотрите на O (nlgn) для вашего окончательного сценария.