Алгоритми/Математичке основе

Пре него што почнемо да се бавимо алгоритамским техникама, морамо да изучимо неопходне математичке основе (математички апарат). Прво ћемо да покријемо математичке дефиниције термина који се користе у књизи. Проширењем математичког вокабулара, бићете много прецизнији и у стању да много једноставније формулишете проблем. Затим ћемо обрадити технике анализе времена извршења алгоритма. После сваког битног алгоритма који је обрађен у књизи, следи анализа времена извршења и доказ исправности.

Асимптотска нотација

уреди

Уз исправност, важна одлика корисног алгоритма је време извршења и утрошени меморијски простор. Време и меморија су важни ресурси и међу њима постоји битна разлика у начину коришћења, чак и ако их има у изобиљу. Како се може измерити потрошња ресурса? Један начин је да направите функцију која одражава њихово употребу у односу на неке карактеристике улаза. Једна од уобичајених карактеристика улаза је величина скупа података. На пример, претпоставимо да је улаз неког алгоритма вектор од   целих бројева. Време извршења алгортма можемо да опишемо функцијом   која зависи од  .

 

где је вредност функције   изражена у некој јединици времена. (У овом разматрању главни фокус је на времену, али исто може да се примени и на утрошак меморије). Ретко се као јединица времена користи секунда, јер време извршења зависи од машине, њеног оперативног система и тренутног оптерећења. Уместо у секундама, време се најчешће изражава као потребан број неких основних операција рачунара. На пример, неке од основних операција које се користе су: потребан број сабирања или множења; број поређења (компарација); изведени број замена меморијских локација; или број извршених машинских инструкција. Генерално, могли бисмо се реферисати само на извршење наведених основних операција.

Да ли је ово добар приступ за одређивање утрошка ресурс једног алгоритма? И да и не. Када су два алгоритма слична по утрошку времена, може да помогне прецизна функција која би одредила који је алгоритам бржи у датим условима. Али у многим случајевима је тешко или немогуће дати тачан аналитички опис потребног броја операција, нарочито када алгоритам извршава операције условно - у зависности од вредности улаза. Уместо тога, оно што је заиста важно није тачно време потребно да се изврши одређена функција, већ степен промене утрошка ресурса у зависности од улаза. Конкретно, размотрићемо две приказане функције које дају потребно време извршења у односу на величину улазног скупа података:

 
 

Оне изгледају прилично различито, али како се понашају? Погледајмо неколико графика ових функција (  у црвеној,   у плавој боји):

 
Графикони f и g, за опсег 0 до 5
 
Графикони f и g, за опсег 0 до 15
 
Графикони f и g, за опсег 0 до 100
 
Графикони f и g, за опсег 0 до 1000


У првом, јако ограниченом графику криве изгледају различито. У другом криве крећу у сличном правцу, у трећем постоји само мала разлика и у последњем су скоро идентичне. У ствари оне се приближавају доминантном члану. Што је n веће, остали чланови постају мање значајни у односу на  . Као што се може видети, промена коефицијената чланова нижег реда алгоритма полиномијалног времена не помаже много. Оно што је стварно важно је коефицијент члана највишег реда. Зато смо усвојили посебну нотацију за ову врсту анализе. Тако је:

 

Занемарујемо чланове нижег реда. Можемо да кажемо да је:

 

Ово нам пружа начин да лакше поредимо различите алгоритме. За сортирање   елемената уметањем (insertion sort), потребно је реда величине   корака. За сортирање спајањем (merge sort) потребно је   корака. Тако, ако је скуп улазних података довољно велик, сортирање спајањем је брже од сортирања уметањем.

Генерално пишемо да важи:

 

када је задовољено:

 

Ово значи да   важи ако и само ако постоје константе   и   веће од нуле, тако да за сваки  ,   функција је позитивна и мања или једнака  . Приметимо да знак једнакости који се користи у горњем запису, описује релацију између   и   , а не истинску еквивалентност. У светлу тога, неки дефинишу велико О у терминима скупова, тако да је:

 

када је:

 

Велико O нотација је само горња граница – супремум; оба следећа исказа су тачна:

 
 

Ако узмемо да знак једнакости означава еквиваленцију, добићемо јако чудан резултат, тј. да је:

 

што је очигледна бесмислица. Зато је дефиниција на бази теорије скупова згодна. Забуна може да се избегне тиме што ћете знак једнакости интерпретирати као једносмеран тј.:

 

не имплицира да важи и:

 

Увек држите О на десној страни знака једнакости.

Велико омега

уреди

Понекад нам није довољно да одредимо само горњу границу времена извршења неке функције. Велико омега нам даје доњу границу – инфинум. Генерално, кажемо да је:

 

када важи:

 

тј.   ако и само ако постоје константе c и n0 такве да је за свако n>n0, f(n) позитивна и већа или једнака cg(n). Тако, на пример, можемо да тврдимо да је:

 , (c=1/2, n0=4) или
 , (c=1, n0=3),

али не можемо да је

 

Велико тета

уреди

Када је дата функција истовремено и O(g(n)) и Ω(g(n)), кажемо да је Θ(g(n)), и тада имамо тесне границе функције. Функција f(n) је Θ(g(n)) када важи:

 

Али у већини случајева када покушавамо да утврдимо да је задата функција  , уместо да користимо горњу дефиницију, показујемо да је она истовремено и O(g(n)) и Ω(g(n)).

Мало о и омега

уреди

Када асимптотске границе нису тесне, то можемо да изразимо тако што кажемо да је   или  . Дефинише се:

f(n) је o(g(n)) акко   и
f(n) је ω(g(n)) акко  

Приметимо да је функција f у o(g(n)) када за сваки коефицијент g, g на крају постаје већа од f, док је за O(g(n)) потребно да постоји један коефицијент за који g постаје најмање једнак f.

Анализа алгоритама: решавање диференцних једначина

уреди

За сортирање n елемената спајањем:  . Ово описује једну итерацију сортирања: простор проблема   се своди на две половине ( ), које се спајају по окончању свих рекурзивних позива ( ). Овај систем обележавања (нотација) је основа за анализу алгоритама, тако да треба што пре да се на њега навикнете. Постоје теореме које можете да користите да би проценили време великог О за функцију чија се диференцна (рекурентна) једначина уклапа и одређени шаблон.

Главна теорема

уреди

Razmotrimo diferencnu jednačinu koja se uklapa u formulu:

 

зa a ≥ 1, b > 1 и k ≥ 0. Овде је a број рекурзивних позива за један позив функције, n је величина улаза, b је фактор за који се улаз смањује и k је полиномијални ред операције која се појављује сваки пут када се позове функција (осим за базне случајеве). На пример, код алгоритма сортирања спајањем, који ћемо покрити касније, имамо да је

 

зато што се два потпроблема позивају (решавају) за сваку итерацију случаја који није базни и величина вектора се сваки пут дели на пола.   је на крају „победнички“ део ове поделе и победнички алгоритам: он троши линеарно време за спајање резултата два рекурзивна позива у један коначни резултат.

Ако замислимо рекурзивне позиве T као формирање стабла, постоје три могућа случаја у којима може да се утврди где се већина времена извршења алгоритма троши („већина“ у смислу који се односи на његово асимптотско понашање):

  1. стабло може да буде разгранато при врху и тада се већина времена се троши за време позива близу корена;
  2. стабло може да буде уравнотежено, када је утрошак времена равномерно распоређен;
  3. стабло може да буде разгранато при дну, када се већина времена троши на позиве близу листова.

У зависности од тога у ком се од три наведена статуса стабло налази, T ће имати другачију сложеност:

Главна теорема

Дато   for a ≥ 1, b > 1 and k ≥ 0:

  • Ако је  , онда   (разгранато при врху)
  • Ако је  , онда   (уравнотежено)
  • Ако је  , онда   (разгранато при дну)

За горњи случај сортирања спајањем

 

имамо да је

 

из чега следи да је  , што чини да је стабло уравнотежено. Према главној теореми сложеност сортирања спајањем је

 .