Datastrukturer: En Dypdykk i Stakken
I programmeringens verden spiller datastrukturer en avgjørende rolle. De er fundamentet for hvordan vi organiserer og administrerer data, noe som har stor innvirkning på effektiviteten til kode. Blant de mest grunnleggende datastrukturene finner vi stakken.
La oss utforske stakken og hvordan vi implementerer den ved hjelp av Python.
Hva kjennetegner en Stakk?
En stakk kan illustreres med en stabel av bøker eller stoler i den fysiske verden. Den opererer etter prinsippet «sist inn, først ut» (LIFO). Dette gjør stakken til en svært enkel, men likevel kraftfull datastruktur. Tenk deg en bunke med bøker; for å få tak i den tredje boken fra toppen, må du fjerne de to øverste først. På samme måte fungerer en stakk innenfor programmering: det elementet som legges til sist, er det første som fjernes.
Stakkoperasjoner
Det finnes primært to basisoperasjoner i en stakk:
1. push(data)
Denne operasjonen tilfører et nytt element, «data», til toppen av stakken.
2. pop()
Denne operasjonen fjerner elementet som ligger øverst i stakken og returnerer det.
For bedre å visualisere disse prosessene, se illustrasjonene under:
I tillegg finnes det hjelpefunksjoner som gir oss mer innsikt i stakkens tilstand:
kikk()
Denne funksjonen returnerer elementet på toppen av stakken uten å fjerne det.
er_tom()
Denne funksjonen sjekker om stakken er tom eller ikke og returnerer en boolsk verdi (True eller False).
Med det konseptuelle grunnlaget på plass, er vi nå klare til å se på implementeringen i praksis.
Implementering av Stakken i Python
Det finnes flere måter å implementere en stakk i Python, hver med sine fordeler og ulemper. La oss utforske noen av de mest vanlige metodene.
#1. Liste som Stakk
En vanlig tilnærming er å bruke en Python-liste som grunnlag for stakken. Ved å kapsle inn listefunksjonaliteten i en klasse, oppnår vi et mer strukturert og lesbart kodebilde.
Trinn 1: Definer en klasse med navnet «Stakk».
class Stakk: pass
Trinn 2: Initialiser en tom liste for å holde elementene.
class Stakk: def __init__(self): self.elementer = []
Trinn 3: Implementer «push»-metoden for å legge til elementer.
class Stakk: def __init__(self): self.elementer = [] def push(self, data): self.elementer.append(data) return data
Trinn 4: Implementer «pop»-metoden for å fjerne elementer.
class Stakk: ## ... def pop(self): return self.elementer.pop()
Trinn 5: Implementer «kikk»-metoden for å se det øverste elementet.
class Stakk: ## ... def kikk(self): return self.elementer[-1]
Trinn 6: Implementer «er_tom»-metoden for å sjekke om stakken er tom.
class Stakk: ## ... def er_tom(self): return len(self.elementer) == 0
Nå som stakkeklassen er ferdig, la oss se hvordan vi bruker den i praksis.
class Stakk: ## ... if __name__ == '__main__': stakk = Stakk()
Test stakk-operasjonene:
- Sjekk om stakken er tom ved å bruke «er_tom»-metoden.
- Legg til tallene 1, 2, 3, 4, 5 i stakken med «push»-metoden.
- Bekreft at stakken ikke lenger er tom.
- Hent det øverste elementet med «kikk»-metoden.
- Fjern det øverste elementet med «pop»-metoden.
- Sjekk det nye øverste elementet med «kikk».
- Tøm stakken ved å fjerne alle elementer.
- Bekreft at stakken er tom igjen.
Fullstendig kodeeksempel:
class Stakk: def __init__(self): self.elementer = [] def push(self, data): self.elementer.append(data) return data def pop(self): return self.elementer.pop() def kikk(self): return self.elementer[-1] def er_tom(self): return len(self.elementer) == 0 if __name__ == '__main__': stakk = Stakk() ## Sjekker om den er tom -> true print(stakk.er_tom()) ## Legger til elementene stakk.push(1) stakk.push(2) stakk.push(3) stakk.push(4) stakk.push(5) ## Sjekker igjen om den er tom -> false print(stakk.er_tom()) ## Skriver ut det øverste elementet -> 5 print(stakk.kikk()) ## Fjerner det øverste elementet -> 5 stakk.pop() ## Sjekker det øverste elementet med peek -> 4 print(stakk.kikk()) ## Fjerner alle elementene stakk.pop() stakk.pop() stakk.pop() stakk.pop() ## Sjekker om den er tom for siste gang -> true print(stakk.er_tom())
Utdata:
True False 5 4 True
Det er viktig å huske at vi kan bruke Python sine innebygde lister direkte som en stakk, men den ovennevnte implementasjonen hjelper å forstå prinsippet bedre.
#2. Deque fra Samlingsmodulen
En annen metode er å bruke «deque» (dobbelt-ended kø) fra Pythons «collections»-modul. Den støtter effektiv tilføying og fjerning av elementer fra begge ender, noe som gjør den egnet for å implementere en stakk.
Metodene vi bruker er:
- `append(data)`: Legger til et element på toppen av stakken.
- `pop()`: Fjerner og returnerer det øverste elementet fra stakken.
Siden «deque» ikke har en direkte «kikk»-metode, kan vi skrive ut hele stakken for å se innholdet. For å sjekke om stakken er tom, kan vi bruke `len()`.
Kodeeksempel:
from collections import deque ## Oppretter et deque-objekt stakk = deque() ## Sjekker om stakken er tom -> true print(len(stakk) == 0) ## Legger til elementene stakk.append(1) stakk.append(2) stakk.append(3) stakk.append(4) stakk.append(5) ## Sjekker om stakken er tom igjen -> false print(len(stakk) == 0) ## Skriver ut stakken print(stakk) ## Fjerner det øverste elementet -> 5 stakk.pop() ## Skriver ut stakken print(stakk) ## Fjerner alle elementene stakk.pop() stakk.pop() stakk.pop() stakk.pop() ## Sjekker om stakken er tom for siste gang -> true print(len(stakk) == 0)
Utdata:
True False deque([1, 2, 3, 4, 5]) deque([1, 2, 3, 4]) True
#3. LifoQueue fra Kømodulen
Den tredje tilnærmingen er å benytte «LifoQueue» (Last In First Out Queue) fra Pythons innebygde «queue»-modul. Som navnet tilsier, følger denne strukturen LIFO-prinsippet og er derfor en direkte stakk-implementering.
Noen av de viktigste metodene:
- `put(data)`: Legger til elementer på toppen av stakken.
- `get()`: Fjerner og returnerer det øverste elementet.
- `empty()`: Sjekker om stakken er tom.
- `qsize()`: Returnerer antall elementer i stakken.
Kodeeksempel:
from queue import LifoQueue ## Oppretter et LifoQueue-objekt stakk = LifoQueue() ## Sjekker om stakken er tom -> true print(stakk.empty()) ## Legger til elementene stakk.put(1) stakk.put(2) stakk.put(3) stakk.put(4) stakk.put(5) ## Sjekker igjen om stakken er tom -> false print(stakk.empty()) ## Fjerner alle elementene print(stakk.get()) print(stakk.get()) print(stakk.get()) ## Sjekker størrelsen på stakken print("Størrelse", stakk.qsize()) print(stakk.get()) print(stakk.get()) ## Sjekker om stakken er tom for siste gang -> true print(stakk.empty())
Utdata:
True False 5 4 3 Størrelse 2 2 1 True
Anvendelser av Stakken
Stakken har mange praktiske anvendelser innen programmering. La oss se på et klassisk eksempel: balansering av parenteser.
Oppgaven går ut på å sjekke om et gitt uttrykk med parenteser, klammeparenteser og krøllparenteser er korrekt balansert. For eksempel er «[{}]([])» balansert, mens «{[}]([])» ikke er det.
Løsningen er å bruke en stakk:
- Opprett en stakk for å lagre åpningsparentesene.
- Dersom lengden på uttrykket er et oddetall, er det ikke balansert.
- Iterer gjennom uttrykket:
- Hvis vi møter en åpningsparentes («(«, «{«, «[«), legg den til i stakken.
- Hvis vi møter en lukkeparentes («)», «}», «]»), fjern den øverste parentesen fra stakken.
- Hvis den fjernede parentesen ikke matcher den lukkende, er uttrykket ikke balansert.
- Til slutt, hvis stakken er tom, er uttrykket balansert.
Kodeeksempel:
## stakk class Stakk: def __init__(self): self.elementer = [] def push(self, data): self.elementer.append(data) return data def pop(self): return self.elementer.pop() def kikk(self): return self.elementer[-1] def er_tom(self): return len(self.elementer) == 0 def balansesjekk(uttrykk): ## Sjekker lengden på uttrykket if len(uttrykk) % 2 != 0: ## ikke balansert hvis lengden er oddetall return False ## for sjekking åpningsparenteser = set('([{') par = set([ ('(',')'), ('[',']'), ('{','}') ]) ## Initialiserer stakken stakk = Stakk() ## Itererer gjennom uttrykket for parentes in uttrykk: ## Sjekker om nåværende parentes er en åpningsparentes if parentes in åpningsparenteser: ## Legger til i stakken stakk.push(parentes) else: ## Fjerner den siste parentesen fra stakken fjernet_parentes = stakk.pop() ## Sjekker om den fjernede og nåværende parentes er et par if (fjernet_parentes, parentes) not in par: return False return stakk.er_tom() if __name__ == '__main__': if balansesjekk('[{}]([])'): print("Balansert") else: print("Ikke Balansert") if balansesjekk('{[}]([])'): print("Balansert") else: print("Ikke Balansert")
Dette er bare ett eksempel på hvordan stakker kan brukes til å løse problemer. Stakker brukes også i blant annet: funksjonskall i programmer, reversering av ord og mye mer.
Konklusjon
Med dette er vi ved veis ende i denne veiledningen. Vi har utforsket hva stakker er, hvordan de fungerer, og sett på forskjellige implementeringsmetoder i Python. Vi har også sett på et praktisk eksempel. Jeg håper at du føler deg komfortabel med å bruke stakker i dine egne programmeringsprosjekter.
Lykke til med kodingen! 👨💻