Typer af kompleksitetsfunktioner af algoritmer. Algoritmens tidskompleksitet Omtrentlig driftstid afhængig af algoritmens kompleksitet

Bestemmelse af kompleksiteten af ​​en algoritme

Estimatet af kompleksitetsfunktionen opnået i asymptotisk analyse kaldes kompleksiteten af ​​algoritmen.

Det skal huskes på, at der er flere skøn over algoritmens kompleksitet.

Den asymptotiske adfærd af kompleksitetsfunktionen er den operationelle kompleksitet. Ud over dette kan du angive følgende typer vanskeligheder.

Midlertidig kompleksitet - et asymptotisk estimat af algoritmens køretid på inputdata af længde P. Det er indlysende, at i fravær af parallelisering af beregningsprocedurer, er algoritmens driftstid entydigt bestemt af antallet af udførte operationer. Konstante koefficienter, der udtrykker varigheden af ​​operationer, påvirker ikke rækkefølgen af ​​tidskompleksitet, derfor falder formlerne for operationel og tidskompleksitet ofte sammen med hinanden.

Kapacitiv kompleksitet - et asymptotisk estimat af antallet af samtidig eksisterende skalære størrelser, når der udføres en algoritme på inputdata af længde P.

Strukturel kompleksitet - en karakteristik af antallet af kontrolstrukturer i algoritmen og detaljerne i deres relative position.

Kognitiv kompleksitet - en karakteristik af tilgængeligheden af ​​algoritmen til forståelse af specialister inden for anvendelsesområder.

Typer og notationer af asymptotika

I den asymptotiske analyse af algoritmer er det sædvanligt at bruge notationen af ​​matematisk asymptotisk analyse. I dette tilfælde overvejes tre estimater (asymptotik) af kompleksiteten af ​​algoritmer, som er angivet som følger:

  • 1) /(i) = O^(n))- asymptotisk nøjagtig estimat af kompleksitetsfunktionen /(α), eller algoritmens operationelle kompleksitet;
  • 2) /(n) = 0(§(n)) - asymptotisk nøjagtig øvre grænse for kompleksitetsfunktionen /( P);
  • 3) /(l) = ?2(#(l)) - asymptotisk nøjagtig nedre grænse for kompleksitetsfunktionen /( P).

I stedet for betegnelse C1^(n)) meget ofte bruges det simplere o(^(«)) med bogstavet "o", småt kursiv.

Lad os forklare formlernes semantik ved hjælp af et eksempel: hvis /(i) = 0(^2(l)) er skrevet, SÅ betyder DETTE, AT funktionen g(n)=og2 (n) er et asymptotisk nøjagtigt estimat af kompleksitetsfunktionen /(«). I det væsentlige er der en to-positionsdefinition i form af en erklæring:

Hvis f(n)= @(log 2()),

mo g(n)= log 2 (l) - asymptotisk nøjagtigt estimat f(n).

Bemærk, at den konstante multiplikator ikke påvirker rækkefølgen af ​​kompleksitet af algoritmen, derfor udelades basen af ​​logaritmen, når den logaritmiske kompleksitet angives, og de skriver simpelthen /(l) = @(1о§(l)), hvilket antyder, at logaritmen har en vilkårlig base større end én.

Formelle definitioner af asymptotika

Asymptotisk eksakt estimat af kompleksitetsfunktionen Med, Med 2, l 0, således at for l>l 0 afviger funktionen /(l), op til konstante faktorer, ikke fra funktionen g( l), derefter funktionen g(n) kaldes et asymptotisk nøjagtigt estimat af funktionen f(n).

  • 3 s ], s 2 e OG, c x > 0, med 2 > 0:
    • (3 l 0 e K, 1 0 > 0: (/l e K, l > l 0:0 g(n) /(l) = 0(?(l)),

hvor 9^, N er mængderne af henholdsvis alle reelle og naturlige tal.

Asymptotisk skarp øvre grænse for kompleksitetsfunktionen er verbalt defineret som følger: hvis der er positive tal Med og l 0 sådan, at for l>l 0 vokser funktionen /(l) ikke hurtigere end funktionen g(n) op til en konstant faktor c, derefter funktionen g(n) kaldes en asymptotisk nøjagtig øvre grænse for funktionen Ap).

En mere præcis formel repræsentation af definitionen er:

  • 3 Med e %s > 0:
    • (3 l 0 e X, l 0 > 0: (/l e K, l > l 0:0 s? #(l))) 0(g(n))

Asymptotisk snæver nedre grænse for kompleksitetsfunktionen er verbalt defineret som følger: hvis der er positive tal Med og l 0 sådan, at for l>l 0 vokser funktionen /(l) ikke langsommere end funktionen g(n) op til en konstant faktor Med, så kaldes funktionen?(l) en asymptotisk eksakt nedre grænse for funktionen

En mere præcis formel repræsentation af definitionen er:

  • 3 Med e 9^, Med > 0:
    • (3 i 0 e X, i 0 > 0: (/i e K, i > jeg 0: 0 s? g(n)

/(JEG) = 0,^(n))

Bemærk følgende:

  • 1) de uligheder, der er specificeret i de formelle definitioner af asymptotik, kan i det generelle tilfælde ikke tilfredsstilles af én, men af ​​et bestemt sæt funktioner, ofte med utallige medlemmer, derfor konstruktionerne Q(g(n)), 0^(n)) Og 0.^(n)) symbolisere mange funktioner, som den undersøgte arbejdsintensitetsfunktion /(i) sammenlignes med; på grund af dette, i notationen af ​​asymptotika af formen /(i) = 0(?(i)), /(/0 = O(? max (l)), Dya) = ?2(? t1n (i) ) i stedet for tegnet "= "Det ville være mere rationelt at bruge tegnet "e";
  • 2) design (d^(n)), 0^(n)) Og ?1^(n)), brugt som betegnelser for visse mængder skal læses i overensstemmelse hermed: enhver funktion, der er sammenfaldende, vokser ikke hurtigere og vokser ikke langsommere g(n).

Tilfældighed og forskel af asymptotika

Lad os være opmærksomme på følgende kendsgerning: estimatet /(i) = 0(?(i)) etablerer både øvre og nedre estimater for /(i), da dets definition forudsætter gyldigheden af ​​relationen c g(n)

Følgende egenskab ved asymptotikerne er ret indlysende: hvis skønnet f(n) = ©^(n)) eksisterer, så lighederne /( P) = 0(^(i)) og /(i) = a2(#(i)), dvs. de øvre og nedre estimater af arbejdsintensitet falder sammen med hinanden; hvis /(i) = 0(? max(i)) og f(n) = C1^ mt(n)), Og g max (n)фg m 1п (i), så er der ingen funktion g(n), sådan at /(i) = 0(?(i)).

Sammenfaldet af de øvre og nedre estimater af arbejdsintensitet er mulig i følgende tilfælde:

  • 1) kompleksitetsfunktionen for alle værdier af inputlængden er en deterministisk (ikke-tilfældig) funktion, dvs. antallet af udførte operationer afhænger ikke af de specifikke værdier af kildedataene; sådanne er for eksempel funktioner af afhængigheden af ​​antallet af multiplikations- og divisionsoperationer af antallet af ukendte størrelser i algoritmen til løsning af systemer af lineære algebraiske ligninger ved IZ-dekomponeringsmetoden;
  • 2) kompleksitetsfunktionen er en tilfældig funktion, dvs. antallet af udførte operationer afhænger af kildedataenes specifikationer og (eller) rækkefølgen af ​​deres modtagelse, og du kan angive funktionerne / m|n (i), / max (i), der beskriver minimum og maksimum antal af operationer udført af algoritme-eksekveren for en specifik inputlængde i, dog har begge disse funktioner de samme dominanter - for eksempel er de polynomier af samme orden.

Der er tre vigtige regler at huske på med hensyn til operationelle kompleksitetsordreestimater:

  • 1) konstante faktorer har ingen betydning for at bestemme rækkefølgen af ​​kompleksitet, dvs. 0 (k?g(n)) = 0(g(«));
  • 2) rækkefølgen af ​​kompleksitet af produktet af to funktioner er lig med produktet af deres kompleksitet, da ligheden er sand:
  • 0(gl (i) §2(i)) = 0 (a| (i)) 0 (#2(i));
  • 3) rækkefølgen af ​​kompleksitet af summen af ​​funktioner er lig med rækkefølgen af ​​den dominante af led, for eksempel: 0(dvs. +p2 +p) = 0(i 5).

Ovenstående regler bruger kun symbolet for ét asymptotisk estimat 0("), men de er gyldige for alle asymptotiske estimater - og for 0( ) , Og &.{ ).

I et sæt af elementære funktioner kan du angive en liste over funktionel dominans: hvis -variabel, a,b - er numeriske konstanter, så er følgende udsagn sande: I" dominerer I!; I! dominerer a"; a" Zj dominerer" if a>b a p dominerer P b, hvis EN> 1 for evt b e 9? ; p a a/ dominerer if a>b i dominerer log d(i) if EN > 1.

Estimering af gennemsnitlig arbejdsintensitet

I praksis vedr Ved beregningsmæssige beregninger er vurderingen af ​​f(i) af den matematiske forventning om kompleksiteten af ​​M af væsentlig interesse, da f(i) i langt de fleste tilfælde er en tilfældig funktion. Men i processen med eksperimentelle undersøgelser af algoritmer med tilfældig /(i) opstår et yderligere problem - at vælge antallet af tests for et pålideligt estimat af M. At overvinde dette problem er den centrale opgave i . Den foreslåede løsning er baseret på brugen af ​​betafordelingen til at tilnærme /(i). Dette er en meget konstruktiv og universel teknik. Men under moderne forhold, hvor computerens ydeevne er ret høj, er det i mange tilfælde muligt at bruge en enklere metode til at vælge omfanget af test baseret på overvågning af den aktuelle variabilitet af værdier f(n) - værdier estimeres, indtil variabiliteten af ​​estimater bliver mindre end en specificeret fejl.

Estimering af den operationelle kompleksitet af en algoritme

Kompleksiteten af ​​en algoritme kan bestemmes ud fra en analyse af dens kontrolstrukturer. Algoritmer uden loops og rekursive opkald har konstant kompleksitet. Derfor kommer bestemmelsen af ​​kompleksiteten af ​​en algoritme hovedsageligt ned på at analysere loops og rekursive opkald.

Overvej fjernelsesalgoritmen Til element fra et array af størrelse P, bestående af bevægelige array-elementer fra (k+ 1) th til P-th en position tilbage til begyndelsen af ​​arrayet og mindske antallet af elementer P pr. enhed. Kompleksiteten af ​​array-behandlingscyklussen er O(p-k), da løkkens krop (flytningsoperation) udføres PC gange, og løkkelegemets kompleksitet er 0(1), dvs. er en konstant.

I det undersøgte eksempel er kompleksiteten karakteriseret ved asymptotisk 0("), da antallet af operationer udført i denne algoritme ikke afhænger af dataværdiernes specifikationer. Kompleksitetsfunktionen er deterministisk, og alle typer af asymptotika falder sammen med hinanden: f(n) = Q(n-k), f(n) = 0(n-k) Og f(n) = Q(n-k). Dette faktum fremgår af indikationen ©( ). Du bør kun bruge 0(*) og/eller?2(*), hvis disse asymptotika er forskellige.

Løkketypen (for, while, repeat) påvirker ikke kompleksiteten. Hvis en sløjfe er indlejret i en anden, og begge sløjfer afhænger af størrelsen af ​​den samme variabel, er hele designet karakteriseret ved kvadratisk kompleksitet. Indlejring af gentagelser er en vigtig faktor i stigende kompleksitet. Som et eksempel giver vi kompleksiteten af ​​velkendte søge- og sorteringsalgoritmer for en række størrelser P:

  • antal sammenligningsoperationer i sekventiel søgning: 0(i);
  • antal sammenligningsoperationer i binær søgning: 0(log 2 P);
  • antal sammenligningsoperationer i den simple udvekslingsmetode (boblesortering): 0(i 2);
  • antal permutationsoperationer i boblesortering: 0(n 2);

Bemærk, at antallet af sammenligningsoperationer i den simple udvekslingsmetode har en asymptotisk adfærd 0(n 2), og antallet af permutationsoperationer har to forskellige asymptotika 0(n 2) og?2(0), fordi antallet af sammenligninger ikke afhænger af de specifikke værdier af de data, der sorteres, mens antallet af permutationer bestemmes præcist af disse detaljer. Permutationer kan slet ikke udføres - hvis dataarrayet er korrekt ordnet initialt, eller antallet af permutationer kan være maksimalt - ca. P 2 - hvis det sorterede array oprindeligt er ordnet i den modsatte retning.

Funktionsnavn g(n) i asymptotik /(l) = @(^(l)) og /(«) = 0(g(n)) kompleksitetsfunktionen /(«) bruges til at karakterisere algoritmen. De taler således om algoritmer af polynomisk, eksponentiel, logaritmisk osv. kompleksitet.

Semester: 8. januar 2010

Inden den angivne deadline bør artiklen ikke redigeres af andre projektdeltagere. internet side. Efter fuldførelse har enhver deltager ret til at rette denne artikel efter eget skøn og fjerne denne advarsel, der vises ved hjælp af skabelonen ((Opgave)).

se også retningslinier om brug af ressourcen internet side i uddannelsesforløbet.

Beregningsmæssig kompleksitetsteori- en gren af ​​beregningsteori, der studerer mængden af ​​arbejde, der kræves for at løse et beregningsmæssigt problem.

Et problem anses for vanskeligt, hvis løsningen af ​​problemet kræver en stor mængde ressourcer, uanset hvilken algoritme der bruges til at løse det. Teorien formaliserer dette intuitive koncept ved at introducere matematiske beregningsmodeller for at studere disse problemer og kvantificere mængden af ​​ressourcer, der kræves for at løse dem, såsom tid og hukommelse brugt. Andre mål for kompleksitet er også mulige, såsom: antallet af meddelelser (kommunikationskompleksitet), antallet af elementer i kredsløbet af funktionelle elementer (kredsløbskompleksitet) og antallet af processorer. Især beregningsmæssige kompleksitetsteorier definerer praktiske grænser for, hvad computere kan og ikke kan.

Nært forbundet med teorierne om beregningsmæssig kompleksitet er analysen af ​​algoritmer og teorien om beregningsevne. Den største forskel mellem beregningsmæssig kompleksitetsteori og algoritmeanalyse er, at sidstnævnte beskæftiger sig med at analysere mængden af ​​ressourcer, der kræves af en bestemt algoritme for at løse et problem, mens førstnævnte stiller et mere generelt spørgsmål om alle de mulige algoritmer, der kan bruges til at løse det samme problem.problem. Mere præcist forsøger beregningsmæssig kompleksitetsteori at klassificere problemer, der kan eller ikke kan løses med en passende mængde begrænsede ressourcer. Til gengæld er indførelsen af ​​restriktioner på tilgængelige ressourcer det, der adskiller beregningskompleksitetsteori fra beregningsbarhedsteori: sidstnævnte spørger, hvilke problemer der i princippet kan løses algoritmisk uden at begrænse beregningsressourcer.

Beregningsmæssige problemer

Opgaveforekomster

Beregningsmæssige problemer kan ses som et uendeligt sæt af par: (instans af problem, løsning for en given instans). Inputstrengen for et beregningsproblem er en streng, der beskriver problemforekomsten. Outputstrengen for et beregningsproblem er en beskrivelse af løsningen for problemforekomsten beskrevet af inputstrengen. For eksempel problemet med at genkende et tals primegrad: en instans af problemet er et tal, for hvilket det er nødvendigt at bestemme, om det er primetal eller ej, løsningen er strengen "ja", hvis dette tal er primtal og " nej” ellers. Teorien om beregningsmæssig kompleksitet betragter kun massive problemer, dvs. kravet om et uendeligt sæt af opgaveinstanser er obligatorisk.

Opgavevisning

Når man overvejer beregningsmæssige problemer, er beskrivelsen af ​​en probleminstans en linje over alfabetet. Som regel antages alfabetet at være binært (dvs. mængden (0,1)). Forskellige matematiske objekter skal kodes i overensstemmelse hermed. Så for eksempel kan heltal repræsenteres i binært, og grafer kan kodes direkte gennem deres tilstødende matricer eller gennem deres binære indkodning af tilstødende lister.

Anerkendelsesopgaver

Genkendelsesproblemer er et af de centrale forskningsobjekter i teorien om beregningsmæssig kompleksitet. Et genkendelsesproblem er en speciel type beregningsproblem, hvor svaret enten er "ja" eller "nej" (1 eller 0). Genkendelsesproblemet kan formuleres som et problem om, hvorvidt en inputstreng tilhører en bestemt delmængde (sprog) af sættet af alle inputstrenge. En inputproblemstreng hører til det tilsvarende sprog, hvis og kun hvis svaret på den streng er "ja". Genkendelsesopgaven er således opgaven med at genkende, om en inputstreng hører til et bestemt sprog.

Et eksempel på en genkendelsesopgave. Input linje: beskrivelse af en vilkårlig graf. Problemet er at afgøre, om en given graf er forbundet eller ej. Sproget for forbundne grafer er et sæt beskrivelser af alle forbundne grafer. For at opnå en præcis definition af dette sprog, skal man beslutte, hvordan grafer kodes som binære strenge.

Søg opgaver

En søgeopgave er en beregningsopgave, hvor outputværdien er mere kompleks end i en genkendelsesopgave (det vil sige, den er ikke blot "ja" eller "nej").

Et eksempel på et søgeproblem er problemet med rejsende sælger. Problemet med den rejsende sælger (rejsende sælger - rejsende købmand) er et af de mest berømte kombinatoriske optimeringsproblemer. Opgaven er at finde den mest rentable rute, der passerer gennem de angivne byer mindst én gang og derefter vender tilbage til den oprindelige by. Betingelserne for problemet angiver kriteriet for rutens rentabilitet (korteste, billigste, aggregerede kriterium osv.) og de tilsvarende matricer for afstande, omkostninger osv. Som regel er det angivet, at ruten skal passere gennem hver by kun én gang - på en sådan måde I dette tilfælde er valget truffet blandt Hamiltonske cykler. Inputstreng: beskrivelse af en vægtet (dvs. med numeriske etiketter på kanterne) graf. Outputlinjen er en beskrivelse af den rejsende sælgers optimale rute.

Der er et parvist forhold mellem genkendelsesopgaver og søgeopgaver. Søgeproblemet kan formuleres som et genkendelsesproblem. For eksempel, for en søgeopgave med "multiplicering af to tal", kan den tilsvarende parvise genkendelsesopgave repræsenteres som et sæt tripletter (A, B, C), således at relationen A × B = C gælder.

Måle sværhedsgrad

Teorien om beregningsmæssig kompleksitet opstod fra behovet for at sammenligne ydeevnen af ​​algoritmer og klart beskrive deres adfærd (udførelsestid, mængde af påkrævet hukommelse osv.) afhængigt af størrelsen af ​​input og output.

Antallet af elementære operationer brugt af en algoritme til at løse et specifikt tilfælde af et problem afhænger ikke kun af størrelsen af ​​inputdataene, men også af selve dataene. For eksempel er antallet af operationer af indsættelsessorteringsalgoritmen meget mindre, hvis inputdataene allerede er sorteret. For at undgå sådanne vanskeligheder skal du overveje begrebet worst-case tidskompleksitet af en algoritme.

Tidskompleksiteten af ​​en algoritme (i værste tilfælde) er en funktion af størrelsen af ​​input- og outputdataene, svarende til det maksimale antal atomoperationer udført af algoritmen for at løse en probleminstans af en specificeret størrelse. I problemer, hvor størrelsen af ​​output ikke er større end eller proportional med størrelsen af ​​input, kan man kun se tidskompleksiteten som funktion af størrelsen af ​​input.

På samme måde som begrebet tidskompleksitet i værste fald defineres begrebet tidskompleksitet af en algoritme i bedste tilfælde. Vi overvejer også begrebet den gennemsnitlige driftstid for en algoritme, det vil sige den matematiske forventning til algoritmens driftstid. Nogle gange siger de ganske enkelt: "Tidskompleksitet af en algoritme" eller "Løbetid for en algoritme", hvilket betyder tidskompleksiteten af ​​en algoritme i det værste, bedste eller gennemsnitlige tilfælde (afhængigt af konteksten).

I analogi med tidskompleksitet bestemmes algoritmens rumlige kompleksitet, kun her taler vi ikke om antallet af elementære operationer, men om mængden af ​​brugt hukommelse.

På trods af at tidskompleksitetsfunktionen af ​​en algoritme kan bestemmes præcist i nogle tilfælde, er det i de fleste tilfælde meningsløst at lede efter dens nøjagtige værdi. Pointen er, at for det første afhænger den nøjagtige værdi af tidskompleksitet af definitionen af ​​elementære operationer (for eksempel kan kompleksitet måles i antallet af aritmetiske operationer eller Turing-maskineoperationer), og for det andet som størrelsen af ​​inputdataene stiger, bliver bidraget fra konstante faktorer og termer, der optræder i udtrykket for den nøjagtige driftstid, ekstremt ubetydeligt.

Overvejelse af store inputdata og estimering af rækkefølgen af ​​vækst af algoritmens køretid fører til begrebet asymptotisk kompleksitet af algoritmen. Desuden er en algoritme med lavere asymptotisk kompleksitet mere effektiv for alle inputdata, med mulig undtagelse af små data.

Kompleksiteten bestemmes ud fra den beregningsmodel, som beregningerne udføres i.

Beregningsmodeller

Der er mange forskellige computermodeller: Post-maskinen, Minsky-maskinen, lambda-regning, delvist rekursive funktioner, normale Markov-algoritmer, random access memory-maskiner (RAM-maskiner) osv. Vi vil kun nævne den mest populære computermodel - Turing maskine.

Turing maskine

Turing maskine (MT) er en abstrakt performer (abstrakt computermaskine). Det blev foreslået af Alan Turing i 1936 for at formalisere begrebet en algoritme.

En Turing-maskine er en forlængelse af en finite state-maskine og er ifølge Church-Turing-afhandlingen i stand til at simulere alle andre eksekutører (ved at specificere overgangsregler), der på en eller anden måde implementerer processen med trin-for-trin beregning, hvor hver trin i beregningen er ret elementært.

En Turing-maskine består af et bånd, der er uendeligt i begge retninger (Turing-maskiner er mulige, der har flere uendelige bånd), opdelt i celler, og en kontrolenhed, der kan være i en af ​​mange tilstande. Antallet af mulige tilstande for kontrolanordningen er begrænset og præcist specificeret.

Kontrolenheden kan bevæge sig til venstre og højre langs båndet, læse og skrive symboler af et begrænset alfabet ind i cellerne på båndet. Et særligt tomt symbol tildeles, der fylder alle båndets celler, undtagen dem af dem (det endelige nummer), hvorpå inputdataene er skrevet.

Kontrolenheden fungerer i henhold til overgangsregler, der repræsenterer algoritmen implementeret af en given Turing-maskine. Hver overgangsregel instruerer maskinen, afhængigt af den aktuelle tilstand og symbolet i den aktuelle celle, om at skrive et nyt symbol ind i denne celle, flytte til en ny tilstand og flytte en celle til venstre eller højre. Nogle tilstande af en Turing-maskine kan markeres som terminal, og en overgang til enhver af dem betyder afslutningen på arbejdet, og stopper algoritmen.

En Turing-maskine siges at være deterministisk, hvis der højst er én regel, der svarer til hver kombination af tilstand og båndsymbol i tabellen. Hvis der er et par (båndsymbol - tilstand), som der er 2 eller flere instruktioner til, kaldes en sådan Turing-maskine ikke-deterministisk.

Turing-maskinemodellen giver mulighed for forskellige udvidelser. Man kan overveje Turing-maskiner med et vilkårligt antal bånd og multi-dimensionelle bånd med forskellige begrænsninger; maskiner, der bruger en kilde til tilfældighed.

Turing-maskinen er en af ​​de vigtigste beregningsmodeller inden for kompleksitetsteori.

Sværhedsklasser

Kompleksitetsklasser er sæt af beregningsmæssige problemer, der er omtrent lige store i beregningsmæssig kompleksitet. Der er sprogkompleksitetsklasser og funktionelle kompleksitetsklasser. Kompleksitetsklassen af ​​sprog er et sæt prædikater (funktioner, der tager et ord som input og returnerer svaret 0 eller 1), der bruger omtrent den samme mængde ressourcer til beregning. Konceptet for en funktionel kompleksitetsklasse ligner, bortset fra at det ikke er et sæt prædikater, men et sæt funktioner. I kompleksitetsteori er standardkompleksitetsklassen kompleksitetsklassen af ​​sprog. En typisk definition af kompleksitetsklasse ser sådan ud:

Kompleksitetsklassen X er sættet af prædikater P(x), der kan beregnes på Turing-maskiner og bruger O(f(n)) ressourcer til beregning, hvor n er længden af ​​ordet x.

Ressourcerne antages normalt at være beregningstiden (antallet af arbejdscyklusser for Turing-maskinen) eller arbejdsområdet (antallet af brugte celler på båndet under drift). Sprog, der genkendes af prædikater fra en eller anden klasse (det vil sige det sæt af ord, hvori prædikatet returnerer 1) siges også at tilhøre samme klasse.

Derudover kan mange klasser også beskrives i form af matematisk logik eller spilteori.

Klasser er normalt angivet med store bogstaver. Komplementet af klasse C (det vil sige klassen af ​​sprog, hvis komplementer hører til C) betegnes co-C.

For hver klasse er der en kategori af opgaver, der er "sværeste". Det betyder, at enhver opgave fra en klasse reduceres til sådan en opgave, og desuden ligger selve opgaven i klassen. Sådanne problemer kaldes komplette problemer for en given klasse.

Klasse P

Klasse P (fra det engelske polynomium) er et sæt af genkendelsesproblemer, der kan løses på en deterministisk Turing-maskine i et tidspolynomium i længden af ​​input. Tilsvarende er klassen FP (fra det engelske funktionelle polynomium) defineret for søgeproblemer.

Overvej mere formelt deterministiske Turing-maskiner, der beregner svaret givet et ord ud fra input-alfabetet, der er angivet på inputbåndet. Driftstiden for en Turing-maskine for et fast inputord x Antallet af arbejdscyklusser for en Turing-maskine fra start til stop af maskinen kaldes. Kompleksiteten af ​​en funktion beregnet af en Turing-maskine er en funktion, der afhænger af længden af ​​inputordet og er lig med maskinens maksimale driftstid for alle inputord af en fast længde:

.

Hvis for funktionen f der er en Turing-maskine M sådan at for nogle tal c og stor nok n, så siger de, at det tilhører klassen FP, eller er polynomium i tid.

Klasse P er en af ​​de grundlæggende klasser i teorien om beregningsmæssig kompleksitet.

Klasse NP

NP-klassen (fra det engelske ikke-deterministiske polynomium) er et sæt genkendelsesproblemer, hvis løsningstid væsentligt afhænger af størrelsen af ​​inputdataene; samtidig er der en algoritme, som efter at have modtaget, sammen med en beskrivelse af inputværdierne, nogle yderligere informationer (et vidne til løsningen), kan løse problemet ret hurtigt (på en tid, der ikke overstiger et polynomium af størrelsen af ​​data).

Mere formelt siges et sprog L at tilhøre klassen NP, hvis der eksisterer et to-steds prædikat R(x, y) fra klassen P (dvs. kan beregnes i polynomisk tid) og et polynomium p således, at for et hvilket som helst ord x af længden n betingelsen "x tilhører L" " svarer til betingelsen "der er y af længde mindre end p(n), således at R(x, y) er sand." Ordet y kaldes et vidne om, at x hører til sproget L. Hvis vi altså har et ord, der hører til sproget og et andet vidneord af begrænset længde (som kan være svært at finde), så kan vi hurtigt verificere, at x hører virkelig til L. Ethvert problem, der hører til NP, kan løses i eksponentiel tid ved at søge gennem alle mulige vidner af længde mindre end p(n).

Eksempel på problem fra NP: genkendelsesproblem "Eksistensen af ​​en heltalsløsning til et system af lineære uligheder." Vidnet er løsningen på ulighedssystemet. Det er let at verificere i polynomiel tid, at vidneløsningen er egnet.

NP-klassen inkluderer P-klassen.

Åbne numre

I teorien om beregningsmæssig kompleksitet er der mange uløste problemer; de vedrører hovedsageligt spørgsmål om opdeling eller indlejring af visse kompleksitetsklasser. Et af disse spørgsmål er problemet med lighed mellem klasserne P og NP.

Problem med lighed af klasserne P og NP

I sidste ende er problemet med klasselighed P og NP dette: Hvis det positive svar på et spørgsmål hurtigt kan verificeres (i polynomiel tid), er det så sandt, at svaret på dette spørgsmål kan findes hurtigt (i polynomisk tid)?

Følgende konsekvens følger umiddelbart af definitionen af ​​klasserne P og NP: . Der vides dog endnu intet om strengheden af ​​denne inddragelse, dvs. er der en algoritme, der ligger i NP, men ikke i P? Hvis en sådan algoritme ikke eksisterer, så kan alle problemer, der hører til klassen NP, løses i polynomisk tid, hvilket lover enorme fordele fra et beregningsmæssigt synspunkt. I øjeblikket kan de sværeste NP-problemer (såkaldte NP-komplette problemer) løses i eksponentiel tid, hvilket næsten altid er uacceptabelt.

Spørgsmålet om ligheden mellem disse to klasser betragtes som et af de sværeste åbne problemer inden for teoretisk datalogi. I øjeblikket mener de fleste matematikere, at disse klasser ikke er lige. Clay Mathematics Institute inkluderede dette problem på listen over Millennium-problemerne og tilbød en belønning på en million amerikanske dollars for dets løsning.

Litteratur

  1. Gehry M., Johnson D. Computermaskiner og problemer, der er svære at løse. Forlaget Mir i 1982. - 420 sek. Monografien af ​​amerikanske videnskabsmænd er viet til at løse komplekse (herunder NP-hårde) kombinatoriske problemer, der opstår i diskret optimering, matematisk programmering, algebra og automatteori med eksempler.
  2. Corman, Thomas H.; Leiserson, Charles I.; Rivest, Ronald L.; Stein, Clifford Algorithms: Construction and Analysis, 2. udgave = Introduktion til Algorithms anden udgave. - M.: "Williams", 2005. -

Konstant tid

De siger, at en algoritme er en algoritme konstant tid(optaget som tid O(1)), hvis værdien T(n) er begrænset til en værdi uafhængig af størrelsen af ​​input. For eksempel tager det konstant tid at hente et element i et array, fordi en enkelt kommando udføres for at lokalisere det. Men at finde minimumsværdien i et usorteret array er ikke en konstant-tidsoperation, da vi skal gennemgå hvert element i arrayet. Denne operation tager således lineær tid, O(n). Hvis antallet af elementer er kendt på forhånd og ikke ændres, kan en sådan algoritme omtales som en konstant-tidsalgoritme.

På trods af navnet "konstant tid" behøver køretiden ikke at være uafhængig af problemets størrelse, men den øvre grænse for køretiden skal ikke. For eksempel opgaven "udveksle værdier -en Og b, hvis det er nødvendigt, så resultatet bliver -enb", betragtes som et konstant-tidsproblem, selvom algoritmens køretid kan afhænge af om uligheden allerede holder -enb eller ikke. Der er dog en vis konstant t, hvor opgavens udførelsestid altid er ikke overstiger t.

Nedenfor er nogle kodeeksempler, der kører konstant:

Int indeks = 5; int item = liste; hvis(tilstand er sand) derefterandet udføre nogle operationer med konstant køretid til i = 1 til 100 til j = 1 til 200 udføre nogle operationer med konstant køretid

Hvis T(n) er lig med O( en eller anden konstant værdi), dette svarer til T(n) er O(1).

Logaritmisk tid

logaritmisk tid, hvis T(n) = O(log n) . Da computere bruger et binært talsystem, bruges 2 som basis for logaritmen (det vil sige log 2 n). Men hvornår base udskiftning logaritmer log a n og log b n afviger kun med en konstant faktor, som kasseres i notationen O-big. Så O(log n) er standardnotationen for logaritmiske tidsalgoritmer, uanset logaritmebasen.

Algoritmer, der kører i logaritmisk tid, findes almindeligvis, når du udfører operationer på binære træer, eller når du bruger binær søgning.

O(log n) algoritmer anses for at være meget effektive, fordi driftstiden pr. element falder, når antallet af elementer stiger.

Et meget simpelt eksempel på en sådan algoritme er at dele en streng i to, den anden halvdel deles i to igen, og så videre. Dette tager O(log n) tid (hvor n er længden af ​​strengen, vi antager her at console.log Og str.understreng tage konstant tid). Det betyder, at for at øge antallet af print, skal linjelængden fordobles.

// Funktion til rekursivt at udskrive højre halvdel af en linje var højre = funktion (str) (var længde = str. længde; // hjælpefunktion var hjælp = funktion (indeks) ( // Rekursion: udskriv højre halvdel hvis (indeks< length ) { // Udskriv tegn fra indeks til slutningen af ​​linjen konsol. log(str. understreng(indeks, længde)); // rekursivt opkald: Kald hjælpefunktionen med højre side hjælp (Math . ceil ((længde + indeks) / 2 )); ) ) hjælp ( 0 ); )

Polylog tid

Algoritmen siges at køre ind polylog tid, hvis T(n) = O((log n) k), for nogle k. For eksempel kan problemet med rækkefølgen af ​​matrix multiplikation løses i polylogaritmisk tid ved parallel RAM-maskine .

Sublineær tid

Algoritmen siges at køre ind sublineær tid, hvis T(n) = o( n). Dette inkluderer især tidskompleksitetsalgoritmerne nævnt ovenfor, såvel som andre såsom Grovers søgning med kompleksitet O( n ½).

Typiske algoritmer, der, selv om de er nøjagtige, stadig fungerer i sublineær tid, bruger parallelisering af processer (ligesom NC 1-algoritmen til beregning af determinanten af ​​en matrix), ikke-klassiske beregninger (som i Grovers søgning) eller har en garanteret antagelse om strukturen af ​​input (som dem, der kører i logaritmisk tid, binære søgealgoritmer og mange træbehandlingsalgoritmer). Imidlertid kan formelle konstruktioner, såsom sættet af alle strenge, der har en bit 1 i positionen bestemt af strengens første log(n) bit, afhænge af hver bit af inputtet, men stadig være sublineær i tid.

Semester algoritme med sublineær køretid bruges normalt til algoritmer, der i modsætning til eksemplerne ovenfor fungerer på almindelige sekventielle maskinmodeller og ikke forudsætter kendskab til inputstrukturen på forhånd. Brugen af ​​probabilistiske metoder er dog tilladt for dem, og endda desuden skal algoritmerne være sandsynlige for de fleste trivielle problemer.

Da en sådan algoritme skal producere et svar uden at læse inputdataene fuldt ud, er den meget afhængig af de adgangsmetoder, der er tilladt i inputstrømmen. Typisk for en stream, der er en bitstreng b 1 ,...,b k, antages det, at algoritmen kan anmode om en værdi i O(1) tid b i for enhver jeg.

Sublineære tidsalgoritmer er normalt probabilistiske og giver kun en omtrentlig løsning. Sublineære runtime-algoritmer opstår naturligt, når man forsker ejendomstjek.

Lineær tid

lineær tid, eller O( n) , hvis dens kompleksitet er O( n). Uformelt betyder det, at for en tilstrækkelig stor inputstørrelse, øges køretiden lineært med størrelsen af ​​input. For eksempel kræver en procedure, der summerer alle elementerne i en liste, tid proportionalt med listens længde. Denne beskrivelse er ikke helt nøjagtig, da driftstiden kan afvige væsentligt fra den nøjagtige proportionalitet, især for små værdier n.

Lineær tid ses ofte som en ønskelig egenskab ved en algoritme. Der er lavet meget forskning for at skabe algoritmer med (næsten) lineær køretid eller bedre. Disse undersøgelser omfattede både software- og hardwaretilgange. I tilfælde af hardwareudførelse kan nogle algoritmer, der ud fra et matematisk synspunkt aldrig kan opnå lineær eksekveringstid i standard computermodeller, køre i lineær tid. Der er nogle hardwareteknologier, der bruger parallelitet til at nå dette mål. Et eksempel er associativ hukommelse. Dette koncept for lineær tid bruges i strengsammenligningsalgoritmer såsom Boyer-Moore-algoritmen og Ukkonen-algoritmen.

Kvasilineær tid

Algoritmen siges at køre i kvasi-lineær tid if T(n) = O( n log k n) for nogle konstante k. Lineær-logaritmisk tid er et særligt tilfælde med k= 1. Ved at bruge svag-O-notationen er disse algoritmer Õ( n). Kvasilineære tidsalgoritmer er også o( n 1+ε) for enhver ε > 0 og arbejd hurtigere end et hvilket som helst polynomium i n

Algoritmer, der kører i kvasi-lineær tid, ud over de lineær-logaritmiske algoritmer, der er nævnt ovenfor, inkluderer:

  • På stedet flet sortering, O( n log 2 n)
  • Quicksort, O( n log n), i den probabilistiske version har en lineær-logaritmisk worst-case eksekveringstid. Den ikke-probabilistiske version har kun lineær-logaritmisk køretid for at måle kompleksitet i gennemsnit.
  • Heapsort, O( n log n), flette sortering, introsort, binær træsortering, glat sortering, solitaire sortering, etc. i værste fald
  • Fast Fourier transformeres, O( n log n)
  • Beregning af Monge-matricer, O( n log n)

Lineær-logaritmisk tid

Lineær-logaritmisk er et specialtilfælde af kvasi-lineær tid med eksponenten k= 1 på det logaritmiske led.

Lineær-logaritmisk funktion er en funktion af formen n log n(dvs. arbejdet lineær og logaritmiske udtryk). De siger, at algoritmen virker ind lineær-logaritmisk tid, hvis T(n) = O( n log n) . Således vokser det lineær-logaritmiske led hurtigere end det lineære led, men langsommere end et hvilket som helst polynomium af n med en grad strengt taget større end 1.

I mange tilfælde driftstid n log n er simpelthen resultatet af at udføre operationen Θ(log n) n enkelt gang. For eksempel opretter binær træsortering et binært træ ved at indsætte hvert element i en matrix med størrelse n efter hinanden. Siden indsættelsesoperationen i balanceret binært søgetræ tager O(log) tid n), vil den samlede udførelsestid for algoritmen være lineær-logaritmisk.

Sammenligning sorterer kræver mindst et lineært-logaritmisk antal sammenligninger i værste fald, da log( n!) = Θ( n log n) ifølge Stirling-formlen. Den samme udførelsestid opstår ofte fra gentagelsesligningen T(n) = 2 T(n/2) + O( n).

Subquadratisk tid

Nogle eksempler på polynomiske tidsalgoritmer:

Strengt og svagt polynomisk tid

I nogle sammenhænge, ​​især inden for optimering, skelnes der mellem algoritmer med streng polynomisk tid Og svagt polynomisk tid. Disse to begreber gælder kun for heltalsinput.

Strengt polynomisk tid er defineret i den aritmetiske model for beregning. I denne model tages grundlæggende aritmetiske operationer (addition, subtraktion, multiplikation, division og sammenligning) som enheder for udførelse, uanset længden af ​​operanderne. Algoritmen kører i strengt polynomisk tid if

  1. antallet af operationer i den aritmetiske beregningsmodel er begrænset af et polynomium i antallet af heltal i inputstrømmen, og
  2. Hukommelsen, der bruges af algoritmen, er begrænset af et polynomium af inputstørrelsen.

Enhver algoritme med disse to egenskaber kan reduceres til en polynomisk tidsalgoritme ved at erstatte de aritmetiske operationer med de tilsvarende algoritmer til at udføre aritmetiske operationer på en Turing-maskine. Hvis det andet af ovenstående krav ikke er opfyldt, vil dette ikke længere være sandt. Givet et heltal (som optager hukommelse proportionalt med n i en Turing-maskine), kan det beregnes med n operationer ved brug af gentagen eksponentiering. Men den hukommelse, der bruges til repræsentation 2 2 n (\displaystyle 2^(2^(n))), proportional 2 n (\displaystyle 2^(n)), og det afhænger eksponentielt snarere end polynomielt af den hukommelse, der bruges til input. Derfor er det umuligt at udføre disse beregninger i polynomiel tid på en Turing-maskine, men de kan udføres i et polynomielt antal aritmetiske operationer.

Omvendt er der algoritmer, der virker i antallet af Turing-maskinetrin begrænset af polynomielængden af ​​det binært kodede input, men som ikke virker i antallet af aritmetiske operationer begrænset af et polynomium i antallet af tal i inputtet. Euklidisk algoritme til at beregne den største fælles divisor af to heltal er et eksempel. For to heltal a (\displaystyle a) Og b (\displaystyle b) Algoritmedriftstid er begrænset O ((log ⁡ a + log ⁡ b) 2) (\displaystyle O((\log \ a+\log \ b)^(2))) trin af en Turing-maskine. Dette tal er et polynomium af størrelsen af ​​den binære repræsentation af tal a (\displaystyle a) Og b (\displaystyle b), som groft sagt kan repræsenteres som log ⁡ a + log ⁡ b (\displaystyle \log \a+\log \b). Samtidig kan antallet af aritmetiske operationer ikke begrænses til antallet af heltal i inputtet (som i dette tilfælde er en konstant - der er kun to tal i inputtet). På grund af denne bemærkning fungerer algoritmen ikke i strengt polynomisk tid. Algoritmens reelle køretid afhænger af mængderne a (\displaystyle a) Og b (\displaystyle b), og ikke kun antallet af heltal i inputtet.

Hvis en algoritme kører i polynomisk tid, men ikke strengt taget polynomiel tid, siges den at køre i svagt polynomisk tid. Et velkendt eksempel på et problem, for hvilket en svag polynomiel algoritme er kendt, men en strengt polynomiel algoritme ikke er kendt, er lineær programmering. Svag polynomisk tid må ikke forveksles med pseudopolynomiel tid.

Sværhedsklasser

Begrebet polynomisk tid fører til flere kompleksitetsklasser i beregningsmæssig kompleksitetsteori. Nogle vigtige klasser defineret ved hjælp af polynomiel tid er givet nedenfor.

  • : Klasse af løselighedsproblemer, der kan løses i en deterministisk Turing-maskine i polynomiel tid.
  • : Kompleksitetsklassen af ​​løselighedsproblemer, der kan løses i en ikke-deterministisk Turing-maskine i polynomisk tid.
  • ZPP: Kompleksitetsklassen af ​​løselighedsproblemer, der kan løses med nul fejl i en probabilistisk Turing-maskine i polynomiel tid.
  • : Kompleksitetsklassen af ​​løselighedsproblemer, der kan løses med ensidige fejl i en probabilistisk Turing-maskine i polynomiel tid.
  • BPP probabilistisk Turing-maskine i polynomisk tid.
  • BQP: Kompleksitetsklassen af ​​løselighedsproblemer, der kan løses med tovejsfejl i en kvante Turing-maskine i polynomisk tid.

P er den mindste tidskompleksitetsklasse på en deterministisk maskine, som er bæredygtige i forhold til at skifte bilmodel. (For eksempel at gå fra en Turing-maskine med enkelt bånd til en Turing-maskine med flere bånd kan resultere i en kvadratisk hastighedsstigning, men enhver algoritme, der kører i polynomiel tid på den ene model, vil køre i polynomiel tid på den anden.)

Superpolynomisk tid

De siger, at algoritmen virker ind superpolynomisk tid, hvis T(n) er ikke afgrænset ovenfor af et polynomium. Denne tid er lig med ω( n c) for alle konstanter c, Hvor n- input parameter, normalt antallet af input bits.

For eksempel en algoritme, der implementerer 2 n trin for at indtaste størrelse n kræver superpolynomisk tid (mere specifikt eksponentiel tid).

Det er klart, at en algoritme, der bruger eksponentielle ressourcer, er superpolynomiel, men nogle algoritmer er meget svagt superpolynomielle. For eksempel, Adleman-Pomeranz-Roumeli enkelhedstest* virker for tiden n O(log log n) på n-bit input. Dette vokser hurtigere end noget polynomium for stort nok n, men inputstørrelsen skal blive meget stor, så den ikke domineres af lavgradspolynomiet.

En algoritme, der kræver superpolynomisk tid, ligger uden for kompleksitetsklassen. Cobhams afhandling hævder, at disse algoritmer er upraktiske, og det er de i mange tilfælde. Da problemet med lighed mellem klasserne P og NP ikke er blevet løst, kendes der i øjeblikket ingen algoritmer til løsning af NP-komplette problemer i polynomisk tid.

Kvasipolynomisk tid

Algoritmer kvasi-polynomisk tid er algoritmer, der kører langsommere end polynomiel tid, men ikke så langsomt som eksponentielle tidsalgoritmer. Den værste køretid for den kvasi-polynomielle algoritme er c. En velkendt klassisk algoritme til faktorisering af et heltal, , Ikke er kvasi-polynomium, da køretiden ikke kan repræsenteres som 2 O ((log ⁡ n) c) (\displaystyle 2^(O((\log n)^(c)))) for nogle faste c. Hvis konstanten "c" i definitionen af ​​en kvasi-polynomisk tidsalgoritme er 1, får vi en polynomiel tidsalgoritme, og hvis den er mindre end 1, får vi en sublineær tidsalgoritme.

Kvasi-polynomiale-tidsalgoritmer opstår normalt, når et NP-hårdt problem reduceres til et andet problem. For eksempel kan du tage et NP-hårdt problem, f.eks. 3SAT, og reducere det til et andet problem B, men problemets størrelse bliver 2 O ((log ⁡ n) c) (\displaystyle 2^(O((\log n)^(c)))). I dette tilfælde beviser reduktionen ikke, at problem B er NP-hård, den viser kun, at der ikke er nogen polynomiel algoritme for B, medmindre der er en kvasi-polynomiel algoritme for 3SAT (og så for alle -problemer). På samme måde er der nogle problemer, som vi kender kvasi-polynomielle-tidsalgoritmer, men som vi ikke kender polynomielle-tidsalgoritmer til. Sådanne problemer optræder i tilnærmelsesalgoritmer. Et berømt eksempel er det orienterede Steiner-problem, for hvilket der er en tilnærmelses-kvasi-polynomiel algoritme med en tilnærmelseskoefficient O (log 3 ⁡ n) (\displaystyle O(\log ^(3)n))(hvor n er antallet af hjørner), men eksistensen af ​​en polynomiel-tidsalgoritme er et åbent problem.

Sværhedsklasse QP består af alle problemer, der har kvasi-polynomiske tidsalgoritmer. Det kan defineres som DTIME som følger

QP = ⋃ c ∈ N DTIME (2 (log ⁡ n) c) (\displaystyle (\mbox(QP))=\bigcup _(c\in \mathbb (N) )(\mbox(DTIME))(2^ ((\log n)^(c))))

Forbindelse med NP-komplet problemer

I kompleksitetsteorien spørger det uløste problem med lighed mellem klasserne P og NP, om alle problemer i klassen NP har polynomial-tidsløsningsalgoritmer. Alle velkendte algoritmer for NP-komplette problemer, som 3SAT, har eksponentiel tid. Desuden er der en hypotese om, at for mange naturlige NP-komplette problemer er der ingen algoritmer med sub-eksponentiel køretid. Her er "subeksponentiel tid" taget i betydningen af ​​den anden definition givet nedenfor. (På den anden side kan mange grafteoretiske problemer, naturligt repræsenteret af tilstødende matricer, løses i sub-eksponentiel tid, blot fordi størrelsen af ​​input er lig med kvadratet af antallet af toppunkter.) Denne formodning (for k- SAT-problem) er kendt som eksponentiel tidshypotese. Da det antages, at NP-komplette problemer ikke har kvasi-polynomiale-tidsalgoritmer, resulterer nogle utilnærmeligheder i, at domænet af tilnærmelsesalgoritmer antager, at NP-komplette problemer ikke har kvasi-polynomiale-tidsalgoritmer. Se f.eks. de velkendte resultater om ikke-tilnærmeligheden af ​​sætdækningsproblemet.

Subeksponentiel tid

Semester subeksponentiel tid bruges til at udtrykke, at udførelsestiden for en eller anden algoritme kan vokse hurtigere end et hvilket som helst polynomium, men forbliver væsentligt mindre end eksponentielt. I denne forstand er problemer, der har sub-eksponentielle tidsalgoritmer, mere håndterbare end algoritmer med kun eksponentiel tid. Den nøjagtige definition af "subeksponentiel" er endnu ikke generelt accepteret, og vi præsenterer nedenfor de to mest almindelige definitioner.

Første definition

Et problem siges at blive løst i subeksponentiel tid, hvis det løses af en algoritme, hvis logaritme af køretid vokser mindre end et givet polynomium. Mere præcist har et problem sub-eksponentiel tid, hvis der for en hvilken som helst ε > 0 er en algoritme, der løser problemet i O(2 n ε) tid. Sættet af alle sådanne problemer udgør kompleksitetsklassen SUBEXP, som i form af DTIME kan udtrykkes som .

SUBEXP = ⋂ ε > 0 DTIME (2 n ε) (\displaystyle (\text(SUBEXP))=\bigcap _(\varepsilon >0)(\text(DTIME))\left(2^(n^(\varepsilon) ))\højre))

Bemærk at her er ε ikke en del af inputdataene og for hver ε kan der være sin egen algoritme til at løse problemet.

Anden definition

Nogle forfattere definerer sub-eksponentiel tid som en køretid på 2 o( n). Denne definition giver mulighed for længere driftstider end den første definition. Et eksempel på en sådan subeksponentiel tidsalgoritme er den velkendte klassiske algoritme til faktorisering af heltal, den generelle talfeltsigte-metode, som kører i ca. 2 O ~ (n 1 / 3) (\displaystyle 2^((\tilde (O))(n^(1/3)))), hvor inputlængden er n. Et andet eksempel er den velkendte algoritme for grafisk isomorfi problemer, hvis driftstid er lig med 2 O ((n log ⁡ n)) (\displaystyle 2^(O((\sqrt (())n\log n)))).

Bemærk, at det gør en forskel, om algoritmen er subeksponentiel i antallet af hjørner eller antallet af kanter. I parameteriseret kompleksitet denne forskel gøres eksplicit ved at specificere parret, løselighedsproblemet og parameteren k. SUBEPT er klassen af ​​alle parameteriserede opgaver, der kører i sub-eksponentiel tid i k og for et polynomium i n :

SUBEPT = DTIME (2 o (k) ⋅ poly (n)) . (\displaystyle (\text(SUBEPT))=(\text(DTIME))\left(2^(o(k))\cdot (\text(poly))(n)\right).)

Mere præcist er SUBEPT klassen af ​​alle parameteriserede opgaver (L, k) (\displaystyle (L,k)), som der er en beregnelig funktion til f: N → N (\displaystyle f:\mathbb (N) \to \mathbb (N) ) Med f ∈ o (k) (\displaystyle f\in o(k)) og en algoritme, der løser L i løbet af 2 f (k) ⋅ poly (n) (\displaystyle 2^(f(k))\cdot (\text(poly))(n)).

For at sammenligne algoritmer er det sædvanligt at bruge en generaliseret karakteristik kaldet effektivitet. De siger, at algoritme L, mere effektivt algoritme A 2, hvis algoritmen er L, kører den på kortere tid og (eller) kræver færre computerressourcer (RAM, diskplads, netværkstrafik osv.).

En effektiv algoritme skal opfylde kravene om acceptabel eksekveringstid og rimeligt ressourceforbrug, som allerede nævnt i afsnit 1.1. Kombinationen af ​​disse egenskaber udgør begrebet algoritmekompleksitet. Når eksekveringstiden for algoritmen og/eller de involverede ressourcer øges, øges kompleksiteten. Således er begreberne effektivitet og kompleksitet omvendt til hinanden.

Karakteristikken for en algoritme, der afspejler den tid, der bruges på dens implementering, kaldes tidskompleksitet. Egenskaben ved en algoritme, der afspejler computerressourceomkostningerne ved dens implementering, kaldes kapacitiv kompleksitet.

I kvantitative og kvalitative vurderinger af algoritmen relateret til bestemmelse af kompleksitet, anvendes to tilgange - praktiske og teoretiske.

Praktisk tilgang forbundet med faktisk at køre algoritmer på specifikke fysiske enheder. Det er karakteriseret ved parametre, der kan måles og registreres. Tidskompleksitet i denne tilgang kan udtrykkes i tidsenheder (for eksempel millisekunder) eller antallet af processorcyklusser brugt på at udføre algoritmen. Kapacitiv kompleksitet kan udtrykkes i bits (eller andre informationsenheder), de minimumshardwarekrav, der kræves for at udføre algoritmen osv.

Den praktiske evaluering er ikke en absolut indikator for effektiviteten af ​​algoritmen. De kvantitative værdier opnået fra denne tilgang afhænger af mange faktorer, såsom:

  • tekniske karakteristika for de komponenter, der udgør computersystemet. Jo højere processorens klokfrekvens er, jo mere elementære operationer kan der således udføres pr. tidsenhed;
  • karakteristika for softwaremiljøet (antal kørende processer, opgaveplanlæggerens algoritme, funktioner i operativsystemet osv.);
  • det valgte programmeringssprog til implementering af algoritmen. Et program skrevet på et højt niveau sprog vil sandsynligvis køre langsommere og kræve flere ressourcer end et program skrevet på lavt niveau sprog, der har direkte adgang til hardware ressourcer;
  • erfaring fra programmøren, der implementerede algoritmen. Mest sandsynligt vil en nybegynder programmør skrive et mindre effektivt program end en erfaren programmør.

En algoritme, der udføres på det samme computersystem for de samme inputdata, kan således have forskellige kvantitative estimater på forskellige tidspunkter. Derfor er en teoretisk tilgang til at definere kompleksitet vigtigere.

Teoretisk kompleksitet karakteriserer algoritmen uden reference til specifik hardware, software og implementeringsværktøjer. I dette tilfælde er tidskompleksitet udtrykt i antallet af operationer, turing-maskinens driftscyklusser osv. Kapacitiv kompleksitet bestemmes af mængden af ​​data (input, mellemliggende, output), antallet af involverede celler på Thjoring-maskinens bånd osv.

I en teoretisk tilgang til evaluering af effektivitet antages det, at algoritmen udføres på nogle idealiseret computer, for hvilken udførelsestiden for hver type operation er kendt og konstant. Det menes også, at en sådan computers ressourcer er uendelige, så den kapacitive kompleksitet er normalt ikke bestemt i en teoretisk tilgang. Antallet af instruktioner (operationer) udført på en idealiseret computer er valgt som en tidskarakteristik for kompleksitet.

Kvantitative skøn opnået ved hjælp af en teoretisk tilgang kan også afhænge af en række af følgende faktorer:

  • mængden af ​​inputdata. Jo større den er, jo mere tid vil det tage at udføre algoritmen;
  • den valgte metode til at løse problemet. For en stor mængde inputdata er quicksort-algoritmen for eksempel mere effektiv end boblesorteringsalgoritmen, selvom den giver det samme resultat.

Algoritmens udførelsestid afhænger normalt af mængden af ​​inputdata (inputstørrelse), hvilket forstås som dimensionen af ​​det problem, der skal løses. Så når du sorterer et sæt værdier, er datamængden antallet af elementer i dette sæt. Ved behandling af strenge er størrelsen af ​​inputdataene længden af ​​strengen.

Lade P - mængden af ​​inputdata for en eller anden algoritme. Lad os betegne med T(p) antallet af instruktioner, der udføres på en idealiseret computer, når en algoritme udføres, og det bestemmes for "worst case", når volumen af ​​operationer er maksimal.

Begrebet "worst case" kan illustreres med et eksempel. Lad os overveje en algoritme til at kontrollere tilstedeværelsen af ​​et numerisk element i et bestemt sæt (array) af tal. Hvis dette sæt er ordnet i stigende rækkefølge, så er det generelt set ingen mening i at kontrollere de elementer, der er placeret efter det første element, der er større end det søgte. I dette tilfælde T(p) osv. Men i værste fald (for et vilkårligt usorteret sæt), bliver du nødt til at se alle elementer i sættet igennem. Tydeligvis her T(p) = p.

Generelt sagt, T(p) er en funktion af mængden af ​​inputdata P. I mange tilfælde T(p) udtrykt som et polynomium, potens eller logaritmisk funktion af P.

Opførsel af kvantitet T(p) afhængig af forstørrelse P hedder asymptotisk kompleksitet algoritme. Det siger de T(s) Det har kompleksitetsorden 0(J(n))(læser "OM stor fra/fra P") for nogle algoritmer, hvis der er konstante Med og datamængde sch sådan at OP > n 0 og der er ulighed T(s) s/(n).

Dette faktum er skrevet som T(n) = 0(J(n)) og betyder det for funktionen T(p) der er sådan en funktion f(n) og en konstant c, for hvilken, startende fra nogle n 0, betyder T(p) ikke overstiger jf(n).

Fungere f(n) repræsenterer den øvre grænse for funktionsværdierne T(n). Lad f.eks. T(n) = 2p A + n 2. Valg af værdier n 0= 0 og c = 5, for enhver n > n 0 vi har T(n) = 2p A + n 2 T(n) er af orden i 4.

Fungere T(s) er forbundet med en bestemt algoritme, så det siges ofte, at rækkefølgen af ​​kompleksitet 0(/(n)) har præcis algoritmen.

Det siger de T(p) Det har nedre grænse Q(g(n))(læser "omega stor fra g fra /g"), hvis konstanten c og mængden af ​​data findes n 0 sådan at /P og der er ulighed T(n) > cg(n).

Dette faktum er skrevet som T(n) = Q(g(n)). Lad f.eks. T(n) = 2. 4+ n 2. Valg af værdi c = 1, for enhver P vi har T(p)= 2. 4 + p 2 > sp A > derfor, T(s) har en nedre grænse i 4 .

Det er let at se, at rækkefølgen og nedre grænse ikke er unikke for nogle funktioner T(n). I eksemplerne ovenfor kunne man vælge i 5 , i 6 ,... som /(i) og som g(n) - i 3, i 2,.... Normalt vælges funktionen med minimumsgraden som /(i), og som g(n)- med maksimum.

Rækkefølgen af ​​kompleksitet 0(/(i)) og den nedre grænse Q(g(rc)) repræsenterer klasser af funktioner. Intuitivt kan Q(g"(n)) forstås som en klasse af funktioner, der vokser mindst lige så hurtigt som T(n). Ligeledes intuitivt 0(f(n)) kan forstås som en klasse af funktioner, der ikke vokser hurtigere end T(n). MED Fra et praktisk synspunkt, når man vurderer kompleksiteten af ​​en algoritme, er det vigtigste klassen af ​​funktioner 0(f(n)). Bestemmelse af typen af ​​funktion /(i) er hovedopgaven med beregning algoritmens teoretiske kompleksitet.

For enhver algoritme, når du bestemmer graden af ​​vækst, kan du bruge følgende egenskaber for 0(/(i)):

1) 0(kf(ji))= 0(/(i)), hvor k= konst. Den konstante multiplikator i funktionen påvirker således ikke vækstraten. For eksempel,

2) 0(J(ri)"g(n)) = 0(J(n))"0(g(ri)). Således er rækkefølgen af ​​produktet af to funktioner lig med produktet af deres kompleksitet. For eksempel,

Nogle gange skrives denne ejendom som

3) 0(/(p) + g(n)) lige med dominerende(funktioner med maksimal grad) funktioner /(i) og g(n). For eksempel,

I teorien om kompleksitet af algoritmer skelnes følgende klasser af kompleksitetsfunktioner:

  • 1) konstant kompleksitet 0(1). Algorithmens køretid og de anvendte ressourcer afhænger ikke af mængden af ​​inputdata. Typisk har algoritmer, der ikke indeholder loops og rekursive opkald, denne kompleksitet;
  • 2) lineær kompleksitet 0(n). Typisk findes en sådan kompleksitet i opgaver, hvor hvert element af inputdata skal behandles et vist antal gange, hvilket på ingen måde er relateret til antallet af behandlinger af andre elementer;
  • 3) logaritmisk kompleksitet 0(log 2 w), 0 (nog 2 n). Andre logaritmiske baser bruges undertiden;
  • 4) polynomisk kompleksitet 0(i 2), 0(i 3), 0(i 4),...;
  • 5) eksponentiel kompleksitet 2 p, 3",....

Når inputstørrelsen øges, vokser kompleksiteten af ​​hver efterfølgende funktionstype hurtigere end den foregående (undtagen 0(log 2 /?)). For en tilstrækkelig stor mængde inputdata er det at foretrække at bruge algoritmer med mindre kompleksitet.

Når kompleksitet beregnes kvantitativt, vælges til at begynde med en operation eller gruppe af operationer, der er signifikant for denne algoritme (udgør dens grundlag). Disse er normalt sammenligningsoperationer og aritmetiske operationer. Sammenligningsoperationer omfatter kontrol af værdierne af to mængder (mindre end, større end, lig med, mindre end eller lig med, større end eller lig med, ikke lig med). De anses for at være ækvivalente i udførelsestid. Aritmetiske operationer er til gengæld opdelt i tilsætningsstof Og multiplikativ. Til den første (ofte kaldet blot tilføjelse) inkludere tilføjelse, subtrahering, dekrementering eller dekrementering af en tællerværdi. Til den anden (kaldes simpelthen multiplikation) omfatter multiplikation, division, modulo.

Additionsoperationer er hurtigere end multiplikationsoperationer, så algoritmer med færre multiplikationer foretrækkes, selvom antallet af additioner stiger i forhold til antallet af mindskede multiplikationer.

Operationer med heltal multiplikation eller division med potenser af 2 klassificeres som additive operationer, da de, når de arbejder med hukommelsesceller, reduceres til et skift, hvilket svarer til additionsoperationen.

Når væsentlige operationer er blevet udvalgt, er de opdelt i to kategorier:

  • 1) operationer, der direkte påvirker kompleksiteten af ​​algoritmen;
  • 2) operationer, der udgør "overhead", når algoritmen udføres (f.eks. allokering af hukommelse til lagring af mellemliggende data).

Direkte optælling eller estimering af antallet af udførte operationer giver dig mulighed for at estimere T(n).

For at estimere kompleksitetens rækkefølge kan du bruge analyse af programkoden, der implementerer algoritmen. Hvori:

  • algoritmer uden loops og rekursive kald har en kompleksitet af orden 0(1). Således har tildelingsoperationer, datainput og -output og betingede strukturer konstant kompleksitet;
  • hvis to dele af programkoden har vanskeligheder 0(J((ri)) Og 0(J2(n)), så har sekventiel eksekvering kompleksitet
  • hvis løkkens krop udføres én gang for hvert element af inputdataene, så er kompleksiteten ved at udføre løkken af ​​størrelsesordenen 0(n)0( 1) = 0(n);
  • rækkefølgen af ​​kompleksitet af udførelse af indlejrede løkker beregnes ved hjælp af produktreglen 0(J x (n)f2(n)) = 0(/,(/?))- 0(J2(ri)). Hvis hver af dem har en kompleksitet af rækkefølgen 0(n), eksekvering af indlejrede sløjfer har en kompleksitet af rækkefølgen på 0 (n 2).

Eksempel 1.3

Bestem rækkefølgen af ​​kompleksitet af en programalgoritme i et sprog

Pascal vist i oversigt 1.2. Programlinjerne er nummereret som kommentarer (se afsnit 2.6).

Liste 1.2

(01) for i:=l til n do

(02) begynder

(03) write("Enter array element

med indeks ",i,": ");

(04) Readln(MyArray[i]);

(05)ende;

(06) for i:=l til n do

(07) for j:=1 til n do

(08) begynder

(09) write("Enter array element

med indeks ", i, ",", j, " : ");

(10) Readln(MyDArray);

(11) ende;

Løsning

Linje 02, 05, 08, 11 indeholder ikke eksekverbare sætninger, så de tages ikke i betragtning ved bestemmelse af rækkefølgen.

Linje 03 og 04 har rækkefølge 0(1). Deres sekventielle udførelse har rækkefølgen 0(1) + 0(1) = 0(1). På samme måde har udførelse af linje 09 og 10 sekventielt en kompleksitet på 0(1).

Sløjfen i linje 01-05 har en kompleksitet af rækkefølge På), indlejrede løkker i linje 06-11 - rækkefølge 0 (n 2). Algoritmens endelige kompleksitet er af orden

Ved at vurdere kompleksiteten af ​​algoritmen, både tid og ressource, kan vi bestemme den maksimale og gennemsnitlige udførelsestid for algoritmen. Dette er ekstremt vigtigt ved behandling af store mængder information, især i de sorterings- og søgeopgaver, der er beskrevet nedenfor.