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

Post on 09-Jan-2016

55 Views

Category:

Documents

4 Downloads

Preview:

Click to see full reader

DESCRIPTION

Сложност на алгоритми. Кр. Манев, Бургас 09.2008. Задачи и алгоритми. З адача (в математически смисъл): „ Упражне-ние по математика, физика и др., което се разрешава чрез разсъждения и изчисления “ . (Тълковен речник на българския език). - PowerPoint PPT Presentation

Transcript

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

(МЗ)

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

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

МЗ

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Подобни са всички останали команди на МПД от „аритметичен“ тип: Изваждане 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 и.т.н.

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

Команди за работа с Акумулатора: 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

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

Команди за преходи: 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

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

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

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

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

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

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

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 // прекратяваме изпълнението

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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 път

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

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

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

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

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

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

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

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

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

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

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

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

Сложност 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

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

Сложността на блока от оператори {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)}

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

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

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 постъпваме

аналогично

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

За пример нека да определим сложността на алгоритъма “на мехурчето” за сортиране на 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;} }

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

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;} }

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

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

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

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

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

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

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

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

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

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

За пример нека да разгледаме версия на алгоритъма “на мехурчето” за сортиране на първите 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

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

Да рагледаме следния алгоритъм. 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

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

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

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 - рекурентно отношение

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

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

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

top related