Top Banner
Сложност на алгоритми Кр. Манев, Бургас 09.2008
35

Сложност на алгоритми

Jan 09, 2016

Download

Documents

elwyn

Сложност на алгоритми. Кр. Манев, Бургас 09.2008. Задачи и алгоритми. З адача (в математически смисъл): „ Упражне-ние по математика, физика и др., което се разрешава чрез разсъждения и изчисления “ . (Тълковен речник на българския език). - PowerPoint PPT Presentation
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Сложност на алгоритми

Сложност на алгоритми

Кр. Манев, Бургас 09.2008

Page 2: Сложност на алгоритми

Задачи и алгоритми

Задача (в математически смисъл): „Упражне-ние по математика, физика и др., което се разрешава чрез разсъждения и изчисления“. (Тълковен речник на българския език).

Дьорд Пойя : „Да имаме задача означава да търсим съзнателно някое действие, годно за постигането на една ясно схващана, но не и непосредствено достижима цел. Да се реши една задача означава да се намери това действие.“

Page 3: Сложност на алгоритми

Задачи и алгоритмиМасова задача

Дадено: Множество X = {x1, x2, x3,…} от обекти с определени свойства (всяко xi може да приема множество стойности – параметър) и множество D = {d1, d2, d3,…} от операции (действия).

Търси се: Множество Y = {y1, y2, y3,…} от обекти с определени свойства - резултат, което да се получи от X, с прилагане на операциите от D.

Решение: Не резултаът, а последователността от операции, с които сме го намерили

Page 4: Сложност на алгоритми

Задачи и алгоритмиПримери за масови задачи

Дадени са естествените числа i и j. С прилагане на аритметични операции (вкл. сравняване) да се намери НОД на i и j.

Дадени са естествените числа i, j и k>0. С при-лагане на аритметични операции (вкл. сравня-ване) да се провери дали k е НОД на i и j.

са масови задачи. Да се намери НОД на 12 и 30. Да се провери дали 6 е НОД на 12 и 30.са екземпляри на тези масови задачи –

получени са с фиксиране на някои/всички параметри.

Page 5: Сложност на алгоритми

Задачи и алгоритмиРешение на масова задача

(МЗ)

Решение на МЗ ще наричаме строго определена крайна последователност от стъпки (процедура), която започвайки от зададените стойности на параметрите на произволен екземпляр на МЗ и прилагайки на всяка стъпка някоя от допустимите операции, намира резултата за този екземпляр на масовата задача - АЛГОРИТЪМ

Page 6: Сложност на алгоритми

Задачи и алгоритмиРазрешими и неразрешими

МЗ

Не за всяка МЗ съществува алгоритъм, който да намира резултат за всеки екземпляр на задачата – неразрешима МЗ.

Разрешимите МЗ също не са безпроблем-ни – много често, първият попаднал ни алгоритъм за рещаване на МЗ е неудов-летворителен.

Page 7: Сложност на алгоритми

Сложност на задачи и алгоритми

Много е важно за тази теория, да сe различават понятията сложност на алгоритъм и сложност на задача.

Обикновено, същствуват много алгоритми за решаване на МЗ и всички те могат да имат различна сложност.

Сложност на МЗ бихме могли да нарчем сложността на най-добрия алгоритъм който я решава. Ако знаехме кой е той!!!

Page 8: Сложност на алгоритми

Сложност на алгоритми

За да можем да дефинираме понятието сложност на алгоритъм ще трябва да направим важни стъпки: Да фиксираме множеството от възможни

стойности на параметрите на МЗ. Да фиксираме изчислителния формализъм

– операции, начин на представяне на процедурите (синтаксис и семантика).

Да определим изключително важното за теорията понятие размер на входа.

Page 9: Сложност на алгоритми

Сложност на алгоритмиСтойности на параметрите

Ще фиксираме като множеството от възможни стойности на параметрите на МЗ стойности от множеството на целите числа.

Компютърът релно работи с подмоножество на целите числа, но то с годините се разширява – 8b, 16b, 32b, 64b, 128b...

Дробните числа в компютъра се моделират с двойка цели – мантиса и порядък. Представя-нето е неравномерно, аритметиката проблем-на: може да се случи (a*b)*c a* (b*c)

Page 10: Сложност на алгоритми

Сложност на алгоритмиИзчислителен формализъм

Машината с произволен достъп до паметта (МПД) е упростен модел на съвременния компютър

Всяка клетка на ВЛ, ИЛ и паметта с произволен достъп, както и Акумула-торът (AC) съдържат r-разряд-но цяло - r-разрядна МПД.

Page 11: Сложност на алгоритми

Сложност на алгоритмиИзчислителен формализъм

Програмната памет е със-тавена от клетки. Всяка клетка има свой адрес и може да съдържа по една команда.

Клетката PC (брояч на ко-мандите) съдържа адреса на текущо изпълняваната команда - r-разрядно положително цяло.

Page 12: Сложност на алгоритми

Сложност на алгоритмиИзчислителен формализъм

Всяка команда е съставена от КОД + АРГУМЕНТ (r-разряда) Използват се 3 типа команди

Непосредствен операнд: CODE# Z – операцията се извъшва с числото Z

С пряк адрес: CODE A – операцията се извъшва с числото намиращо се в клетка с адрес A - <A>

С косвен адрес: CODE& A – операцията се извъшва с числото намиращо се в клетка с адрес, който се намира в клетката с адрес A - <<A>>.

Page 13: Сложност на алгоритми

Сложност на алгоритмиИзчислителен формализъм

Да разгледаме за пример командите за събиране Непосредствен операнд: ADD# 100 – към

съдържанието на АC се добавя 100. Означаваме <AC>:=<AC>+100

С пряк адрес: ADD 100 – към съдържанието на АC се добавя съдържанието на клетката с адрес 100 - <AC>:=<AC>+<100>

С косвен адрес: ADD& 100 – към съдържани-ето на АC се добавя съдържанието на клет-ката с адрес, който се намира в клетката с адрес 100 - <AC>:=<AC>+<<100>>.

При всяка от тези команди <PC>:=<PC>+1

Page 14: Сложност на алгоритми

Сложност на алгоритмиИзчислителен формализъм

Подобни са всички останали команди на МПД от „аритметичен“ тип: Изваждане SUB# Z, SUB A, SUB& A Умножение MUL# Z, MUL A, MUL& A Деление DIV# Z, DIV A, DIV & A Остатък при деление MOD# Z, MOD A, MOD

& A Побитова дизюнкция OR# Z, OR A, OR & A Побитова конюнкция AND# Z, AND A, AND &

A Изместване наляво SHL# Z, SHL A, SHL & A Изместване надясно SHR# Z, SHR A, SHR & A и.т.н.

Page 15: Сложност на алгоритми

Сложност на алгоритмиИзчислителен формализъм

Команди за работа с Акумулатора: LOAD# Z - <AC>:=Z, <PC>:=<PC>+1 LOAD A - <AC>:=<A>, <PC>:=<PC>+1 LOAD & A - <AC>:=<<A>>, <PC>:=<PC>+1 STORE A - <A>:=<AC>, <PC>:=<PC>+1 STORE& A - <<A>>:=<AC>, <PC>:=<PC>+1

Команди за вход и изход INPUT - <AC>:=<поредна клетка на ВЛ> <PC>:=<PC>+1 OUTPUT – <поредна клетка на ИЛ>:=<AC> <PC>:=<PC>+1

Page 16: Сложност на алгоритми

Сложност на алгоритмиИзчислителен формализъм

Команди за преходи: JMP B - <PC>:= B JMPZ B – ако <AC> = 0, <PC>:=B,

иначе <PC>:=<PC>+1 JMPP B – ако <AC> > 0, <PC>:=B,

иначе <PC>:=<PC>+1 JMPN B – ако <AC> < 0, <PC>:=B,

иначе <PC>:=<PC>+1 Команда за прекратяване на

работата: STOP

Page 17: Сложност на алгоритми

Сложност на алгоритмиИзчислителен формализъм

Задача: да се състави програма за МПД, която въвежда от ВЛ положителни числа до срещане на 0 и запомня в паметта тези числа (нещо като масив) и броя им.

Първата работа при съставяне на програма за МПД е да си разпределим паметта: В клетката с адрес 0 ще си организираме

индекс на масива от числа, а като завършим четенето от него ще намерим и броя на числата

В клетката с адрес 1 ще поставим първото въведено число, в клетката с адрес 2 – второто, в клетката с адрес 3 –третото и т.н.

Page 18: Сложност на алгоритми

Сложност на алгоритмиИзчислителен формализъм

0) LOAD# 1 // поставяме 1 в АС 1) STORE 0 // съхраняваме 1 в клетка 0 (индекс) 2) INPUT // въвеждаме поредно число в АС 3) JMPZ 9 // ако е въведена 0 - команда 9) 4) STORE& 0 // записваме числото в адреса от

клетка 0 5) LOAD 0 // стойността на индекса - в АС 6) ADD# 1 // увеличаваме индекса с 1 7) STORE 0 // нова стойност на индекса в клетка 0 8) JMP 2 // връщаме се за ново четене 9) LOAD 0 // стойността на индекса в АС 10) SUB# 1 // намаляваме индекса с 1 11) STORE 0 // брой на числата в клетка 0 12) OUTPUT // извеждаме резултата 13) STOP // прекратяваме изпълнението

Page 19: Сложност на алгоритми

Сложност на алгоритмиРазмер на входа

Последната стъпка, която трябва да направим, преди да дефинираме сложност на алгоритъм, е да кажем как ще определяме размер на входа.

Определянето на размер на входа е много сложна задача, затова ще отложим засега окончателното определяне на тази стъпка.

За сега ще считаме, че размерът на входа е приблизително равен на броя на прочетените от ВЛ числа. За нашия пример нека да вземем за размер на входа броя N на положителните числа, които четем от лентата. Това, че изключваме прочетената 0 от рзмера на входа е несъществено.

Page 20: Сложност на алгоритми

Сложност на алгоритмиСложност по време

Сложност по време на един алгоритъм A ще наричаме сложността на програмата за МПД, с която е реализиран. Да означим с # броя на командите, изпълнени от МПД при работата й върху вход . Дефинираме два вида сложност по време на програми за МПД: сложност по време в най-лошия случай:

tA(N) = max с размер N {#} сложност по време в средния случай:

tA*(N) = с размер N {#} / |{ с размер N}| По различни причини ще се занимаваме

само със сложността в най-лошия случай.

Page 21: Сложност на алгоритми

Сложност на алгоритмиСложност по памет

Сложност по памет на един алгоритъм A ще наричаме сложността на програмата за МПД, с която е реализиран. Да означим с @ броя на клетките памет, използвани от МПД при работата й върху вход . Дефинираме два вида сложност по памет на програми за МПД: сложност по памет в най-лошия случай:

sA(N) = max с размер N {@} сложност по памет в средния случай:

sA*(N) = с размер N {@} / |{ с размер N}| По различни причини няма да се

занимаваме сега със сложността по памет.

Page 22: Сложност на алгоритми

Сложност на алгоритми Сложност по време

0) LOAD# 1 // 1 път 1) STORE 0 // 1 път 2) INPUT // N+1 пъти 3) JMPZ 9 // N+1 пъти 4) STORE& 0 // N пъти 5) LOAD 0 // N пъти 6) ADD# 1 // N пъти 7) STORE 0 // N пъти 8) JMP 2 // N пъти 9) LOAD 0 // 1 път 10) SUB# 1 // 1 път 11) STORE 0 // 1 път 12) OUTPUT // 1 път 13) STOP // 1 път

Page 23: Сложност на алгоритми

Сложност на алгоритмиСложност за примера

И така, за нашия пример получаваме: за сложносттта по време в най-лошия

случай: tA(N) = 7.N + 9 за сложността по време в средния

случай, тъй като всички случаи са еднакви:

tA*(N) = tA(N) = 7.N + 9 за сложносттта по памет и в най-

лошия случай и в средния случай, тъй като всички случаи са еднакви:

sA*(N) = sA(N) = N + 1

Page 24: Сложност на алгоритми

Сложност на алгоритмиПрограма на С

В състезателната дейност не използваме МПД и затова ще се наложи да пренесем представе-ната теория в друг изчислителен формализъм – език за програмиане.

По понятни причини ще използаме езика С, но пренасянето на теорията няма да се различава съществено, ако използаваме друг език за програмиране.

Основен принцип при пренасянето ще бъде следният: ще се опитаме да съпоставим на програмата на С такава сложност, каквато бихме получили, ако програмата беше написана на езика на МПД.

Page 25: Сложност на алгоритми

Сложност на алгоритмиПрограма на С

Сложност tе(N) на израз е в програма на С, както и сложността на съответния оператор е; ще дефинираме като броя на всички знаци на операции в израза, плюс броя на всички скоби (както “кръгли”, така и индексни), влючително и тези пропуснати заради приоритети.

Пример: (m[i+1])=(a+(b*C))- сложност 12 а всъщност е 10, но това е удовлетворително

LOAD i MUL c ADD# 1 STORE d ADD m LOAD a STORE t ADD d LOAD b STORE& t

Page 26: Сложност на алгоритми

Сложност на алгоритмиПрограма на С

Сложността на блока от оператори {oper 1;oper 2;…;oper K; } в програма на С ще дефинираме като tblck(N) = toper 1(N) + toper 2(N) + … + toper K(N). Сложността на условния оператор if expr oper в програма на С ще дефинираме като tif(N) = texpr(N) + toper (N). Сложността на условния оператор if expr oper 1 else oper 2 в програма на С ще дефинираме като tif_else(N) = texpr(N) + max {toper 1(N), toper 2(N)}

Page 27: Сложност на алгоритми

Сложност на алгоритмиПрограма на С

За да определим сложността на оператора за цикъл

while expr oper първо определяме броя c (N) на итерациите. Ако сложността toper не зависи от N, тогава

twhile(N) = (c (N)+1)texpr(N) + c (N)toper. Ако сложността toper зависи от N, да означим

с ti(N) сложността на i-тата итерация. Тогава

twhile(N) = (c (N)+1)texpr(N) + t1(N) + t2(N)+…+ tc(N)(N) За цикъла do oper while expr постъпваме

аналогично

Page 28: Сложност на алгоритми

Сложност на алгоритмиПрограма на С

За пример нека да определим сложността на алгоритъма “на мехурчето” за сортиране на N числа. За размер на входа да приемем N.

int a[],N; bubble_sort() { int i,j,t; for(i=N-1;i>0;i--) for(j=1;j<=i;j++) if(a[j]>a[j+1]) {t=a[j];a[j]=a[j+1];a[j+1]=t;} }

Page 29: Сложност на алгоритми

Сложност на алгоритмиПрограма на С

int a[],N,; bubble_sort() { int i,j,t; 3 2 3 for(i=N-1;i>0;i--) 3+N*5+i=1,…,N-1f(i) 2 3 3 for(j=1;j<=i;j++) 2+(i+1)*6+i*30= 10 =36*i+8=f(i) 30 if(a[j]>a[j+1]) 5 9 6 20 {t=a[j];a[j]=a[j+1];a[j+1]=t;} }

Page 30: Сложност на алгоритми

Сложност на алгоритмиПрограма на С

И така за сложността на алгоритъма на мехурчето получаваме:

tbubble_sort(N)= 3 +5N + i=1,2,…,N-1 f (i) = = 3 +5N + i=1,2,…,N-1 (36i + 8) = = 3 +5N +8(N – 1) +36 i=1,2,…,N-1 i = = 13N – 5 + 18N(N – 1) = = 18N2 – 5N – 5

Page 31: Сложност на алгоритми

Сложност на алгоритмиИзвикване на програми

За да определим сложността на оператор, в който има извикване на функция f, трябва да разгледаме съответната функция f

като имплементация на специфичен алгоритъм;

да определим за този алгоритъм какво е размер N* на входа и да пресметнем сложността tf(N*);

Да се върнем в оператора и да изразим N* като функция на N: N* = g(N).

Тогава сложността на извикването ще бъде tf(g(N))

Page 32: Сложност на алгоритми

Сложност на алгоритми Извикване на програми

За пример нека да разгледаме версия на алгоритъма “на мехурчето” за сортиране на първите N* измежду зададени N числа.

int a[],N; bubble_sort(int N*) { int i,j,t; for(i=N*-1;i>0;i--) for(j=1;j<=i;j++) if(a[j]>a[j+1]) {t=a[j];a[j]=a[j+1];a[j+1]=t;} } Сложността му е tbubble_sort(N*) = 18.(N*)2 – 15N* – 5

Page 33: Сложност на алгоритми

Сложност на алгоритми Извикване на програми

Да рагледаме следния алгоритъм. int a[],N,; alabala() { int i; for(i=1;i<=N;i++) bubble_sort(int i)} Сложността му ще бъде talabala(N) = 2 + (N + 1).6 + i=1,2,…,N tbubble_sort(i) = = 6N + 8 + i=1,2,…,N (18.i2 – 15i – 5) = = 6N + 8 + 3N(N + 1)(2N + 1) – 7.5N(N + 1) – 5N= = 6N +8 + 6N3 + 9N2 + 3N – 7.5N 2 – 7.5N – 5N= = 6N3 + 1.5 N2 – 3.5N + 8

Page 34: Сложност на алгоритми

Сложност на алгоритми Рекурсивни извиквания

Да рагледаме следния алгоритъм за сортиране на масив, съдържащ рекурсивни извиквания:

int a[],N; int main(){merge_sort(1,N);return 0;} merge_sort(int i,int j) { int k; if(i==j) return; k=(i+j)/2;merge_sort(i,k); merge_sort(k+1,j); merge(i,k,j);} Сложността му е: t (N)=t merge_sort(N)=3+4+2tmerge_sort (N)+tmerge (N),N > 1t (1) = const - рекурентно отношение

Page 35: Сложност на алгоритми

Сложност на алгоритми Рекурсивни извиквания

Да рагледаме популярния алгоритъм за търсене на число в сортиран масив, съдържащ рекурсивно извикване:

int a[],N,x; int main(){bin_search(1,N);return 0;} bin_search(int i,int j) { while(i<=j) {int k=(i+j)/2; if(x==a[k]) return k; if(x<a[k])bin_search(i,k-1); else bin_search(k+1,j);}} Сложността му се изразява с рекурентното

отношение: t (1) = constt (N)=t bin_search(N)=3+4+6+6+tbin_search(N/2), N > 1