Witaj z powrotem, @name! Darwin tutaj z ostatnimi strukturami danych przed rekursją.
Wyobraź sobie organizowanie ekspedycji:
To są właśnie stosy (stacks) i kolejki (queues) - fundamentalne struktury danych!
Stack to struktura danych gdzie ostatni dodany element jest pierwszy do usunięcia (LIFO - Last In, First Out).
Analogia Safari: Stos talerzy - bierzesz talerz z góry (ostatni dodany), nie z dołu.
| Operacja | Złożoność | Opis | |----------|-----------|------| | push(x) | O(1) | Dodaj element na szczyt | | pop() | O(1) | Usuń i zwróć element ze szczytu | | peek() / top() | O(1) | Zobacz element na szczycie (bez usuwania) | | is_empty() | O(1) | Sprawdź czy stos jest pusty | | size() | O(1) | Zwróć liczbę elementów |
1# Sposób 1: Lista Pythona (najprostsze!)
2class Stack:
3 """Implementacja stosu używając listy"""
4
5 def __init__(self):
6 self.items = []
7
8 def push(self, item):
9 """Dodaj element na szczyt - O(1)"""
10 self.items.append(item)
11
12 def pop(self):
13 """Usuń i zwróć element ze szczytu - O(1)"""
14 if self.is_empty():
15 raise IndexError("Stack jest pusty!")
16 return self.items.pop()
17
18 def peek(self):
19 """Zobacz element na szczycie - O(1)"""
20 if self.is_empty():
21 raise IndexError("Stack jest pusty!")
22 return self.items[-1]
23
24 def is_empty(self):
25 """Sprawdź czy stos jest pusty - O(1)"""
26 return len(self.items) == 0
27
28 def size(self):
29 """Zwróć liczbę elementów - O(1)"""
30 return len(self.items)
31
32 def __str__(self):
33 """String representation"""
34 return f"Stack({self.items})"
35
36# Przykład użycia
37equipment_stack = Stack()
38equipment_stack.push("Namiot")
39equipment_stack.push("Śpiwór")
40equipment_stack.push("Latarka")
41equipment_stack.push("Mapa")
42
43print(equipment_stack) # Stack(['Namiot', 'Śpiwór', 'Latarka', 'Mapa'])
44print(f"Szczyt: {equipment_stack.peek()}") # Mapa (ostatni dodany)
45print(f"Wyciągam: {equipment_stack.pop()}") # Mapa
46print(f"Teraz szczyt: {equipment_stack.peek()}") # Latarka
47print(f"Rozmiar: {equipment_stack.size()}") # 3Safari przykład - Śledzenie ścieżki eksploracji:
1def track_exploration_path():
2 """Śledź ścieżkę ekspedycji używając stosu"""
3 path = Stack()
4
5 # Eksploruj dżunglę
6 path.push("Obóz Bazowy")
7 print(f"Wchodzę do: Obóz Bazowy")
8
9 path.push("Las Północny")
10 print(f"Wchodzę do: Las Północny")
11
12 path.push("Rzeka")
13 print(f"Wchodzę do: Rzeka")
14
15 # Wracamy tą samą drogą (cofamy się)
16 print("\nWracam tą samą ścieżką:")
17 while not path.is_empty():
18 location = path.pop()
19 print(f"Wychodzę z: {location}")
20
21# Wyjście:
22# Wchodzę do: Obóz Bazowy
23# Wchodzę do: Las Północny
24# Wchodzę do: Rzeka
25# Wracam tą samą ścieżką:
26# Wychodzę z: Rzeka
27# Wychodzę z: Las Północny
28# Wychodzę z: Obóz Bazowy1def is_balanced(expression):
2 """
3 Sprawdź czy nawiasy są zbalansowane
4 Przykład: "({[]})" → True, "({[}])" → False
5 """
6 stack = Stack()
7 pairs = {')': '(', ']': '[', '}': '{'}
8
9 for char in expression:
10 if char in '([{':
11 # Otwierający nawias - dodaj na stos
12 stack.push(char)
13 elif char in ')]}':
14 # Zamykający nawias - sprawdź czy pasuje
15 if stack.is_empty():
16 return False # Brak otwierającego
17 if stack.pop() != pairs[char]:
18 return False # Nie pasuje
19 # Pasuje - kontynuuj
20
21 # Stack powinien być pusty na końcu
22 return stack.is_empty()
23
24# Testy
25print(is_balanced("({[]})")) # True
26print(is_balanced("({[}])")) # False
27print(is_balanced("((()))")) # True
28print(is_balanced("(()")) # False
29
30# Safari przykład
31code = "species = {name: 'Python', data: [1, 2, 3]}"
32print(f"Kod: {code}")
33print(f"Zbalansowany: {is_balanced(code)}") # TrueQueue to struktura danych gdzie pierwszy dodany element jest pierwszy do usunięcia (FIFO - First In, First Out).
Analogia Safari: Kolejka zwierząt do wodopoju - pierwsze w kolejce jest pierwsze napojone.
| Operacja | Złożoność | Opis | |----------|-----------|------| | enqueue(x) | O(1) | Dodaj element na koniec | | dequeue() | O(1) | Usuń i zwróć element z przodu | | front() / peek() | O(1) | Zobacz element z przodu | | is_empty() | O(1) | Sprawdź czy kolejka jest pusta | | size() | O(1) | Zwróć liczbę elementów |
1from collections import deque
2
3class Queue:
4 """Implementacja kolejki używając deque"""
5
6 def __init__(self):
7 # deque = double-ended queue - O(1) operacje z obu stron!
8 self.items = deque()
9
10 def enqueue(self, item):
11 """Dodaj element na koniec - O(1)"""
12 self.items.append(item)
13
14 def dequeue(self):
15 """Usuń i zwróć element z przodu - O(1)"""
16 if self.is_empty():
17 raise IndexError("Queue jest pusta!")
18 return self.items.popleft() # popleft() z deque = O(1)!
19
20 def front(self):
21 """Zobacz element z przodu - O(1)"""
22 if self.is_empty():
23 raise IndexError("Queue jest pusta!")
24 return self.items[0]
25
26 def is_empty(self):
27 """Sprawdź czy kolejka jest pusta - O(1)"""
28 return len(self.items) == 0
29
30 def size(self):
31 """Zwróć liczbę elementów - O(1)"""
32 return len(self.items)
33
34 def __str__(self):
35 """String representation"""
36 return f"Queue({list(self.items)})"
37
38# Przykład użycia
39species_queue = Queue()
40species_queue.enqueue("Python")
41species_queue.enqueue("Leo")
42species_queue.enqueue("Elephas")
43
44print(species_queue) # Queue(['Python', 'Leo', 'Elephas'])
45print(f"Pierwszy: {species_queue.front()}") # Python
46print(f"Obsługuję: {species_queue.dequeue()}") # Python (pierwszy dodany)
47print(f"Teraz pierwszy: {species_queue.front()}") # LeoUWAGA: Nie używaj listy Pythona z
pop(0) dla kolejki - to O(n)! Używaj deque!1# ❌ ŹLE - pop(0) to O(n)
2queue = []
3queue.append(1) # O(1)
4queue.pop(0) # O(n) - musi przesunąć wszystkie elementy!
5
6# ✅ DOBRZE - deque z popleft()
7from collections import deque
8queue = deque()
9queue.append(1) # O(1)
10queue.popleft() # O(1) - zoptymalizowane!1def process_discoveries():
2 """Symulacja obsługi odkryć w kolejności zgłoszenia"""
3 discovery_queue = Queue()
4
5 # Zgłoszenia odkryć
6 print("=== ZGŁOSZENIA ODKRYĆ ===")
7 discoveries = ["Python regius", "Panthera leo", "Gorilla gorilla", "Elephas maximus"]
8 for species in discoveries:
9 discovery_queue.enqueue(species)
10 print(f"Zgłoszono: {species}")
11
12 print(f"\nW kolejce: {discovery_queue.size()} odkryć\n")
13
14 # Przetwarzanie w kolejności FIFO
15 print("=== PRZETWARZANIE ===")
16 while not discovery_queue.is_empty():
17 current = discovery_queue.dequeue()
18 print(f"Katalogowanie: {current}")
19 # Symulacja przetwarzania
20 import time
21 time.sleep(0.5)
22
23 print("\n✓ Wszystkie odkrycia skatalogowane!")
24
25# Wynik:
26# === ZGŁOSZENIA ODKRYĆ ===
27# Zgłoszono: Python regius
28# Zgłoszono: Panthera leo
29# Zgłoszono: Gorilla gorilla
30# Zgłoszono: Elephas maximus
31#
32# W kolejce: 4 odkryć
33#
34# === PRZETWARZANIE ===
35# Katalogowanie: Python regius (pierwszy zgłoszony)
36# Katalogowanie: Panthera leo
37# Katalogowanie: Gorilla gorilla
38# Katalogowanie: Elephas maximus
39#
40# ✓ Wszystkie odkrycia skatalogowane!Deque (czyt. "dek") to kolejka z obu końców - możesz dodawać i usuwać z przodu i z tyłu!
1from collections import deque
2
3# Stwórz deque
4dq = deque([1, 2, 3])
5
6# Operacje z prawej strony (jak lista)
7dq.append(4) # [1, 2, 3, 4]
8dq.pop() # 4, pozostaje [1, 2, 3]
9
10# Operacje z lewej strony (unikalne dla deque!)
11dq.appendleft(0) # [0, 1, 2, 3]
12dq.popleft() # 0, pozostaje [1, 2, 3]
13
14# Inne operacje
15dq.extend([4, 5]) # [1, 2, 3, 4, 5]
16dq.extendleft([0, -1]) # [-1, 0, 1, 2, 3, 4, 5]
17dq.rotate(2) # [4, 5, -1, 0, 1, 2, 3] (obrót w prawo)1class RecentDiscoveriesTracker:
2 """Śledź ostatnie N odkryć"""
3
4 def __init__(self, max_size=5):
5 self.discoveries = deque(maxlen=max_size) # Automatyczne usuwanie starych!
6
7 def add_discovery(self, species):
8 """Dodaj odkrycie (automatycznie usuwa najstarsze jeśli przekroczone max)"""
9 self.discoveries.append(species)
10
11 def get_recent(self):
12 """Zwróć ostatnie odkrycia (najnowsze najpierw)"""
13 return list(reversed(self.discoveries))
14
15 def __str__(self):
16 return f"Ostatnie {len(self.discoveries)} odkryć: {list(self.discoveries)}"
17
18# Użycie
19tracker = RecentDiscoveriesTracker(max_size=3)
20tracker.add_discovery("Python")
21tracker.add_discovery("Leo")
22tracker.add_discovery("Elephas")
23print(tracker) # ['Python', 'Leo', 'Elephas']
24
25tracker.add_discovery("Gorilla") # Przekroczy max - usuwa Python!
26print(tracker) # ['Leo', 'Elephas', 'Gorilla']
27
28print(f"Najnowsze najpierw: {tracker.get_recent()}")
29# ['Gorilla', 'Elephas', 'Leo']Priority Queue to kolejka gdzie elementy są obsługiwane według priorytetu, nie kolejności dodania.
1import heapq
2
3class PriorityQueue:
4 """Kolejka priorytetowa (mniejszy priorytet = wyższy priorytet)"""
5
6 def __init__(self):
7 self.heap = []
8 self.counter = 0 # Dla zachowania kolejności przy równych priorytetach
9
10 def enqueue(self, item, priority):
11 """Dodaj element z priorytetem - O(log n)"""
12 # Heapq używa min-heap (najmniejszy na górze)
13 # Dodajemy counter aby zachować kolejność FIFO dla równych priorytetów
14 heapq.heappush(self.heap, (priority, self.counter, item))
15 self.counter += 1
16
17 def dequeue(self):
18 """Usuń i zwróć element z najwyższym priorytetem - O(log n)"""
19 if self.is_empty():
20 raise IndexError("PriorityQueue jest pusta!")
21 priority, _, item = heapq.heappop(self.heap)
22 return item
23
24 def is_empty(self):
25 """Sprawdź czy pusta - O(1)"""
26 return len(self.heap) == 0
27
28 def size(self):
29 """Zwróć rozmiar - O(1)"""
30 return len(self.heap)
31
32# Safari przykład - Priorytetyzacja badania gatunków
33pq = PriorityQueue()
34
35# Dodaj gatunki z priorytetem (1 = najwyższy, 5 = najniższy)
36pq.enqueue("Crocodylus niloticus", priority=1) # Niebezpieczny - priorytet!
37pq.enqueue("Python regius", priority=3) # Normalny priorytet
38pq.enqueue("Panthera leo", priority=1) # Niebezpieczny - priorytet!
39pq.enqueue("Gorilla gorilla", priority=2) # Średni priorytet
40pq.enqueue("Elephas maximus", priority=3) # Normalny priorytet
41
42print("Kolejność badania (priorytet):")
43while not pq.is_empty():
44 species = pq.dequeue()
45 print(f" Badanie: {species}")
46
47# Wynik:
48# Badanie: Crocodylus niloticus (priorytet 1, pierwszy dodany)
49# Badanie: Panthera leo (priorytet 1, drugi dodany)
50# Badanie: Gorilla gorilla (priorytet 2)
51# Badanie: Python regius (priorytet 3, pierwszy dodany)
52# Badanie: Elephas maximus (priorytet 3, drugi dodany)| Struktura | Dodawanie | Usuwanie | Złożoność | Zastosowanie | |-----------|-----------|----------|-----------|--------------| | Stack | push (góra) | pop (góra) | O(1) | Undo, Call stack, DFS | | Queue | enqueue (tył) | dequeue (przód) | O(1) | BFS, Scheduling, Buffering | | Deque | append/appendleft | pop/popleft | O(1) | Sliding window, Recent history | | Priority Queue | enqueue | dequeue (min) | O(log n) | Dijkstra, Task scheduling |
1class ExpeditionPlanner:
2 """System planowania ekspedycji używający różnych struktur danych"""
3
4 def __init__(self):
5 self.path_history = Stack() # Historia ścieżki (do backtrackingu)
6 self.task_queue = Queue() # Kolejka zadań do wykonania
7 self.recent_discoveries = deque(maxlen=10) # 10 ostatnich odkryć
8 self.priority_tasks = PriorityQueue() # Zadania priorytetowe
9
10 def enter_location(self, location):
11 """Wejdź do lokacji (zapisz w historii)"""
12 self.path_history.push(location)
13 print(f"➡️ Wchodzę do: {location}")
14
15 def backtrack(self):
16 """Wróć do poprzedniej lokacji"""
17 if self.path_history.is_empty():
18 print("⚠️ Już w obozie bazowym!")
19 return None
20 location = self.path_history.pop()
21 print(f"⬅️ Wychodzę z: {location}")
22 return location
23
24 def add_task(self, task, priority=None):
25 """Dodaj zadanie (normalne lub priorytetowe)"""
26 if priority is not None:
27 self.priority_tasks.enqueue(task, priority)
28 print(f"📌 Priorytetowe zadanie: {task} (priorytet {priority})")
29 else:
30 self.task_queue.enqueue(task)
31 print(f"📋 Zadanie: {task}")
32
33 def process_next_task(self):
34 """Przetwórz następne zadanie (priorytet najpierw)"""
35 if not self.priority_tasks.is_empty():
36 task = self.priority_tasks.dequeue()
37 print(f"⚡ Wykonuję priorytetowe: {task}")
38 return task
39 elif not self.task_queue.is_empty():
40 task = self.task_queue.dequeue()
41 print(f"✓ Wykonuję: {task}")
42 return task
43 else:
44 print("✓ Wszystkie zadania wykonane!")
45 return None
46
47 def record_discovery(self, species):
48 """Zapisz odkrycie"""
49 self.recent_discoveries.append(species)
50 print(f"🔬 Odkryto: {species}")
51
52 def show_recent_discoveries(self, n=5):
53 """Pokaż ostatnie N odkryć"""
54 recent = list(self.recent_discoveries)[-n:]
55 print(f"\n📊 Ostatnie {len(recent)} odkryć:")
56 for i, species in enumerate(reversed(recent), 1):
57 print(f" {i}. {species}")
58
59# Użycie
60planner = ExpeditionPlanner()
61
62# Eksploracja
63planner.enter_location("Las Północny")
64planner.enter_location("Rzeka")
65planner.enter_location("Wodospad")
66
67# Odkrycia
68planner.record_discovery("Python regius")
69planner.record_discovery("Panthera leo")
70
71# Zadania
72planner.add_task("Zbadaj próbki wody")
73planner.add_task("PILNE: Napraw sprzęt komunikacyjny", priority=1)
74planner.add_task("Stwórz mapę terenu")
75
76# Przetwarzanie zadań
77planner.process_next_task() # PILNE najpierw!
78planner.process_next_task()
79planner.process_next_task()
80
81# Backtracking
82planner.backtrack()
83planner.backtrack()
84planner.backtrack()
85
86# Podsumowanie
87planner.show_recent_discoveries()Stwórz "Safari Command Center":
W tej lekcji nauczyłeś/aś się:
Przed przejściem dalej:
Kluczowe: Stack dla backtrackingu i undo, Queue dla BFS i scheduling, Deque dla sliding window!
W następnej i ostatniej lekcji tego modułu Darwin wprowadzi Cię w rekursję - funkcje wywołujące same siebie! 🔄🌀