Guide til hauger i Python

Guide til hauger i Python

Introduksjon

Se for deg en travel flyplass med fly som tar av og lander hvert minutt. Akkurat som flygeledere prioriterer flyreiser basert på haster, hjelper massevis oss med å administrere og behandle data basert på spesifikke kriterier, og sikrer at den mest «hastende» eller «viktige» databiten alltid er tilgjengelig øverst.

I denne guiden skal vi legge ut på en reise for å forstå hauger fra grunnen av. Vi starter med å avmystifisere hva hauger er og deres iboende egenskaper. Derfra vil vi dykke inn i Pythons egen implementering av hauger, den heapq modul, og utforske dens rike sett med funksjoner. Så hvis du noen gang har lurt på hvordan du effektivt kan administrere et dynamisk sett med data der det høyest (eller laveste) prioriterte elementet ofte er nødvendig, har du en godbit.

Hva er en haug?

Det første du ønsker å forstå før du dykker inn i bruken av hauger er hva er en haug. En haug skiller seg ut i verden av datastrukturer som et trebasert kraftsenter, spesielt dyktig på opprettholde orden og hierarki. Selv om det kan ligne et binært tre for det utrente øyet, skiller nyansene i dets struktur og styrende regler det tydelig.

En av de definerende egenskapene til en haug er dens natur som en komplett binært tre. Dette betyr at hvert nivå av treet, kanskje unntatt det siste, er helt fylt. Innenfor dette siste nivået fylles noder fra venstre til høyre. En slik struktur sikrer at hauger effektivt kan representeres og manipuleres ved hjelp av arrays eller lister, med hvert elements posisjon i arrayen som speiler plasseringen i treet.

guide-to-heaps-in-python-01.png

Den sanne essensen av en haug ligger imidlertid i dens bestilling. I en maks haug, enhver gitt nodes verdi overgår eller er lik verdiene til dens underordnede, og plasserer det største elementet rett ved roten. På den annen side, a min haug opererer på det motsatte prinsippet: en hvilken som helst nodes verdi er enten mindre enn eller lik barnas verdier, noe som sikrer at det minste elementet sitter ved roten.

guide-to-heaps-in-python-02.png

Råd: Du kan visualisere en haug som en pyramide av tall. For en maksimal haug, når du stiger fra basen til toppen, øker tallene, og kulminerer med maksimalverdien på toppen. Derimot starter en min haug med minimumsverdien på topp, med tall som eskalerer etter hvert som du beveger deg nedover.

Etter hvert som vi går videre, vil vi dykke dypere inn i hvordan disse iboende egenskapene til hauger muliggjør effektive operasjoner og hvordan Pythons heapq modulen integrerer sømløst massevis i kodingsarbeidet vårt.

Kjennetegn og egenskaper til hauger

Heaps, med sin unike struktur og ordensprinsipper, frembringer et sett med distinkte egenskaper og egenskaper som gjør dem uvurderlige i ulike beregningsscenarier.

Først og fremst er hauger iboende effektiv. Deres trebaserte struktur, nærmere bestemt det komplette binære treformatet, sikrer at operasjoner som innsetting og utvinning av prioriterte elementer (maksimum eller minimum) kan utføres i logaritmisk tid, vanligvis O (log n). Denne effektiviteten er en velsignelse for algoritmer og applikasjoner som krever hyppig tilgang til prioriterte elementer.

En annen bemerkelsesverdig egenskap til hauger er deres minneeffektivitet. Siden hauger kan representeres ved hjelp av matriser eller lister uten behov for eksplisitte pekere til underordnede eller overordnede noder, er de plassbesparende. Plasseringen til hvert element i arrayet tilsvarer dets plassering i treet, noe som gir mulighet for forutsigbar og enkel kryssing og manipulering.

Bestillingsegenskapen til hauger, enten som en maks haug eller en min haug, sikrer det roten har alltid elementet med høyeste prioritet. Denne konsekvente rekkefølgen er det som gir rask tilgang til det toppprioriterte elementet uten å måtte søke gjennom hele strukturen.

Dessuten er hauger allsidig. Mens binære hauger (der hver forelder har maksimalt to barn) er de vanligste, kan hauger generaliseres til å ha mer enn to barn, kjent som d-ary-hauger. Denne fleksibiliteten gir mulighet for finjustering basert på spesifikke brukstilfeller og ytelseskrav.

Til slutt, hauger er selvjusterende. Hver gang elementer legges til eller fjernes, omorganiserer strukturen seg for å opprettholde egenskapene. Denne dynamiske balanseringen sikrer at haugen til enhver tid forblir optimalisert for kjernevirksomheten.

Råd: Disse egenskapene gjorde at haugdatastrukturen passet godt for en effektiv sorteringsalgoritme – haugsortering. For å lære mer om haugsortering i Python, les vår "Hapsortering i Python" artikkel.

Når vi går dypere inn i Pythons implementering og praktiske applikasjoner, vil det sanne potensialet til hauger utfolde seg foran oss.

Typer av hauger

Ikke alle hauger er skapt like. Avhengig av deres rekkefølge og strukturelle egenskaper, kan hauger kategoriseres i forskjellige typer, hver med sitt eget sett med applikasjoner og fordeler. De to hovedkategoriene er maks haug og min haug.

Det mest karakteristiske trekk ved en maks haug er at verdien til en gitt node er større enn eller lik verdiene til dens barn. Dette sikrer at det største elementet i haugen alltid ligger ved roten. En slik struktur er spesielt nyttig når det er behov for ofte å få tilgang til maksimalelementet, som i visse prioriterte køimplementeringer.

Motstykket til den maksimale haugen, en min haug sikrer at verdien til en gitt node er mindre enn eller lik verdiene til dens barn. Dette plasserer det minste elementet i haugen ved roten. Mine hauger er uvurderlige i scenarier der det minste elementet er av største betydning, for eksempel i algoritmer som omhandler sanntidsdatabehandling.

Utover disse primærkategoriene, kan hauger også skilles ut basert på deres forgreningsfaktor:

Mens binære hauger er de vanligste, med hver forelder som har maksimalt to barn, kan konseptet med hauger utvides til noder som har mer enn to barn. I en d-ær haug, hver node har maksimalt d barn. Denne variasjonen kan optimaliseres for spesifikke scenarier, som å redusere høyden på treet for å fremskynde visse operasjoner.

Binomial haug er et sett med binomiale trær som er definert rekursivt. Binomiale hauger brukes i prioriterte køimplementeringer og tilbyr effektive fletteoperasjoner.

Oppkalt etter den berømte Fibonacci-sekvensen Fibonacci-haug tilbyr bedre amortiserte kjøretider for mange operasjoner sammenlignet med binære eller binomiale hauger. De er spesielt nyttige i nettverksoptimaliseringsalgoritmer.

Pythons Heap-implementering – The heapq Moduler

Python tilbyr en innebygd modul for heap-operasjoner – den heapq modul. Denne modulen gir en samling av heap-relaterte funksjoner som lar utviklere transformere lister til heaps og utføre ulike heap-operasjoner uten behov for en tilpasset implementering. La oss dykke ned i nyansene i denne modulen og hvordan den gir deg kraften til hauger.

De heapq modulen gir ikke en distinkt haugdatatype. I stedet tilbyr den funksjoner som fungerer på vanlige Python-lister, transformerer og behandler dem som binære hauger.

Denne tilnærmingen er både minneeffektiv og integreres sømløst med Pythons eksisterende datastrukturer.

Det betyr det hauger er representert som lister in heapq. Det fine med denne representasjonen er dens enkelhet – det nullbaserte listeindekssystemet fungerer som et implisitt binært tre. For et gitt element i posisjon i, det er:

  • Venstre barn er i posisjon 2*i + 1
  • Høyre barn er i posisjon 2*i + 2
  • Foreldre node er på plass (i-1)//2

guide-to-heaps-in-python-03.png

Denne implisitte strukturen sikrer at det ikke er behov for en separat nodebasert binær trerepresentasjon, noe som gjør operasjoner enkle og minnebruk minimal.

Romkompleksitet: Heaps er vanligvis implementert som binære trær, men krever ikke lagring av eksplisitte pekere for underordnede noder. Dette gjør dem plasseffektive med en plasskompleksitet på O (n) for lagring av n elementer.

Det er viktig å merke seg at heapq moduler oppretter min hauger som standard. Dette betyr at det minste elementet alltid er ved roten (eller den første posisjonen i listen). Hvis du trenger en maksimal haug, må du invertere rekkefølgen ved å multiplisere elementer med -1 eller bruk en tilpasset sammenligningsfunksjon.

Pythons heapq modulen gir en rekke funksjoner som lar utviklere utføre ulike heap-operasjoner på lister.

OBS: For å bruke heapq modul i applikasjonen din, må du importere den ved hjelp av simple import heapq.

I de følgende delene vil vi dykke dypt inn i hver av disse grunnleggende operasjonene, og utforske deres mekanikk og bruksområder.

Hvordan forvandle en liste til en haug

De heapify() funksjon er utgangspunktet for mange heap-relaterte oppgaver. Det tar en iterabel (vanligvis en liste) og omorganiserer elementene på plass for å tilfredsstille egenskapene til en min haug:

Sjekk ut vår praktiske, praktiske guide for å lære Git, med beste praksis, bransjeaksepterte standarder og inkludert jukseark. Slutt å google Git-kommandoer og faktisk lære den!

import heapq data = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
heapq.heapify(data)
print(data)

Dette vil sende ut en omorganisert liste som representerer en gyldig min haug:

[1, 1, 2, 3, 3, 9, 4, 6, 5, 5, 5]

Tidskompleksitet: Konvertering av en uordnet liste til en haug ved hjelp av heapify funksjon er en O (n) operasjon. Dette kan virke motintuitivt, slik man kan forvente at det skal være O (nlogn), men på grunn av trestrukturens egenskaper kan det oppnås i lineær tid.

Hvordan legge til et element i haugen

De heappush() funksjonen lar deg sette inn et nytt element i haugen mens du opprettholder haugens egenskaper:

import heapq heap = []
heapq.heappush(heap, 5)
heapq.heappush(heap, 3)
heapq.heappush(heap, 7)
print(heap)

Å kjøre koden vil gi deg en liste over elementer som opprettholder min heap-egenskapen:

[3, 5, 7]

Tidskompleksitet: Innsettingsoperasjonen i en haug, som innebærer å plassere et nytt element i haugen mens haugegenskapen opprettholdes, har en tidskompleksitet på O (logn). Dette er fordi elementet i verste fall må reise fra bladet til roten.

Hvordan fjerne og returnere det minste elementet fra haugen

De heappop() funksjon trekker ut og returnerer det minste elementet fra haugen (roten i en min haug). Etter fjerning sikrer det at listen forblir en gyldig haug:

import heapq heap = [1, 3, 5, 7, 9]
print(heapq.heappop(heap))
print(heap)

OBS: De heappop() er uvurderlig i algoritmer som krever behandlingselementer i stigende rekkefølge, som Heap Sort-algoritmen, eller når du implementerer prioriterte køer der oppgaver utføres basert på deres haster.

Dette vil gi ut det minste elementet og den gjenværende listen:

1
[3, 7, 5, 9]

Her 1 er det minste elementet fra heap, og den gjenværende listen har opprettholdt heap-egenskapen, selv etter at vi fjernet 1.

Tidskompleksitet: Å fjerne rotelementet (som er det minste i en min haug eller størst i en maks haug) og omorganisere haugen tar også O (logn) tid.

Hvordan skyve en ny gjenstand og sprette den minste gjenstanden

De heappushpop() funksjon er en kombinert operasjon som skyver et nytt element inn på haugen og deretter spretter og returnerer det minste elementet fra haugen:

import heapq heap = [3, 5, 7, 9]
print(heapq.heappushpop(heap, 4)) print(heap)

Dette vil skrive ut 3, det minste elementet, og skriv ut det nye heap liste som nå inkluderer 4 mens du opprettholder haugegenskapen:

3
[4, 5, 7, 9]

OBS: Bruke heappushpop() funksjonen er mer effektiv enn å utføre operasjoner med å skyve et nytt element og sprette det minste separat.

Hvordan erstatte den minste gjenstanden og skyve en ny gjenstand

De heapreplace() funksjonen åpner det minste elementet og skyver et nytt element inn på haugen, alt i en effektiv operasjon:

import heapq heap = [1, 5, 7, 9]
print(heapq.heapreplace(heap, 4))
print(heap)

Dette skrives ut 1, det minste elementet, og listen inkluderer nå 4 og opprettholder heap-egenskapen:

1
[4, 5, 7, 9]

Merknader: heapreplace() er fordelaktig i streaming-scenarier der du ønsker å erstatte det gjeldende minste elementet med en ny verdi, for eksempel i rullende vinduoperasjoner eller sanntidsdatabehandlingsoppgaver.

Finne flere ekstremer i Python's Heap

nlargest(n, iterable[, key]) og nsmallest(n, iterable[, key]) funksjoner er designet for å hente flere største eller minste elementer fra en iterabel. De kan være mer effektive enn å sortere hele iterable når du bare trenger noen få ekstreme verdier. Si for eksempel at du har følgende liste og du vil finne tre minste og tre største verdier i listen:

data = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]

Her nlargest() og nsmallest() funksjoner kan komme godt med:

import heapq data = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
print(heapq.nlargest(3, data)) print(heapq.nsmallest(3, data)) 

Dette vil gi deg to lister – den ene inneholder de tre største verdiene og den andre inneholder de tre minste verdiene fra data liste:

[9, 6, 5]
[1, 1, 2]

Hvordan bygge din egendefinerte haug

Mens Python er heapq modulen gir et robust sett med verktøy for å jobbe med heaps, det er scenarier der standard min heap-atferd kanskje ikke er tilstrekkelig. Enten du ønsker å implementere en maks haug eller trenger en haug som opererer basert på tilpassede sammenligningsfunksjoner, kan å bygge en tilpasset haug være svaret. La oss utforske hvordan du kan skreddersy hauger til spesifikke behov.

Implementering av en Max Heap ved hjelp av heapq

Som standard heapq skaper min hauger. Men med et enkelt triks kan du bruke det til å implementere en maksimal haug. Tanken er å invertere rekkefølgen på elementene ved å multiplisere dem med -1 før du legger dem til haugen:

import heapq class MaxHeap: def __init__(self): self.heap = [] def push(self, val): heapq.heappush(self.heap, -val) def pop(self): return -heapq.heappop(self.heap) def peek(self): return -self.heap[0]

Med denne tilnærmingen blir det største tallet (i form av absolutt verdi) det minste, noe som tillater heapq funksjoner for å opprettholde en maksimal haugstruktur.

Massevis med tilpassede sammenligningsfunksjoner

Noen ganger kan det hende du trenger en haug som ikke bare sammenlignes basert på den naturlige rekkefølgen av elementer. Hvis du for eksempel jobber med komplekse objekter eller har spesifikke sorteringskriterier, blir en tilpasset sammenligningsfunksjon viktig.

For å oppnå dette kan du pakke elementer inn i en hjelpeklasse som overstyrer sammenligningsoperatorene:

import heapq class CustomElement: def __init__(self, obj, comparator): self.obj = obj self.comparator = comparator def __lt__(self, other): return self.comparator(self.obj, other.obj) def custom_heappush(heap, obj, comparator=lambda x, y: x < y): heapq.heappush(heap, CustomElement(obj, comparator)) def custom_heappop(heap): return heapq.heappop(heap).obj

Med dette oppsettet kan du definere hvilken som helst egendefinert komparatorfunksjon og bruke den med heapen.

konklusjonen

Heaps tilbyr forutsigbar ytelse for mange operasjoner, noe som gjør dem til et pålitelig valg for prioriterte oppgaver. Det er imidlertid viktig å vurdere de spesifikke kravene og egenskapene til den aktuelle applikasjonen. I noen tilfeller kan det å justere haugens implementering eller til og med velge alternative datastrukturer gi bedre ytelse i den virkelige verden.

Heaps, som vi har reist gjennom, er mer enn bare en annen datastruktur. De representerer et sammenløp av effektivitet, struktur og tilpasningsevne. Fra deres grunnleggende egenskaper til deres implementering i Python's heapq modul tilbyr heaps en robust løsning på et utall av beregningsmessige utfordringer, spesielt de som er sentrert rundt prioritet.

Tidstempel:

Mer fra Stackabuse