Modern förståelse av rekursion: definition av funktionalitet och tillgång till den utifrån och från denna funktionalitet. Man tror att rekursion föddes av matematiker: faktorberäkning, oändliga serier, fraktaler, fortsatta bråk … Dock kan rekursion hittas överallt. Objektiva naturlagar "betraktar" rekursion som sin huvudsakliga algoritm och uttrycksform (existens), inte så mycket av den materiella världens föremål, utan i allmänhet den huvudsakliga algoritmen för rörelse.
Människor med olika specialiteter inom olika vetenskaps- och teknikområden använder den rekursiva algoritmen f (x), där "x ~/=f (x)". En funktion som kallar sig själv är en stark lösning, men att forma och förstå denna lösning är i de flesta fall en mycket svår uppgift.
I gamla tider användes rekursion för att utöka palatsutrymmet. Genom ett system av speglar riktade mot varandra kan du skapa fantastiska tredimensionella rumsliga effekter. Men är det så lätt att förstå hurjustera dessa speglar? Det är ännu svårare att avgöra var en punkt i rymden är, reflekterad genom flera speglar.
Rekursion, rekursiva algoritmer: betydelse och syntax
Problemet, som formuleras genom att upprepa en sekvens av operationer, kan lösas rekursivt. En enkel algoritm (att beräkna en andragradsekvation, ett skript för att fylla en webbsida med information, läsa en fil, skicka ett meddelande…) kräver ingen rekursion.
Huvudskillnaderna i algoritmen som tillåter en rekursiv lösning:
- det finns en algoritm som måste köras flera gånger;
- algoritmen behöver data som ändras varje gång;
- algoritmen behöver inte ändras varje gång;
- det finns ett sista villkor: algoritmen är rekursiv - inte oändlig.
Generellt kan det inte hävdas att engångsavrättning är en nödvändig förutsättning för avsaknad av skäl till rekursion. Du kan inte heller kräva ett obligatoriskt slutvillkor: oändliga rekursioner har sin egen omfattning.
Algorithmen är rekursiv: när en sekvens av operationer utförs upprepade gånger, på data som ändras varje gång och ger ett nytt resultat varje gång.
Rekursionsformel
Den matematiska förståelsen av rekursion och dess analoga i programmering är annorlunda. Matematik, även om det finns tecken på programmering, men programmering är matematik av mycket högre ordning.
En välskriven algoritm är som en spegel av författarens intellekt. Allmänrekursionsformeln i programmering är "f(x)", där "x ~/=f(x)" har minst två tolkningar. Här är "~" likheten eller frånvaron av resultatet, och "=" är närvaron av resultatet av funktionen.
Första alternativet: datadynamik.
- funktionen "f(x)" har en rekursiv och oföränderlig algoritm;
- "x" och resultatet "f(x)" har nya värden varje gång, resultatet "f(x)" är den nya "x"-parametern för denna funktion.
Andra alternativet: koddynamik.
- funktionen "f(x)" har flera algoritmer som förfinar (analyserar) data;
- dataanalys - en del av koden och implementering av rekursiva algoritmer som utför önskad åtgärd - den andra delen av koden;
- resultatet av funktionen "f(x)" är inte.
Inget resultat är norm alt. Programmering är inte matematik, här behöver resultatet inte vara explicit närvarande. En rekursiv funktion kan helt enkelt analysera platser och fylla i databasen, eller instansiera objekt enligt den inkommande inmatningen.
Data och rekursion
Programmering av rekursiva algoritmer handlar inte om att beräkna en faktor, där funktionen varje gång får ett givet värde som är ett mer eller mindre än ett - implementerings alternativet beror på utvecklarens preferens.
Det spelar ingen roll hur "8!"algoritm som strikt följer denna formel.
Bearbetning av information är "matematik" av en helt annan ordning. Rekursiva funktioner och algoritmer här fungerar på bokstäver, ord, fraser, meningar och stycken. Varje nästa nivå använder den föregående.
Indataströmmen analyseras över ett brett spektrum av förhållanden, men analysprocessen är i allmänhet rekursiv. Det är ingen mening att skriva unika algoritmer för alla varianter av ingångsströmmen. Det bör finnas en funktionalitet. Här är rekursiva algoritmer exempel på hur man bildar en utdataström som är tillräcklig för ingången. Detta är inte resultatet av den rekursiva algoritmen, men det är den önskade och nödvändiga lösningen.
Abstraktion, rekursion och OOP
Objektorienterad programmering (OOP) och rekursion är fundament alt olika enheter, men de kompletterar varandra perfekt. Abstraktion har inget med rekursion att göra, men genom linsen för OOP skapar den möjligheten att implementera kontextuell rekursion.
Till exempel, information analyseras och bokstäver, ord, fraser, meningar och stycken markeras separat. Uppenbarligen kommer utvecklaren att se till att instanser av objekt av dessa fem typer skapas och erbjuda en lösning av rekursiva algoritmer på varje nivå.
Under tiden, om på bokstävernivå "det är ingen mening att leta efter mening", så dyker semantik upp på ordnivå. Du kan dela in ord i verb, substantiv, adverb, prepositioner… Du kan gå längre och definiera kasus.
På frasnivå kompletteras semantiken med skiljetecken och logikordkombinationer. På meningsnivån finns en mer perfekt nivå av semantik, och ett stycke kan betraktas som en fullständig tanke.
Objektorienterad utveckling förutbestämmer arvet av egenskaper och metoder och föreslår att man startar hierarkin av objekt med skapandet av en helt abstrakt förfader. Samtidigt, utan tvekan, kommer analysen av varje ättling att vara rekursiv och kommer inte att skilja sig alltför mycket på teknisk nivå i många positioner (bokstäver, ord, fraser och meningar). Stycken, som fullständiga tankar, kan sticka ut från den här listan, men de är inte kärnan.
Det är viktigt att den överväldigande delen av algoritmen kan formuleras på den abstrakta förfadernivån, förfina den på nivån för varje ättling med data och metoder som anropas från den abstrakta nivån. I detta sammanhang öppnar abstraktion upp nya horisonter för rekursion.
Historiska funktioner i OOP
OOP har kommit till mjukvaruvärlden två gånger, även om vissa experter kanske pekar ut framväxten av cloud computing och moderna idéer om objekt och klasser som en ny omgång i utvecklingen av IT-teknik.
Termen "objekt" och "objektiv" i den moderna kontexten av OOP tillskrivs vanligtvis 50- och 60-talen av förra seklet, men de är förknippade med 1965 och framväxten av Simula, Lisp, Algol, Smalltalk.
På den tiden var programmering inte särskilt utvecklad och kunde inte svara på revolutionerande koncept. Kampen mellan idéer och programmeringsstilar (C / C ++ och Pascal - mestadels) var fortfarande långt borta, och databaser var fortfarande konceptuellt bildade.
I slutet av 80-talet och början av 90-talet dök objekt upp i Pascal och alla kom ihåg klasser i C/C ++ – detta markerade en ny intresserunda för OOP och det var då som verktyg, främst programmeringsspråk, inte blev stöder bara objektorienterade idéer, men utvecklas därefter.
Naturligtvis, om tidigare rekursiva algoritmer bara var funktioner som användes i programmets allmänna kod, skulle nu rekursion kunna bli en del av egenskaperna hos ett objekt (klass), vilket gav intressanta möjligheter i samband med arv.
Funktion av modern OOP
Utvecklingen av OOP-deklarerade objekt (klasser) från början som samlingar av data och egenskaper (metoder). I själva verket handlade det om data som har syntax och mening. Men då gick det inte att presentera OOP som ett verktyg för att hantera riktiga objekt.
OOP har blivit ett verktyg för att hantera "computer nature"-objekt. Ett skript, en knapp, ett meny alternativ, en menyrad, en tagg i ett webbläsarfönster är ett objekt. Men inte en maskin, en livsmedelsprodukt, ett ord eller en mening. Verkliga objekt har stått utanför objektorienterad programmering, och datorverktyg har fått en ny inkarnation.
På grund av skillnaderna i populära programmeringsspråk har många dialekter av OOP dykt upp. När det gäller semantik är de praktiskt taget likvärdiga, och deras fokus på den instrumentella sfären, och inte på den tillämpade, gör det möjligt att ta beskrivningen av verkliga objekt bortomalgoritmer och säkerställer deras "existens" på flera plattformar och på flera språk.
Stackar och funktionsanropsmekanismer
Mekanismer för att anropa funktioner (procedurer, algoritmer) kräver att data (parametrar) skickas, returnera ett resultat och komma ihåg adressen till operatören som måste ta emot kontroll efter att funktionen (proceduren) har slutförts.
Vanligtvis används stacken för detta ändamål, även om programmeringsspråk eller utvecklaren själv kan tillhandahålla en mängd olika alternativ för att överföra kontroll. Modern programmering medger att namnet på en funktion inte bara kan vara en parameter: det kan bildas under exekveringen av algoritmen. En algoritm kan också skapas medan en annan algoritm körs.
Konceptet med rekursiva algoritmer, när deras namn och kroppar kan bestämmas vid tidpunkten för bildandet av uppgiften (välja den önskade algoritmen), utökar rekursiviteten inte bara till hur man gör något, utan också vem som exakt ska gör det. Att välja en algoritm med dess "meningsfulla" namn är lovande, men skapar svårigheter.
Rekursivitet på en uppsättning funktioner
Du kan inte säga att en algoritm är rekursiv när den kallar sig själv och det är det. Programmering är inte en dogm, och begreppet rekursivitet är inte ett exklusivt krav för att ringa dig själv utifrån din egen algoritm.
Praktiska tillämpningar ger inte alltid en ren lösning. Ofta måste initialdata förberedas och resultatet av det rekursiva anropet måste analyseras i sammanhanget av hela problemet (hela algoritmen) itot alt.
Faktiskt, inte bara innan en rekursiv funktion anropas, utan även efter att den har slutförts, kan eller bör ett annat program anropas. Om det inte finns några speciella problem med anropet: den rekursiva funktionen A() anropar funktionen B(), som gör något och anropar A(), så uppstår omedelbart ett problem med återgången av kontrollen. Efter att ha slutfört det rekursiva anropet måste funktionen A() ta emot kontroll för att återanropa B(), som kommer att anropa den igen. Att återföra kontrollen som den ska vara i ordning på stacken tillbaka till B() är fel lösning.
Programmeraren är inte begränsad i valet av parametrar och kan komplettera dem med funktionsnamn. Med andra ord, den idealiska lösningen är att skicka namnet på B() till A() och låta A() själv anropa B(). I det här fallet kommer det inte att finnas några problem med att återföra kontroll, och implementeringen av den rekursiva algoritmen kommer att vara mer transparent.
Förståelse och nivå av rekursion
Problemet med att utveckla rekursiva algoritmer är att du måste förstå dynamiken i processen. När du använder rekursion i objektmetoder, särskilt på nivån för en abstrakt förfader, finns det ett problem med att förstå din egen algoritm i samband med dess exekveringstid.
För närvarande finns det inga begränsningar på kapslingsnivån för funktioner och stackkapacitet i anropsmekanismer, men det finns ett problem att förstå: vid vilken tidpunkt vilken datanivå eller vilken plats i den allmänna algoritmen som kallas rekursiven funktion och på vilket antal samtal hon själv är.
Befintliga felsökningsverktyg är ofta maktlösatala om för programmeraren den rätta lösningen.
Slingor och rekursion
Det anses att cyklisk exekvering är likvärdig med rekursion. I vissa fall kan den rekursiva algoritmen faktiskt implementeras i syntaxen för villkorliga och cykliska konstruktioner.
Men om det finns en klar förståelse för att en viss funktion måste implementeras genom en rekursiv algoritm, bör all extern användning av en loop eller villkorssatser överges.
Meningen här är att en rekursiv lösning i form av en funktion som använder sig själv kommer att vara en komplett, funktionellt komplett algoritm. Denna algoritm kommer att kräva att programmeraren skapar den med ansträngning och förstår dynamiken i algoritmen, men det kommer att vara den slutliga lösningen som inte kräver extern kontroll.
Varje kombination av externa villkorliga och cykliska operatorer tillåter oss inte att representera den rekursiva algoritmen som en komplett funktion.
Rekursionskonsensus och OOP
I nästan alla varianter av att utveckla en rekursiv algoritm, uppstår en plan för att utveckla två algoritmer. Den första algoritmen genererar en lista över framtida objekt (instanser), och den andra algoritmen är faktiskt en rekursiv funktion.
Den bästa lösningen skulle vara att ordna rekursion som en enda egenskap (metod) som faktiskt innehåller den rekursiva algoritmen, och lägga allt förberedande arbete i objektkonstruktorn.
En rekursiv algoritm är bara den rätta lösningen när den fungerarendast av honom själv, utan extern kontroll och ledning. En extern algoritm kan bara ge en signal att fungera. Resultatet av detta arbete bör vara den förväntade lösningen, utan externt stöd.
Rekursion ska alltid vara en komplett fristående lösning.
Intuitiv förståelse och funktionell fullständighet
När objektorienterad programmering blev de facto-standarden blev det uppenbart att för att koda effektivt måste du ändra ditt eget tänkande. Programmeraren måste gå från språkets syntax och semantik till dynamiken i semantiken under exekveringen av algoritmen.
Kännetecknande för rekursion: den kan appliceras på allt:
- web scraping;
- sökoperationer;
- parsar textinformation;
- läsa eller skapa MS Word-dokument;
- sampling eller analys av taggar…
Kännetecknande för OOP: det gör det möjligt att beskriva en rekursiv algoritm på nivån för en abstrakt förfader, men se till att den hänvisar till unika avkomlingar, som var och en har sin egen palett av data och egenskaper.
Rekursion är idealisk eftersom den kräver den funktionella fullständigheten hos dess algoritm. OOP förbättrar prestandan för en rekursiv algoritm genom att ge den tillgång till alla unika barn.