[1] strucktura_data #156

Open
simonovams wants to merge 5 commits from simonovams/2026-rff_mp:SimonovaMS into develop
21 changed files with 1730 additions and 0 deletions

View File

View File

@ -0,0 +1,50 @@
['Structura', 'shuffled/sorted', 'Operation', 'Time']
LinkedList | shuffled | insert | 3.798362
LinkedList | shuffled | find | 0.028610
LinkedList | shuffled | delete | 0.035444
LinkedList | sorted | insert | 3.117239
LinkedList | sorted | find | 0.020465
LinkedList | sorted | delete | 0.028734
HashTable | shuffled | insert | 0.013259
HashTable | shuffled | find | 0.000109
HashTable | shuffled | delete | 0.000079
HashTable | sorted | insert | 0.014760
HashTable | sorted | find | 0.000107
HashTable | sorted | delete | 0.000076
Bst | shuffled | insert | 0.020712
Bst | shuffled | find | 0.000246
Bst | shuffled | delete | 0.000096
Bst | sorted | insert | 3.905296
Bst | sorted | find | 0.029092
Bst | sorted | delete | 0.018350
Результаты:
Структура Режим вставка поиск удаление
LinkedList shuffled 3.798362 0.028610 0.035444
LinkedList sorted 3.117239 0.020465 0.028734
HashTable shuffled 0.013259 0.000109 0.000079
HashTable sorted 0.014760 0.000107 0.000076
Bst shuffled 0.020712 0.000246 0.000096
Bst sorted 3.905296 0.029092 0.018350
График
График сохранён в файл: results_plot.png
Анализ:
ВСТАВКА:
Лучшая: HashTable (0.014010 сек)
Худшая: LinkedList (3.457801 сек)
ПОИСК:
Лучшая: HashTable (0.000108 сек)
Худшая: LinkedList (0.024537 сек)
УДАЛЕНИЕ:
Лучшая: HashTable (0.000077 сек)
Худшая: LinkedList (0.032089 сек)
Вывод:
Для вставок, поиска и удаления лучше всего использовать HashTable как для отсортированных, так и для неотсортированных данных
BST неплох для отсортированных данных, но всё равно хуже HashTable
LinkedList показал худшие результаты
HashTable - оптимальный выбор для телефонного справочника

121
SimonovaMS/analyz.py Normal file
View File

@ -0,0 +1,121 @@
import csv
import matplotlib.pyplot as plt
import numpy as np
from collections import defaultdict
import os
report_file = open("analys_report.txt", "w", encoding="utf-8")
data = defaultdict(lambda: defaultdict(dict))
with open("C:/Users/Honor/Documents/dep2k/lab_inf_1/data/results.csv", "r", encoding="utf-8") as f:
reader = csv.reader(f)
header = next(reader)
print(f"{header}")
report_file.write(f"{header}\n")
for row in reader:
if len(row) >= 4:
struct = row[0] # LinkedList, HashTable, Bst
mode = row[1] # shuffled или sorted
op = row[2] # insert, find, delete
time_val = float(row[3])
data[struct][mode][op] = time_val
print(f"{struct} | {mode} | {op} | {time_val:.6f}")
report_file.write(f"{struct} | {mode} | {op} | {time_val:.6f}\n")
op_names = {
'insert': 'вставка',
'find': 'поиск',
'delete': 'удаление'
}
structures = ["LinkedList", "HashTable", "Bst"]
modes = ["shuffled", "sorted"]
operations = ["insert", "find", "delete"]
print("Результаты:")
report_file.write("\nРезультаты:\n")
print(f"{'Структура':<15} {'Режим':<10} {'вставка':<15} {'поиск':<15} {'удаление':<15}")
report_file.write(f"{'Структура':<15} {'Режим':<10} {'вставка':<15} {'поиск':<15} {'удаление':<15}\n")
for struct in structures:
for mode in modes:
insert_time = data[struct][mode]['insert']
find_time = data[struct][mode]['find']
delete_time = data[struct][mode]['delete']
print(f"{struct:<15} {mode:<10} {insert_time:<15.6f} {find_time:<15.6f} {delete_time:<15.6f}")
report_file.write(f"{struct:<15} {mode:<10} {insert_time:<15.6f} {find_time:<15.6f} {delete_time:<15.6f}\n")
#графики
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
for idx, op in enumerate(operations):
ax = axes[idx]
x = np.arange(len(structures))
width = 0.35
shuffled_vals = [data[s]["shuffled"][op] for s in structures]
sorted_vals = [data[s]["sorted"][op] for s in structures]
bars1 = ax.bar(x - width/2, shuffled_vals, width, label='shuffled', color='orange', alpha=0.8)
bars2 = ax.bar(x + width/2, sorted_vals, width, label='sorted', color='cyan', alpha=0.8)
ax.set_xlabel('Структура')
ax.set_ylabel('Время (сек)')
ax.set_title(f'{op_names[op]}')
ax.set_xticks(x)
ax.set_xticklabels(structures, rotation=45)
ax.legend()
ax.set_yscale('log')
for bar in bars1:
height = bar.get_height()
ax.text(bar.get_x() + bar.get_width()/2, height,
f'{height:.3f}', ha='center', va='bottom', fontsize=8)
for bar in bars2:
height = bar.get_height()
ax.text(bar.get_x() + bar.get_width()/2, height,
f'{height:.3f}', ha='center', va='bottom', fontsize=8)
plt.tight_layout()
plot_filename = "results_plot.png"
plt.savefig('results_plot.png', dpi=150)
plt.show()
report_file.write("График\n")
report_file.write(f"График сохранён в файл: {plot_filename}\n")
print("Анализ:")
report_file.write("\nАнализ:\n")
for op in operations:
print(f"\n{op_names[op].upper()}:")
report_file.write(f"\n{op_names[op].upper()}:\n")
# Среднее по двум режимам
avg_times = []
for s in structures:
avg = (data[s]["shuffled"][op] + data[s]["sorted"][op]) / 2
avg_times.append((s, avg))
avg_times.sort(key=lambda x: x[1])
print(f" Лучшая: {avg_times[0][0]} ({avg_times[0][1]:.6f} сек)")
print(f" Худшая: {avg_times[-1][0]} ({avg_times[-1][1]:.6f} сек)")
report_file.write(f" Лучшая: {avg_times[0][0]} ({avg_times[0][1]:.6f} сек)\n")
report_file.write(f" Худшая: {avg_times[-1][0]} ({avg_times[-1][1]:.6f} сек)\n")
print("Вывод:")
report_file.write("\nВывод:\n")
print("Для вставок, поиска и удаления лучше всего использовать HashTable как для отсортированных, так и для неотсортированных данных")
print("BST неплох для отсортированных данных, но всё равно хуже HashTable")
print("LinkedList показал худшие результаты")
print("HashTable - оптимальный выбор для телефонного справочника")
report_file.write("Для вставок, поиска и удаления лучше всего использовать HashTable как для отсортированных, так и для неотсортированных данных\n")
report_file.write("BST неплох для отсортированных данных, но всё равно хуже HashTable\n")
report_file.write("LinkedList показал худшие результаты\n")
report_file.write("HashTable - оптимальный выбор для телефонного справочника\n")
report_file.close()

29
SimonovaMS/generator.py Normal file
View File

@ -0,0 +1,29 @@
import random
from typing import List, Tuple
def generate_data(n=10000):
records = []
for i in range(n):
name = f"User_{i:05d}"
phone = f"8{random.randint(900,999)}{random.randint(100,999)}{random.randint(0,9)}{random.randint(0,9)}{random.randint(0,9)}{random.randint(0,9)}"
records.append((name,phone))
records_shuffled = records.copy()
random.shuffle(records_shuffled)
records_sorted = sorted(records, key=lambda x:x[0])
return records_shuffled, records_sorted
def generate_search(records, exist_count=100, no_exist_count=10):
exist_names = [name for name, _ in records]
select_exist = random.sample(exist_names, min(exist_count, len(exist_names)))
no_exist_count=[f"None_{i:05d}" for i in range(no_exist_count)]
return select_exist + no_exist_count
def generate_delete(records, count=50):
names = [name for name, _ in records]
return random.sample(names, min(count, len(names)))

View File

@ -0,0 +1,200 @@
# experiments.py
import time
import csv
from typing import List, Dict
from maze_model import Maze
from maze_builder import TextFileMazeBuilder
from pathfinding_strategies import BFSStrategy, DFSStrategy, AStarStrategy
from maze_solver import MazeSolver, SearchStats
class ExperimentRunner:
def __init__(self):
self.builder = TextFileMazeBuilder()
self.strategies = [
BFSStrategy(),
DFSStrategy(),
AStarStrategy(),
]
self.results: List[Dict] = []
def create_test_maze_file(self, filename: str, maze_data: List[str]) -> None:
with open(filename, 'w', encoding='utf-8') as f:
f.write('\n'.join(maze_data))
def generate_simple_maze(self) -> List[str]:
maze = [
"S E",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" "
]
return maze
def generate_complex_maze(self, size: int = 50) -> List[str]:
import random
random.seed(42)
maze = []
for y in range(size):
row = []
for x in range(size):
if (x == 0 and y == 0):
row.append('S')
elif (x == size - 1 and y == size - 1):
row.append('E')
elif random.random() < 0.3: # 30% стен
row.append('#')
else:
row.append(' ')
maze.append(''.join(row))
for i in range(size):
if maze[i][0] == '#':
row = list(maze[i])
row[0] = ' '
maze[i] = ''.join(row)
if maze[0][i] == '#':
row = list(maze[0])
row[i] = ' '
maze[0] = ''.join(row)
return maze
def generate_empty_maze(self, size: int = 50) -> List[str]:
maze = []
for y in range(size):
row = []
for x in range(size):
if x == 0 and y == 0:
row.append('S')
elif x == size - 1 and y == size - 1:
row.append('E')
else:
row.append(' ')
maze.append(''.join(row))
return maze
def generate_no_exit_maze(self, size: int = 20) -> List[str]:
maze = []
for y in range(size):
row = []
for x in range(size):
if x == 0 and y == 0:
row.append('S')
elif x == size - 1 and y == size - 1:
row.append('#') # Выход заблокирован
else:
row.append('#') # Всё стены
maze.append(''.join(row))
# выход в тупике
row = list(maze[size - 1])
row[size - 1] = 'E'
maze[size - 1] = ''.join(row)
return maze
def run_experiment(self, maze_name: str, maze_data: List[str],
num_runs: int = 5) -> List[Dict]:
filename = f"test_{maze_name}.txt"
self.create_test_maze_file(filename, maze_data)
maze = self.builder.build_from_file(filename)
results = []
for strategy in self.strategies:
solver = MazeSolver(maze, strategy)
times = []
path_lengths = []
for run in range(num_runs):
stats = solver.solve()
times.append(stats.time_ms)
path_lengths.append(stats.path_length)
avg_time = sum(times) / len(times)
avg_path_length = sum(path_lengths) / len(path_lengths)
result = {
'maze': maze_name,
'strategy': strategy.name,
'avg_time_ms': round(avg_time, 3),
'min_time_ms': round(min(times), 3),
'max_time_ms': round(max(times), 3),
'path_length': int(avg_path_length) if avg_path_length else 0,
'path_found': avg_path_length > 0
}
results.append(result)
print(f"{maze_name} - {strategy.name}: "
f"{avg_time:.3f} мс, путь: {int(avg_path_length)}")
return results
def run_all_experiments(self):
experiments = [
("simple_10x10", self.generate_simple_maze()),
("complex_50x50", self.generate_complex_maze(50)),
("large_100x100", self.generate_complex_maze(100)),
("empty_50x50", self.generate_empty_maze(50)),
("no_exit_20x20", self.generate_no_exit_maze(20))
]
all_results = []
for name, data in experiments:
print(f"\n Лабиринт: {name} ---")
results = self.run_experiment(name, data)
all_results.extend(results)
self.save_to_csv(all_results, "experiment_results.csv")
return all_results
def save_to_csv(self, results: List[Dict], filename: str):
if not results:
return
with open(filename, 'w', newline='', encoding='utf-8') as csvfile:
fieldnames = results[0].keys()
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(results)
def print_analysis(results: List[Dict]):
# Группировка
mazes = set(r['maze'] for r in results)
for maze in sorted(mazes):
print(f"\nЛабиринт: {maze}")
print("-" * 40)
maze_results = [r for r in results if r['maze'] == maze]
#по времени
sorted_results = sorted(maze_results, key=lambda x: x['avg_time_ms'])
for r in sorted_results:
status = "" if r['path_found'] else ""
print(f" {status} {r['strategy']:8} | "
f"Время: {r['avg_time_ms']:8.3f} мс | "
f"Путь: {r['path_length']:4} шагов")
# Определяем лучший
fastest = sorted_results[0]
print(f"\n → Самый быстрый: {fastest['strategy']} "
f"({fastest['avg_time_ms']:.3f} мс)")

146
SimonovaMS/lab2/main.py Normal file
View File

@ -0,0 +1,146 @@
import sys
from maze_builder import TextFileMazeBuilder
from pathfinding_strategies import BFSStrategy, DFSStrategy, AStarStrategy
from maze_solver import MazeSolver
from visualization import ConsoleView, GameController, EventType
from experiments import ExperimentRunner, print_analysis
from analysis import plot_results
def create_sample_maze():
sample_maze = [
"S ##### ",
"# # ### ",
"# # # # ",
"# # ### # ",
"# # # ",
"### # ### ",
"# # # ",
"# ####### ",
"# E ",
"##########"
]
filename = "sample_maze.txt"
with open(filename, 'w', encoding='utf-8') as f:
f.write('\n'.join(sample_maze))
return filename
def interactive_mode():
builder = TextFileMazeBuilder()
filename = create_sample_maze()
try:
maze = builder.build_from_file(filename)
print(f"Лабиринт загружен: {maze.width}x{maze.height}")
except Exception as e:
print(f"Ошибка загрузки: {e}")
return
view = ConsoleView()
controller = GameController(maze, view)
strategies = {
'1': BFSStrategy(),
'2': DFSStrategy(),
'3': AStarStrategy(),
}
print("\nДоступные алгоритмы поиска пути:")
print(" 1. BFS (поиск в ширину) - кратчайший путь")
print(" 2. DFS (поиск в глубину) - быстрый, не оптимальный")
print(" 3. A* - оптимальный с эвристикой")
# Выбор стратегии
while True:
choice = input("\nВыберите алгоритм (1-3): ").strip()
if choice in strategies:
strategy = strategies[choice]
break
print("Неверный выбор. Попробуйте снова.")
# Поиск пути
print(f"\nИспользуем: {strategy.name}")
print("Поиск пути...")
solver = MazeSolver(maze, strategy)
stats = solver.solve()
if stats.path_found:
print(f" Путь найден! Победа! Длина: {stats.path_length} шагов")
print(f" Время: {stats.time_ms:.3f} мс")
path = strategy.find_path(maze, maze.start, maze.exit)
controller.set_path(path)
# Интерактивное управление
print("\nДемонстрация паттерна Command:")
print(" Используйте W/A/S/D для перемещения")
print(" Нажмите U для отмены последнего хода")
print(" Нажмите Q для выхода")
print("\nТочка '.' показывает найденный путь")
print("Буква 'P' показывает текущую позицию игрока")
controller._render()
while True:
key = input("\n> ").lower()
if key == 'q':
break
elif key == 'w':
from visualization import Direction
controller.move(Direction.UP)
elif key == 's':
from visualization import Direction
controller.move(Direction.DOWN)
elif key == 'a':
from visualization import Direction
controller.move(Direction.LEFT)
elif key == 'd':
from visualization import Direction
controller.move(Direction.RIGHT)
elif key == 'u':
controller.undo()
print("Ход отменён!")
else:
print("Команды: W(вверх), S(вниз), A(влево), D(вправо), U(отмена), Q(выход)")
else:
print("Путь не найден, грустно")
def experimental_mode():
print("эксперименты")
print("Запуск экспериментов на лабиринтах разной сложности...")
runner = ExperimentRunner()
results = runner.run_all_experiments()
print_analysis(results)
#графики
plot_results(results)
def main():
print("\nВыберите режим работы:")
print(" 1. Интерактивный режим (с визуализацией)")
print(" 2. Экспериментальный режим (замеры производительности)")
print(" 3. Выход")
choice = input("\nВаш выбор (1-3): ").strip()
if choice == '1':
interactive_mode()
elif choice == '2':
experimental_mode()
else:
print("Adios!")
sys.exit(0)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,65 @@
from abc import ABC, abstractmethod
from typing import Tuple
import os
from maze_model import Maze, Cell
class MazeBuilder(ABC):
@abstractmethod
def build_from_file(self, filename: str) -> Maze:
pass
class TextFileMazeBuilder(MazeBuilder):
def build_from_file(self, filename: str) -> Maze:
if not os.path.exists(filename):
raise FileNotFoundError(f"Файл {filename} не найден..")
with open(filename, 'r', encoding='utf-8') as file:
lines = [line.rstrip('\n') for line in file.readlines()]
if not lines:
raise ValueError("Пусто(")
height = len(lines)
width = len(lines[0]) if lines else 0
for i, line in enumerate(lines):
if len(line) != width:
raise ValueError(f"Лабиринт не прямоугольный, что-то не так с размерами!")
maze = Maze(width, height)
start_found = False
exit_found = False
for y, line in enumerate(lines):
for x, char in enumerate(line):
cell = Cell(x, y)
if char == '#':
cell.is_wall = True
elif char == 'S':
cell.is_start = True
cell.is_wall = False
maze.start = cell
start_found = True
elif char == 'E':
cell.is_exit = True
cell.is_wall = False
maze.exit = cell
exit_found = True
elif char == ' ':
cell.is_wall = False
else:
raise ValueError(f"Недопустимый символ-'{char}' в позиции ({x}, {y}), уберите его")
maze.set_cell(x, y, cell)
if not start_found:
raise ValueError("В лабиринте нет начала")
if not exit_found:
raise ValueError("В лабиринте нет конца")
return maze

View File

@ -0,0 +1,67 @@
# maze_model.py
from __future__ import annotations
from typing import List, Optional
from dataclasses import dataclass
@dataclass
class Cell:
x: int
y: int
is_wall: bool = False
is_start: bool = False
is_exit: bool = False
def is_passable(self) -> bool:
return not self.is_wall
def __hash__(self) -> int:
return hash((self.x, self.y))
def __eq__(self, other) -> bool:
if not isinstance(other, Cell):
return False
return self.x == other.x and self.y == other.y
class Maze:
def __init__(self, width: int, height: int):
self.width = width
self.height = height
self._cells: List[List[Cell]] = []
self.start: Optional[Cell] = None
self.exit: Optional[Cell] = None
for y in range(height):
row = []
for x in range(width):
row.append(Cell(x, y))
self._cells.append(row)
def set_cell(self, x: int, y: int, cell: Cell) -> None:
if 0 <= x < self.width and 0 <= y < self.height:
self._cells[y][x] = cell
def get_cell(self, x: int, y: int) -> Optional[Cell]:
if 0 <= x < self.width and 0 <= y < self.height:
return self._cells[y][x]
return None
def get_neighbors(self, cell: Cell) -> List[Cell]:
neighbors = []
# вверх, вниз, влево, вправо
directions = [(0, -1), (0, 1), (-1, 0), (1, 0)]
for dx, dy in directions:
neighbor = self.get_cell(cell.x + dx, cell.y + dy)
if neighbor and neighbor.is_passable():
neighbors.append(neighbor)
return neighbors
def get_all_cells(self) -> List[Cell]:
cells = []
for row in self._cells:
cells.extend(row)
return cells

View File

@ -0,0 +1,52 @@
import time
from dataclasses import dataclass
from typing import List, Optional
from maze_model import Maze, Cell
from pathfinding_strategies import PathFindingStrategy
@dataclass
class SearchStats:
time_ms: float
visited_cells: int
path_length: int
path_found: bool
strategy_name: str
class MazeSolver:
def __init__(self, maze: Maze, strategy: Optional[PathFindingStrategy] = None):
self.maze = maze
self._strategy = strategy
def set_strategy(self, strategy: PathFindingStrategy) -> None:
self._strategy = strategy
def solve(self) -> SearchStats:
if self._strategy is None:
raise ValueError("Стратегии нет!")
if self.maze.start is None or self.maze.exit is None:
raise ValueError("Лабиринт не содержит начала или конца")
start_time = time.perf_counter()
if hasattr(self._strategy, '_find_path_with_stats'):
path, visited = self._strategy._find_path_with_stats(
self.maze, self.maze.start, self.maze.exit
)
else:
path = self._strategy.find_path(
self.maze, self.maze.start, self.maze.exit
)
visited = 0
end_time = time.perf_counter()
return SearchStats(
time_ms=(end_time - start_time) * 1000,
visited_cells=visited,
path_length=len(path) if path else 0,
path_found=len(path) > 0,
strategy_name=self._strategy.name
)

Binary file not shown.

View File

@ -0,0 +1,142 @@
from abc import ABC, abstractmethod
from typing import List, Dict, Optional, Tuple
from collections import deque
import heapq
from maze_model import Maze, Cell
class PathFindingStrategy(ABC):#интерфейс стратегии поиска
@abstractmethod
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:
pass
@property
@abstractmethod
def name(self) -> str:
pass
class BFSStrategy(PathFindingStrategy):#в ширину
@property
def name(self) -> str:
return "BFS"
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:
path, _ = self._find_path_with_stats(maze, start, exit_cell)
return path
def _find_path_with_stats(self, maze: Maze, start: Cell, exit_cell: Cell) -> tuple:
if start == exit_cell:
return [start], 1
from collections import deque
queue = deque([start])
visited = {start}
parent = {start: None}
while queue:
current = queue.popleft()
if current == exit_cell:
return self._reconstruct_path(parent, exit_cell), len(visited)
for neighbor in maze.get_neighbors(current):
if neighbor not in visited:
visited.add(neighbor)
parent[neighbor] = current
queue.append(neighbor)
return [], len(visited)
def _reconstruct_path(self, parent: dict, exit_cell: Cell) -> List[Cell]:
path = []
current = exit_cell
while current is not None:
path.append(current)
current = parent[current]
return list(reversed(path))
class DFSStrategy(PathFindingStrategy):#в глубину
@property
def name(self) -> str:
return "DFS"
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:
path, _ = self._find_path_with_stats(maze, start, exit_cell)
return path
def _find_path_with_stats(self, maze: Maze, start: Cell, exit_cell: Cell) -> tuple:
if start == exit_cell:
return [start], 1
stack = [(start, [start])]
visited = {start}
while stack:
current, path = stack.pop()
if current == exit_cell:
return path, len(visited)
for neighbor in maze.get_neighbors(current):
if neighbor not in visited:
visited.add(neighbor)
stack.append((neighbor, path + [neighbor]))
return [], len(visited)
class AStarStrategy(PathFindingStrategy): #A*
@property
def name(self) -> str:
return "A*"
def _heuristic(self, cell: Cell, target: Cell) -> int:
return abs(cell.x - target.x) + abs(cell.y - target.y)
def find_path(self, maze: Maze, start: Cell, exit_cell: Cell) -> List[Cell]:
path, _ = self._find_path_with_stats(maze, start, exit_cell)
return path
def _find_path_with_stats(self, maze: Maze, start: Cell, exit_cell: Cell) -> tuple:
import heapq
if start == exit_cell:
return [start], 1
counter = 0
open_set = [(0, counter, start)]
came_from = {}
visited = {start}
g_score = {start: 0}
f_score = {start: self._heuristic(start, exit_cell)}
while open_set:
current = heapq.heappop(open_set)[2]
if current == exit_cell:
return self._reconstruct_path(came_from, exit_cell), len(visited)
for neighbor in maze.get_neighbors(current):
visited.add(neighbor)
tentative_g = g_score[current] + 1
if neighbor not in g_score or tentative_g < g_score[neighbor]:
came_from[neighbor] = current
g_score[neighbor] = tentative_g
f_score[neighbor] = tentative_g + self._heuristic(neighbor, exit_cell)
counter += 1
heapq.heappush(open_set, (f_score[neighbor], counter, neighbor))
return [], len(visited)
def _reconstruct_path(self, came_from: dict, current: Cell) -> List[Cell]:
path = [current]
while current in came_from:
current = came_from[current]
path.append(current)
return list(reversed(path))

View File

@ -0,0 +1,10 @@
S #####
# # ###
# # # #
# # ### #
# # #
### # ###
# # #
# #######
# E
##########

View File

@ -0,0 +1,50 @@
S
## # # ## ## ## # # ### #
# # # # # # # # # # # # # # # #
## ### # ## ## ## # ## ## #
# # # # ## # # ## ## # # #
# ### # # # ### # # # # ## # ##
## ### # # # # # ### #
# # ## # # # ## ##
# ## #### # # # # # # ##
## #### ## # # # ## # #
# # # # # ### #### # # # ##
# # # # # # # # ## ##
# ## ##### ## ###### # #
## # ## # # ## #### ##
## ## ## ## ## # # #
# # # ## # # # # #
## # # # # # #
## # # # # ## # # ### # # # #
# # # # ## ## # # #
# ### ## # # # # # #
# ## # ## # ## # # #### ## # ## #
# ## ## # # # # # # ##
# # ## # ## # # # # #
# # # # # # # ### # # # ## ##
# # # ### # ## ## # #
### ## # # ## # #
## ### # # # # # # #
## # # # # # ## # # ## # ### #
# # # ## # # # ## # # #
### # # # # # # # #
# ## ## ## # # # #
### # # # # #### # #
# ## # ### # # #### # #
# # # # # # # # ##
# # # # # # # ## # ##
# ## # ### ## ## # # # #
# # # # # # # # # # ##
## # # ## ### # ## # # ###
# # # # # ## # # # # # #
# #### # # # #### # ## # #
# # # # ### # ## #
# # # # # # ### # # # #
## # # # # # # #### # #
### # ## ## # ### # #
## # ## ## ### # # # # # # #
### ## # # # # # #
# # # # ## ## # #
# # # ### # # # # # ## # #
# ### # # # # # ## ## ## # ##
# # # # ##### # ## # # #E

View File

@ -0,0 +1,50 @@
S
E

View File

@ -0,0 +1,100 @@
S
# # # # # # # # # # # # # # # # ## ### # ## ## ## # ## ## #
# # # # ## # # ## ## # # # # # ### # # # ### # # # # ## # ##
## ### # # # # # ### # # # ## # # # ## ##
# ## #### # # # # # # ## ## #### ## # # # ## # #
# # # # # ### #### # # # ## # # # # # # # # # ## ##
# ## ##### ## ###### # # ## # ## # # ## #### ##
## ## ## ## ## # # # # # # ## # # # # #
## # # # # # # ## # # # # ## # # ### # # # #
# # # # ## ## # # # # ### ## # # # # # #
# ## # ## # ## # # #### ## # ## # # # ## ## # # # # # # ##
# # ## # ## # # # # ### # # # # # # ### # # # ## ##
# # # ### # ## ## # # ### ## # # ## # #
## ### # # # # # # # # ## # # # # # ## # # ## # ### #
# # # ## # # # ## # # # #### # # # # # # # #
# ## ## ## # # # # ### # # # # #### # #
# ## # ### # # #### # # # # # # # # # # ##
# # # # # # # ## # ### # ## # ### ## ## # # # #
# # # # # # # # # # ### ## # # ## ### # ## # # ###
# # # # # ## # # # # # # # #### # # # #### # ## # #
# # # # ### # ## # # # # # # # ### # # # #
## # # # # # # #### # # # ### # ## ## # ### # #
## # ## ## ### # # # # # # # ### ## # # # # # #
# # # # ## ## # # # # # ### # # # # # ## # #
# ### # # # # # ## ## ## # ## # # # # ##### # ## # # #
# # # # # # ## ## # # # # # # # # # # ## # ## # # # # # # ##
### ## # # ##### # # # # ## # # ## # # ## #
# # # # # ## # # # ## # ## # # # # # # ### # ## ### ##
### # ## # # # ## # # ## # # # # #### # ## #### # # # # # # #
# # # ### # ## # # ## # # # # # # # # # # ###### #
## # ## # # # #### #### # # ##### # # # ### # # # # #
# # # # ## ### # # # # # # # ## # # ## # # ## # # # #
# # # ## # # ### # ## # # # # #### # # ## # ##
## # ## # # ## # # # # # ## # # # # # # # # # # # # ###### #
## # # ## ### # #### # # # # # # # # # # # # # ## # # # # #
## # # # ## # ## # # # ### # # # # # # # # # #
# # # # ## # ### # # # # # ## ## ## # # ## # ###
### # # # # # # ## # # ## ## # # # # # #
## ## ## ### # # ### # # # # ### # # # # #
# # ## # # # ### ## ## ## ## # # ### # ## # # # # ## ## #
# # # # ## # # # ## # # # # ## # ### #### # ## ##
### ### # # # ### ### # # ## # # # ### ## # ## #
# ## # # # ### #### # # # # ### # # # ## ### ## # #
#### # ### ## # # # # # # # # ### # # # # ## # ### ###
# # # # # # # # # # ## ### ## ### # ## # # # ## # #### #
## # # # # # # # # # # # ### # # # # # ## # # #
# # ## # # # # ## # # # # ## ## ## # # ## # ## # # ## #
## # # ## # # # # ### # # # # # # # ## # # # ## # ### ## # #
# # ## # ## ### ## # # # # ## # # # # # #
# ## # # ### # # # # # ## # # # # # ## # ## # # #
# # ## # ### # ## # # ## # # # # # # # #
# # # ## #### # # ### # ## # # ## # # ##
# # # ## # ### # ## ## # # # # ### # # # #
# # # # # # ## # ## ## ### ### # # ## # # # ## # #
# ## # # ### ##### # # # # ## # # # # # ## # # #
# # # ## # # ## # ## ## # ## # ### # # # # ## ##
# ### # ## ### # # ## # # # # # # # # # # # ## ## # #
# # # # # # # # ## # # # # # # # # # # # ## # # # ## # #
# # # ## # # ## # # ## # # # ### ### # # # # # # #
## # ## # # # # # # # ## # # ## # ### ### # # ## ##
# ## # # #### # # # # ##### # ## #### # # # # # # ####
## # ### ### # ## # ## # # ## # # # # # # ## #### # ## # #
# # # ## # # # # # # # ## # # # # # #
## # ## ## # ### #### # # # # ## # ## # ## #
# # # ## ## # ## # ## # # # # # # ##
# # # # # # ### ## ### # ## # # #### # # # ##### #
## ## # # # ## # ## ## # # # # # # # # # # ##
##### # ### # ## # # # ## # ### #### # # ### # ## #
### ## ## # ## # ### # ## ### # ## ## ## ## # # # #
# # ### # ## # # ## # # # # ## ## # ## # ## #
# ## # ## # ## # ## # # # # # # # # #
# ## # # # ####### # ## ## ## # # # # # # # # # ## #
# # # # ## # # ### # # # ## #### # # # # # #
### # ### # ### # ### ## # # # # # ## # # # # # # # #
# # ##### # ## ##### #### ## # # # ## # ## # # ## #
# ### ## ## # ##### # ## # # # # # #
# # # ## ## # ## ## ## # ## # ## #### # # ## # # # # # ##
# # ## # # # #### # # ## # ## ## # # ## # ## ## # # ## # #
# # # #### # ## # # # ## ### ## #### # # # # #
## ### # # # ## # # # # # # # ## # ## ###
# ## # ## # # # # # # # # # # # ### # # # ## #
# ## ## # #### # ## # # # # # # #
# # ## ### # # # ## ## # ## # # # ## # # # # # ####
# # ## ### # # ## ## # # # # ### # # ## # # # ##
## # # # # ## ## # ## # # #### # # # #
# ## # # # # # # ### ## # #### # # ## # # # # ### ## # ##
### # ## ## # # # # # # ## # # # ## # #### # ##### #
# # # # # # # ## ## ### # ### ### # # #### # # # # ## # ##
# # # #### # # # # ## # # ## # # ## # # ## # ##
# # # ## ## # ## # # # ## ## # ### ## # ## # # # # # # #
## # # # ## # ## ## ## # # ## # # # # # ## # # # #
### # # # ## # # # # # # # # # # # # ## # # # ##
# # # ## # # # # ## # # ## # # # # # # ## # # # #
# # # ## # ## # ### # # ### # ## # # # ## # ### #
## # # # ## # # ## # # # ## # # #### ## # # # ### #
# #### ## ### ### # # ### # # ## # # # ### # ####### # ##
# # ## ## ### ## ### # # # # # # # # # # #
# ### # ## # ### # ## ## ## # # # # # # # ## ## # ###
# ## ### ## # # # # # # # # # # # # ###
# # # # # ## ### # # ## ## ## ### # # # # # # ## # # E

View File

@ -0,0 +1,20 @@
S###################
####################
####################
####################
####################
####################
####################
####################
####################
####################
####################
####################
####################
####################
####################
####################
####################
####################
####################
###################E

View File

@ -0,0 +1,10 @@
S E

View File

@ -0,0 +1,160 @@
from abc import ABC, abstractmethod
from typing import List, Optional, Set
from enum import Enum
from maze_model import Maze, Cell
class EventType(Enum):
PATH_FOUND = "path_found"
MOVE = "move"
MAZE_LOADED = "maze_loaded"
SOLVE_START = "solve_start"
SOLVE_END = "solve_end"
class Observer(ABC):
@abstractmethod
def update(self, event_type: EventType, data: any) -> None:
pass
class ConsoleView(Observer):
def __init__(self):
self.last_path: Optional[List[Cell]] = None
def update(self, event_type: EventType, data: any) -> None:
if event_type == EventType.MAZE_LOADED:
print("Лабиринт загружен")
elif event_type == EventType.SOLVE_START:
print("Начинается поиск пути...")
elif event_type == EventType.SOLVE_END:
print(f"Поиск завершён. Статистика: {data}")
elif event_type == EventType.PATH_FOUND:
self.last_path = data
def render(self, maze: Maze, player_pos: Optional[Cell] = None,
path: Optional[List[Cell]] = None) -> None: #рисует лаб
import os
os.system('cls' if os.name == 'nt' else 'clear')
path_set = set(path) if path else set()
# Верх
print("" + "" * maze.width + "")
for y in range(maze.height):
line = ""
for x in range(maze.width):
cell = maze.get_cell(x, y)
if player_pos and player_pos.x == x and player_pos.y == y:
line += "P"
elif cell == maze.start:
line += "S"
elif cell == maze.exit:
line += "E"
elif cell is not None and cell.is_wall:
line += "#"
elif path and cell in path_set:
line += "."
else:
line += " "
line += ""
print(line)
# Низ
print("" + "" * maze.width + "")
if path:
print(f"\nПуть найден! Длина: {len(path)} шагов")
elif path == []:
print("\nПуть не найден:(")
class Player:
def __init__(self, start_cell: Cell):
self.current_cell = start_cell
def move_to(self, cell: Cell) -> None:
self.current_cell = cell
def get_position(self) -> Cell:
return self.current_cell
class Direction(Enum):
UP = (0, -1)
DOWN = (0, 1)
LEFT = (-1, 0)
RIGHT = (1, 0)
class Command(ABC):
@abstractmethod
def execute(self) -> None:
pass
@abstractmethod
def undo(self) -> None:
pass
class MoveCommand(Command):
def __init__(self, player: Player, maze: Maze, direction: Direction):
self.player = player
self.maze = maze
self.direction = direction
self.previous_cell = player.current_cell
def execute(self) -> None:
dx, dy = self.direction.value
new_x = self.player.current_cell.x + dx
new_y = self.player.current_cell.y + dy
new_cell = self.maze.get_cell(new_x, new_y)
if new_cell and new_cell.is_passable():
self.previous_cell = self.player.current_cell
self.player.move_to(new_cell)
return True
return False
def undo(self) -> None:
self.player.move_to(self.previous_cell)
class GameController:
def __init__(self, maze: Maze, view: ConsoleView):
if maze.start is None:
raise ValueError("Лабиринт не имеет стартовой клетки")
self.maze = maze
self.view = view
self.player = Player(maze.start)
self.command_history: List[Command] = []
self.found_path: Optional[List[Cell]] = None
def move(self, direction: Direction) -> bool:
command = MoveCommand(self.player, self.maze, direction)
if command.execute():
self.command_history.append(command)
self._render()
return True
return False
def undo(self) -> None:
if self.command_history:
command = self.command_history.pop()
command.undo()
self._render()
def set_path(self, path: List[Cell]) -> None:
self.found_path = path
self._render()
def _render(self) -> None:
self.view.render(self.maze, self.player.get_position(), self.found_path)

247
SimonovaMS/phonebook.py Normal file
View File

@ -0,0 +1,247 @@
import time
import csv
import random
from functools import lru_cache
from operator import index
#LinkedListPhoneBook
def create_node(name, phone):
return {'name': name, 'phone': phone, 'next': None}
def ll_insert(head, name, phone):
new_node = create_node(name,phone)
if head is None:
return new_node
current = head
while current['next'] is not None:
if current['next']['name'] == name:
new_node['next'] = current['next']['next']
current['next']=new_node
return head
current=current['next']
current['next'] = new_node
return head
def ll_find(head, name):
current = head
while current is not None:
if current['name'] ==name:
return current['phone']
current=current['next']
return None
def ll_delete(head, name):
if head is None:
return None
if head['name'] == name:
return head['next']
current =head
while current['next'] is not None:
if current['next']['name'] == name:
current['next'] = current['next']['next']
return head
current=current['next']
return head
def ll_list_all(head):
records = []
current = head
while current is not None:
records.append((current['name'], current['phone']))
current = current['next']
records.sort(key=lambda x: x[0])
return records
#хеш=тфблица
def create_buckets(size=1000):
return [None] * size
def hash_function(name, buckest_size):
hash_value = 0
for char in name:
hash_value = (hash_value * 31 + ord(char)) % buckest_size
return hash_value
def ht_insert(buckets, name, phone):
index = hash_function(name, len(buckets))
buckets[index] = ll_insert(buckets[index], name, phone)
def ht_find(buckets, name):
index = hash_function(name, len(buckets))
return ll_find(buckets[index], name)
def ht_delete(buckets, name):
index = hash_function(name, len(buckets))
buckets[index] = ll_delete(buckets[index], name)
def ht_list_all(buckets):
records = []
for bucket in buckets:
current = bucket
while current is not None:
records.append((current['name'], current['phone']))
current = current['next']
records.sort(key=lambda x:x[0])
return records
#bts
def create_bst_node(name, phone):
return {'name': name, 'phone': phone, 'left': None, 'right': None}
def bst_insert(root, name, phone):
new_node = create_bst_node(name, phone)
if root is None:
return new_node
current = root
while True:
if name == current['name']:
current['phone'] = phone
return root
elif name < current['name']:
if current['left'] is None:
current['left'] = new_node
return root
current = current['left']
else:
if current['right'] is None:
current['right'] = new_node
return root
current = current['right']
def bst_find(root, name):
current = root
while current is not None:
if name == current['name']:
return current['phone']
elif name < current['name']:
current=current['left']
else:
current=current['right']
return None
def bst_find_min(node):
current = node
while current['left'] is not None:
current = current['left']
return current
def bst_delete(root, name):
if root is None:
return None
if root['name'] == name:
if root['left'] is None and root['right'] is None:
return None
if root['left'] is None:
return root['right']
if root['right'] is None:
return root['left']
parent = root
min_node = root['right']
while min_node['left']:
parent = min_node
min_node = min_node['left']
root['name'] = min_node['name']
root['phone'] = min_node['phone']
if parent == root:
parent['right'] = min_node['right']
else:
parent['left'] = min_node['right']
return root
parent = None
current = root
while current and current['name'] != name:
parent = current
if name < current['name']:
current = current['left']
else:
current = current['right']
if current is None:
return root
if current['left'] is None and current['right'] is None:
if parent['left'] == current:
parent['left'] = None
else:
parent['right'] = None
elif current['left'] is None:
if parent['left'] == current:
parent['left'] = current['right']
else:
parent['right'] = current['right']
elif current['right'] is None:
if parent['left'] == current:
parent['left'] = current['left']
else:
parent['right'] = current['left']
else:
min_parent = current
min_node = current['right']
while min_node['left']:
min_parent = min_node
min_node = min_node['left']
current['name'] = min_node['name']
current['phone'] = min_node['phone']
if min_parent == current:
min_parent['right'] = min_node['right']
else:
min_parent['left'] = min_node['right']
return root
def bst_list_all(root):
records = []
stack = []
current = root
while stack or current:
while current:
stack.append(current)
current = current['left']
current = stack.pop()
records.append((current['name'], current['phone']))
current = current['right']
return records
def bst_list_all(root):
records =[]
stack = []
current = root
while stack or current is not None:
while current is not None:
stack.append(current)
current=current['left']
current=stack.pop()
records.append((current['name'], current['phone']))
current=current['right']
return records

BIN
SimonovaMS/result_plot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

211
SimonovaMS/test.py Normal file
View File

@ -0,0 +1,211 @@
import time
import csv
import random
from phonebook import (ll_insert, ll_find, ll_delete, create_buckets, ht_insert, ht_find, ht_delete, bst_insert, bst_find, bst_delete)
from generator import generate_data
def run_exp():
records_shuffled, records_sorted = generate_data(10000)
all_names = [name for name, _ in records_shuffled]
search_names = random.sample(all_names, 100) + [f"None_{i}" for i in range(10)]
delete_names = random.sample(all_names, 50)
results = [["Structura", "shuffled/sorted", "Operation", "Time"]]
times =[]
print('LinkedList - shuffled')
for r in range(5):
head = None
start = time.perf_counter()
for name, phone in records_shuffled:
head = ll_insert(head, name, phone)
times.append(time.perf_counter() - start)
avg = sum(times)/5
results.append(["LinkedList", "shuffled", "insert", avg])
print(f"вставка - {avg:.6f}")
times=[]
for r in range(5):
start = time.perf_counter()
for name in search_names:
ll_find(head, name)
times.append(time.perf_counter() - start)
avg = sum(times) / 5
results.append(["LinkedList", "shuffled", "find", avg])
print(f"поиск - {avg:.6f}")
times=[]
for r in range(5):
start = time.perf_counter()
for name in delete_names:
head = ll_delete(head, name)
times.append(time.perf_counter() - start)
avg = sum(times) / 5
results.append(["LinkedList", "shuffled", "delete", avg])
print(f"удаление - {avg:.6f}")
print('LinkedList - sorted')
for r in range(5):
head = None
start = time.perf_counter()
for name, phone in records_sorted:
head = ll_insert(head, name, phone)
times.append(time.perf_counter() - start)
avg = sum(times) / 5
results.append(["LinkedList", "sorted", "insert", avg])
print(f"вставка - {avg:.6f}")
times = []
for r in range(5):
start = time.perf_counter()
for name in search_names:
ll_find(head, name)
times.append(time.perf_counter() - start)
avg = sum(times) / 5
results.append(["LinkedList", "sorted", "find", avg])
print(f"поиск - {avg:.6f}")
times = []
for r in range(5):
start = time.perf_counter()
for name in delete_names:
head = ll_delete(head, name)
times.append(time.perf_counter() - start)
avg = sum(times) / 5
results.append(["LinkedList", "sorted", "delete", avg])
print(f"удаление - {avg:.6f}")
print('HashTable - shuffled')
times =[]
for r in range(5):
buckets = create_buckets(1000)
start = time.perf_counter()
for name, phone in records_shuffled:
ht_insert(buckets,name,phone)
times.append(time.perf_counter() - start)
avg = sum(times) / 5
results.append(["HashTable", "shuffled", "insert", avg])
print(f"вставка - {avg:.6f}")
times = []
for r in range(5):
start = time.perf_counter()
for name in search_names:
ht_find(buckets, name)
times.append(time.perf_counter() - start)
avg = sum(times) / 5
results.append(["HashTable", "shuffled", "find", avg])
print(f"поиск - {avg:.6f}")
times = []
for r in range(5):
start = time.perf_counter()
for name in delete_names:
ht_delete(buckets, name)
times.append(time.perf_counter() - start)
avg = sum(times) / 5
results.append(["HashTable", "shuffled", "delete", avg])
print(f"удаление - {avg:.6f}")
print('sorted')
times = []
for r in range(5):
buckets = create_buckets(1000)
start = time.perf_counter()
for name, phone in records_sorted:
ht_insert(buckets, name, phone)
times.append(time.perf_counter() - start)
avg = sum(times) / 5
results.append(["HashTable", "sorted", "insert", avg])
print(f"вставка - {avg:.6f}")
times = []
for r in range(5):
start = time.perf_counter()
for name in search_names:
ht_find(buckets, name)
times.append(time.perf_counter() - start)
avg = sum(times) / 5
results.append(["HashTable", "sorted", "find", avg])
print(f"поиск - {avg:.6f}")
times = []
for r in range(5):
start = time.perf_counter()
for name in delete_names:
ht_delete(buckets, name)
times.append(time.perf_counter() - start)
avg = sum(times) / 5
results.append(["HashTable", "sorted", "delete", avg])
print(f"удаление - {avg:.6f}")
print("BST - shuffled")
times = []
for r in range(5):
root = None
start = time.perf_counter()
for name, phone in records_shuffled:
root = bst_insert(root, name, phone)
times.append(time.perf_counter() - start)
avg = sum(times) / 5
results.append(["Bst", "shuffled", "insert", avg])
print(f"вставка - {avg:.6f}")
times = []
for r in range(5):
start = time.perf_counter()
for name in search_names:
bst_find(root, name)
times.append(time.perf_counter() - start)
avg = sum(times) / 5
results.append(["Bst", "shuffled", "find", avg])
print(f"поиск - {avg:.6f}")
times = []
for r in range(5):
start = time.perf_counter()
for name in delete_names:
root = bst_delete(root, name)
times.append(time.perf_counter() - start)
avg = sum(times) / 5
results.append(["Bst", "shuffled", "delete", avg])
print(f"удаление - {avg:.6f}")
print('sorted')
times = []
for r in range(5):
root = None
start = time.perf_counter()
for name, phone in records_sorted:
root = bst_insert(root, name, phone)
times.append(time.perf_counter() - start)
avg = sum(times) / 5
results.append(["Bst", "sorted", "insert", avg])
print(f"вставка - {avg:.6f}")
times = []
for r in range(5):
start = time.perf_counter()
for name in search_names:
bst_find(root, name)
times.append(time.perf_counter() - start)
avg = sum(times) / 5
results.append(["Bst", "sorted", "find", avg])
print(f"поиск - {avg:.6f}")
times = []
for r in range(5):
start = time.perf_counter()
for name in delete_names:
root = bst_delete(root, name)
times.append(time.perf_counter() - start)
avg = sum(times) / 5
results.append(["Bst", "sorted", "delete", avg])
print(f"удаление - {avg:.6f}")
with open("C:/Users/Honor/Documents/dep2k/lab_inf_1/data/results.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerows(results)
if __name__ == "__main__":
run_exp()