1

Тема: Складність алгоритму

Я вирішив навчитися визначати складність власних програм.
До вас як до лікаря, зразу з аналізами і направленням.
Тобто, до цього я дивився це

Прихований текст

Доречі, після перших 30-40 хв. можна не дивитися, там далі інша тема

і це

Прихований текст

Далі я ще читав:
1) http://uk.wikipedia.org/wiki/Теорія_скл … _обчислень
2) http://uk.wikipedia.org/wiki/Обчислювальна_складність

І оскільки я ще не вчив логарифмів, то
http://uk.wikipedia.org/wiki/Логарифм

Про логарифми вроді зрозумів і у відео вроді все понятно. Але все ж я не розумію як визначити складність або приблизно порахувати к-сть операцій, які виконуються програмою.

І ще не зрозумів максимальну складність, чи як там її ( О(n) і інші, тобто з О    )

Поясніть будь-ласка
P.S. Можете навести приклади програм де складністю є щось пов'язане з логарифмами.

2

Re: Складність алгоритму

Це тільки підтверджує, що відеоуроки - то фігня. Дві години вбили і ніц не зрозуміли.
O(n) означає, що кількість операцій час роботи програми залежить від кількості вхідних даних лінійно, на кшталт k+l*n, де k - час на фіксовані дії (ініціалізацію змінних і вивід результату, наприклад), а l - час на обробку одиниці вхідних даних. Наприклад, програма, що шукає максимум, має саме таку складність: деякі операції будуть виконані незалежно від того, скільки є вхідних даних і чи є вони взагалі, а деякі (ввід, порівняння і присвоювання) - стільки разів, скільки є вхідних значень. Так, деякі операції (присвоювання в результаті порівняння) будуть виконуватися не завжди, але для простоти беремо найгірший випадок і вважаємо, що вони будуть завжди; ну і, зрештою, якщо масив буде впорядкований по зростанню, то ввід, присвоювання і порівняння будуть виконуватися завжди (час, умовно, k+3*n), а якщо максимум буде першим, то ніколи (k+2*n). Обидва вирази лінійні, тобто складність завжди O(n).
А логарифмічна складність виникає, коли об'єм даних, що лишився, зменшується на кожному кроці в певну кількість разів. Наприклад бінарний пошук по впорядкованому масиву - беремо середину, якщо не вгадали - беремо середину того відрізку, що лишився і т.д. - має логарифмічну складність.
В чому сенс цього всього? В тому, що реальним алгоритмам треба обробляти дуже великі об'єми даних. Настільки великі, що число k взагалі непомітне (що таке п'ять хвилин прогріву, якщо алгоритм буде працювати два місяці?), а зменшення коефіціенту l удвічі - ніщо порівняно із заміною алгоритму на інший з логарифмічною складністю. Хоча, звісно, треба бути обережним, а то алгоритм Коперсміта-Винограда вийде - він, звісно, оптимальніший за інші, але тільки для матриць, яким на сучасних носіях знадобиться більше фізичного місця, ніж його займає Земля.

Подякували: Joker, FakiNyan2

3

Re: Складність алгоритму

Добре, я зрозумів більше, але не все.
Давайте пограємося з прикладами. Беремо перший - О(1)
Я це розумію так:
Складність незалежить від вхідних даних.
І для прикладу ось така програма буде працювати за О(1)

#include <iostream>
using naemspace std;

int main ()
{
int n;

cin >> n;

for (int i=0; i<15000; ++i)
cout << "Hello" << endl;

return 0;
}

Заки все ок?

4

Re: Складність алгоритму

Так, але ви не використали свої вхідні дані, тому не знаю, чи є тут сенс говорити про якусь складність.

МАКЕ ЦКЯАІИЕ БЯЕАТ АБАІИ

5 Востаннє редагувалося Joker (25.12.2014 21:43:52)

Re: Складність алгоритму

Але якщо я заміню
цей рядок

for (int i=0; i<15000; ++i)

на такий

for (int i=0; i<n; ++i)

то складність буде O(n)
Доречі, яка складність коли i = n; i<1500?
І дайте будь ласка приклади складності O(1)

6

Re: Складність алгоритму

Що дати, вибачте?

Доречі, яка складність коли i = n; i<1500?

Та ж сама O(n). Можете переконатись в цьому, підрахувавши кількість операцій і відкинувши доданки меншого порядку та коефіцієнти.

МАКЕ ЦКЯАІИЕ БЯЕАТ АБАІИ

7

Re: Складність алгоритму

Що дати, вибачте?

Вибачте, буду уважнішим.

Та ж сама O(n). Можете переконатись в цьому, підрахувавши кількість операцій і відкинувши доданки меншого порядку та коефіцієнти.

Ясненько. О(n) буде тоді, коли к-сть операцій на пряму залежить від вхідних даних.


І дайте будь ласка приклади складності O(1)

8 Востаннє редагувалося koala (25.12.2014 21:57:57)

Re: Складність алгоритму

Це приклад якраз складності O(1) - якщо на вхід дати одне значення чи мільярд, то все одно буде виконано 15000 операцій. Головне тут - розрізняти реальні випадки O(1) від замаскованих, які працюють тільки коли n<15000.
Якщо вам реальний приклад - то пошук в хеш-таблиці має складність O(1).

Подякували: Joker1

9

Re: Складність алгоритму

Joker написав:

Що дати, вибачте?

Вибачте, буду уважнішим.

Та ж сама O(n). Можете переконатись в цьому, підрахувавши кількість операцій і відкинувши доданки меншого порядку та коефіцієнти.

Ясненько. О(n) буде тоді, коли к-сть операцій на пряму залежить від вхідних даних.


І дайте будь ласка приклади складності O(1)

http://replace.org.ua/topic/18/
Подивіться розбір останньої задачі. Очевидне рішення за O(n), трохи менш очевидне за O(log(n)), а в кінці-кінців задача розв’язується за O(1).

МАКЕ ЦКЯАІИЕ БЯЕАТ АБАІИ
Подякували: Joker1

10

Re: Складність алгоритму

http://replace.org.ua/topic/18/
Подивіться розбір останньої задачі. Очевидне рішення за O(n), трохи менш очевидне за O(log(n)), а в кінці-кінців задача розв’язується за O(1).

Круто, буду сидіти і розбирати. Дякую, заки

P.S. Але питання ще будуть!

11 Востаннє редагувалося Joker (26.12.2014 00:48:23)

Re: Складність алгоритму

От дивіться, спершу треба розібратися з усіма розв'язками
Я почав з найкращого О(1)
Така складність, бо обчислення лінійне. Але ж воно все ж залежне від вхідних даних.
Ось частинка коду пана koala

    int log = log10( n ) + 1;
    return ( n + 1 ) * log  - ( pow( 10,  log) - 1 ) / ( 10 - 1 );

І ще я вроді і зрозумів логарифми, читав вікіпедію і дивися (половину відеокурсу)
https://www.youtube.com/watch?v=xzjCwvb … 4zHCkFO18L

Але наскільки я розумію функція log ( http://www.cplusplus.com/reference/cmath/log/ ) бере за основу ось це число http://uk.wikipedia.org/wiki/E_(число) . Ось тут я трошка в ступорі і єдине що поняв, що число близьке до 2,7.

І щодо цих всіх формул, я мало зрозумів (хоча ви трохи пояснювали їх)

Головне питання полягає в тому, як визначити де О(1), а де О(n). Я вважав, що О(1) константний розв'язок, незалежний від вхідних даних. А O(n) - складність, і вона напрям залежить від n, але є лінійною. Бо якщо цикли, то n вже буде у якомусь степені.

Що тут неправильно?Що тут правильно?

12

Re: Складність алгоритму

Ой вибачте, я незамітив, що log - змінна

13

Re: Складність алгоритму

Тоді ви, мабуть, не помітили і того, що log - ціле, а log10 повертає double.

14 Востаннє редагувалося quez (26.12.2014 08:33:58)

Re: Складність алгоритму

Joker написав:

Головне питання полягає в тому, як визначити де О(1), а де О(n). Я вважав, що О(1) константний розв'язок, незалежний від вхідних даних.

O(1) ми маємо тоді, коли кількість операцій не залежить від величини вхідних даних. В цьому випадку якою б не була n, програма виконає однакову кількість операцій — просто порахує дві формули.

Рахувати кількість цифр в числах від 1 до n можна кількома способами. Найбільш наївний спосіб — це просто взяти і порахувати кількість цифр:

int count = 0;
for(int i = 1; i <= n; i++){
    int temp = i;
    while(temp > 0){
        count++;
        temp /= 10;
    }
}

Наївний спосіб має складність O(n*log(n))¹ — n раз виконуємо не більше ніж log(n) операцій.

Тут можна згадати про те, кількість цифр в числі n дорівнює log10(n) + 1. Замінивши внутрішній цикл цією формулою, отримаємо O(n):

int count = 0;
for(int i = 1; i <= n; i++){
    int temp = i;
    count += log10(n) + 1;
}

Наступна сходинка еволюції — помітити, що від 1 до 10 є 9*1 цифр, від 10 до 100 є 90*2 цифр, і т. д. Обчислимо їх всіх і складемо докупи. Отримуємо складність O(log(n)).

int res = 0;
while(i < n){
    res += (i - i/10)*log10(i);
    i *= 10;
}
res += (n - i/10)*log10(i)+log10(n)+1;

Ну і коли ми зможемо позбутись і цього циклу, обчислюючи дві формули для будь-якого числа, ми отримаємо алгоритм складністю O(1).

¹Насправді O(log(n!)). Але графік n*log(n) - log(n!) сильно схожий на лінію, тому я насмілюсь припустити, що log(n!) = n*log(n) - a*n, з подальшим відкиданням меншого доданка.

МАКЕ ЦКЯАІИЕ БЯЕАТ АБАІИ
Подякували: Chemist-i, koala, Joker3

15

Re: Складність алгоритму

Добре, я здається майже зрозумів.
Ще одне питання. У складностях з логарифмом, логарифм беруть за основою 10?

Далі я здається зрозумів. Оскільки я написав здається, а не просто зрозумів. Можете мене перевірити? Задайте якісь приклади, щоб я сам визначив складність.

P.S. Але сьогодні я повернуся трошка пізно, десь біля 7 вечора. Просто, щоб не думали що я забив на все це.

16

Re: Складність алгоритму

Joker написав:

Добре, я здається майже зрозумів.
Ще одне питання. У складностях з логарифмом, логарифм беруть за основою 10?

Логарифми відрізняються один від одного лише константним множником, тому про основу ніхто не говорить.

Прикладів хочете? Нате.

1. На вхід подається список з стрінгі́в, які представляють послідовно записані числа у довільній системі числення. Яку складність матиме алгоритм, що визначає цю систему числення?

2. Знайдіть складність алгоритму множення в стовпчик.

Може ще щось придумаю.

МАКЕ ЦКЯАІИЕ БЯЕАТ АБАІИ

17

Re: Складність алгоритму

Почну з другого

18

Re: Складність алгоритму

2. Знайдіть складність алгоритму множення в стовпчик.

Додавання виконувати також за допомогою довгої арифметики, чи достатньо простою операцією +   ?

19 Востаннє редагувалося quez (27.12.2014 01:44:28)

Re: Складність алгоритму

Ніяких довгих арифметик. Взагалі ніяких комп’ютерів. У вас є таблиця множення — набір елементарних операцій (ну і додавання теж є елементарною операцією). Вам дається два числа, кожне з яких не довше n. Ви шукаєте складність обчислення їх добутку.

МАКЕ ЦКЯАІИЕ БЯЕАТ АБАІИ

20

Re: Складність алгоритму

Ну дивіться. Якщо я правильно зрозумів умову, то я збираюсь робити щось таке:
1) записати дві строки
2) розбити їх на цифри
3) множити стовпчиком
3.1) Помножити кожне верхнє число на кожне з  нижніх.
3.2) Результати множення буду зберігати у окремому векторі.
3.2) Додати їх, але ще треба перед цим помножити на 10 в певному степені.
3.3) Додати їх
4) Вивести результат додавання

Я правильно зрозумів умову?