From da3cf034d1b8ee22ed90cbef2f1636093716943f Mon Sep 17 00:00:00 2001 From: ZhuravlevDV Date: Mon, 25 May 2026 12:30:20 +0300 Subject: [PATCH 1/2] [1] firstex --- .../docs/data/firstex/LinkedListPhoneBook.py | 212 ++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 ZhuravlevDV/docs/data/firstex/LinkedListPhoneBook.py diff --git a/ZhuravlevDV/docs/data/firstex/LinkedListPhoneBook.py b/ZhuravlevDV/docs/data/firstex/LinkedListPhoneBook.py new file mode 100644 index 0000000..c2c6e64 --- /dev/null +++ b/ZhuravlevDV/docs/data/firstex/LinkedListPhoneBook.py @@ -0,0 +1,212 @@ +import time +import random +import csv + +def ll_insert(head, name, phone): + new_node = {'name': name, 'phone': phone, 'next': None} + if head is None: + return new_node + current = head + while current['next']: + current = current['next'] + current['next'] = new_node + return head + +def ll_find(head, name): + current = head + while current: + 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']: + 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: + records.append((current['name'], current['phone'])) + current = current['next'] + records.sort(key=lambda x: x[0]) + return records + +def ht_insert(buckets, name, phone): + index = hash(name) % len(buckets) + buckets[index] = ll_insert(buckets[index], name, phone) + return buckets + +def ht_find(buckets, name): + index = hash(name) % len(buckets) + return ll_find(buckets[index], name) + +def ht_delete(buckets, name): + index = hash(name) % len(buckets) + buckets[index] = ll_delete(buckets[index], name) + return buckets + +def ht_list_all(buckets): + records = [] + for bucket in buckets: + current = bucket + while current: + records.append((current['name'], current['phone'])) + current = current['next'] + records.sort(key=lambda x: x[0]) + return records + +def bst_insert(root, name, phone): + if root is None: + return {'name': name, 'phone': phone, 'left': None, 'right': None} + if name < root['name']: + root['left'] = bst_insert(root['left'], name, phone) + elif name > root['name']: + root['right'] = bst_insert(root['right'], name, phone) + else: + root['phone'] = phone + return root + +def bst_find(root, name): + if root is None: + return None + if name == root['name']: + return root['phone'] + elif name < root['name']: + return bst_find(root['left'], name) + else: + return bst_find(root['right'], name) + +def bst_min_node(node): + current = node + while current['left']: + current = current['left'] + return current + +def bst_delete(root, name): + if root is None: + return None + if name < root['name']: + root['left'] = bst_delete(root['left'], name) + elif name > root['name']: + root['right'] = bst_delete(root['right'], name) + else: + if root['left'] is None: + return root['right'] + elif root['right'] is None: + return root['left'] + temp = bst_min_node(root['right']) + root['name'] = temp['name'] + root['phone'] = temp['phone'] + root['right'] = bst_delete(root['right'], temp['name']) + return root + +def bst_list_all(root): + records = [] + if root: + records.extend(bst_list_all(root['left'])) + records.append((root['name'], root['phone'])) + records.extend(bst_list_all(root['right'])) + return records + +def generate_records(n): + records = [(f"User_{i:05d}", f"+7-999-{i:07d}") for i in range(n)] + records_shuffled = records.copy() + random.shuffle(records_shuffled) + records_sorted = sorted(records, key=lambda x: x[0]) + return records_shuffled, records_sorted + +def run_experiment(structure_name, records, insert_func, find_func, delete_func, list_all_func, buckets=None): + if structure_name == "HashTable": + buckets = [None] * 1000 + + start = time.perf_counter() + if structure_name == "HashTable": + for name, phone in records: + buckets = insert_func(buckets, name, phone) + else: + root_or_head = None + for name, phone in records: + if structure_name == "LinkedList": + root_or_head = insert_func(root_or_head, name, phone) + else: + root_or_head = insert_func(root_or_head, name, phone) + insert_time = time.perf_counter() - start + + existing_names = [name for name, _ in records[:100]] + nonexisting_names = [f"None_{i}" for i in range(10)] + all_searches = existing_names + nonexisting_names + random.shuffle(all_searches) + + start = time.perf_counter() + for name in all_searches: + if structure_name == "HashTable": + find_func(buckets, name) + else: + find_func(root_or_head, name) + find_time = time.perf_counter() - start + + delete_names = [records[i][0] for i in random.sample(range(len(records)), min(50, len(records)))] + start = time.perf_counter() + for name in delete_names: + if structure_name == "HashTable": + buckets = delete_func(buckets, name) + else: + root_or_head = delete_func(root_or_head, name) + delete_time = time.perf_counter() - start + + return insert_time, find_time, delete_time + +def main(): + N = 1000 + records_shuffled, records_sorted = generate_records(N) + + results = [] + + for mode, records in [("случайный", records_shuffled), ("отсортированный", records_sorted)]: + for run in range(5): + ins_ll, find_ll, del_ll = run_experiment("LinkedList", records, ll_insert, ll_find, ll_delete, ll_list_all) + results.append(["LinkedList", mode, "вставка", ins_ll, run+1]) + results.append(["LinkedList", mode, "поиск", find_ll, run+1]) + results.append(["LinkedList", mode, "удаление", del_ll, run+1]) + + ins_ht, find_ht, del_ht = run_experiment("HashTable", records, ht_insert, ht_find, ht_delete, ht_list_all) + results.append(["HashTable", mode, "вставка", ins_ht, run+1]) + results.append(["HashTable", mode, "поиск", find_ht, run+1]) + results.append(["HashTable", mode, "удаление", del_ht, run+1]) + + ins_bst, find_bst, del_bst = run_experiment("BST", records, bst_insert, bst_find, bst_delete, bst_list_all) + results.append(["BST", mode, "вставка", ins_bst, run+1]) + results.append(["BST", mode, "поиск", find_bst, run+1]) + results.append(["BST", mode, "удаление", del_bst, run+1]) + + with open("results.csv", "w", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + writer.writerow(["Структура", "Режим", "Операция", "Время (сек)", "Повторение"]) + writer.writerows(results) + + avg_results = {} + for row in results: + key = (row[0], row[1], row[2]) + if key not in avg_results: + avg_results[key] = [] + avg_results[key].append(row[3]) + + with open("avg_results.csv", "w", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + writer.writerow(["Структура", "Режим", "Операция", "Среднее время (сек)"]) + for (struct, mode, op), times in avg_results.items(): + writer.writerow([struct, mode, op, sum(times)/len(times)]) + +if __name__ == "__main__": + main() \ No newline at end of file From e9ede2ecb35ee1208295c80548a71c2537ba486e Mon Sep 17 00:00:00 2001 From: ZhuravlevDV Date: Mon, 25 May 2026 13:03:14 +0300 Subject: [PATCH 2/2] [2] secondex --- .../docs/data/secondex/wayoutoflabirint.py | 395 ++++++++++++++++++ 1 file changed, 395 insertions(+) create mode 100644 ZhuravlevDV/docs/data/secondex/wayoutoflabirint.py diff --git a/ZhuravlevDV/docs/data/secondex/wayoutoflabirint.py b/ZhuravlevDV/docs/data/secondex/wayoutoflabirint.py new file mode 100644 index 0000000..84734a9 --- /dev/null +++ b/ZhuravlevDV/docs/data/secondex/wayoutoflabirint.py @@ -0,0 +1,395 @@ +import heapq +import time +import csv +from abc import ABC, abstractmethod + +class Cell: + def __init__(self, x, y, is_wall=False, is_start=False, is_exit=False): + self.x = x + self.y = y + self.is_wall = is_wall + self.is_start = is_start + self.is_exit = is_exit + + def is_passable(self): + return not self.is_wall + +class Maze: + def __init__(self, width, height): + self.width = width + self.height = height + self.grid = [[None for _ in range(width)] for _ in range(height)] + self.start = None + self.exit = None + + def set_cell(self, x, y, cell): + self.grid[y][x] = cell + if cell.is_start: + self.start = cell + if cell.is_exit: + self.exit = cell + + def get_cell(self, x, y): + if 0 <= x < self.width and 0 <= y < self.height: + return self.grid[y][x] + return None + + def get_neighbors(self, cell): + neighbors = [] + directions = [(0, -1), (0, 1), (-1, 0), (1, 0)] + for dx, dy in directions: + nx, ny = cell.x + dx, cell.y + dy + neighbor = self.get_cell(nx, ny) + if neighbor and neighbor.is_passable(): + neighbors.append(neighbor) + return neighbors + +class MazeBuilder(ABC): + @abstractmethod + def build_from_file(self, filename): + pass + +class TextFileMazeBuilder(MazeBuilder): + def build_from_file(self, filename): + with open(filename, 'r', encoding='utf-8') as f: + lines = [line.rstrip('\n') for line in f.readlines()] + + height = len(lines) + width = len(lines[0]) if height > 0 else 0 + maze = Maze(width, height) + + for y, line in enumerate(lines): + for x, ch in enumerate(line): + is_wall = (ch == '#') + is_start = (ch == 'S') + is_exit = (ch == 'E') + is_passable = (ch == ' ' or is_start or is_exit) + + cell = Cell(x, y, is_wall=is_wall, is_start=is_start, is_exit=is_exit) + maze.set_cell(x, y, cell) + + return maze + +class PathFindingStrategy(ABC): + @abstractmethod + def find_path(self, maze, start, exit): + pass + +class BFSStrategy(PathFindingStrategy): + def find_path(self, maze, start, exit): + if not start or not exit: + return [] + + queue = [(start, [start])] + visited = set() + + while queue: + current, path = queue.pop(0) + + if current == exit: + return path + + if current in visited: + continue + + visited.add(current) + + for neighbor in maze.get_neighbors(current): + if neighbor not in visited: + queue.append((neighbor, path + [neighbor])) + + return [] + +class DFSStrategy(PathFindingStrategy): + def find_path(self, maze, start, exit): + if not start or not exit: + return [] + + stack = [(start, [start])] + visited = set() + + while stack: + current, path = stack.pop() + + if current == exit: + return path + + if current in visited: + continue + + visited.add(current) + + for neighbor in maze.get_neighbors(current): + if neighbor not in visited: + stack.append((neighbor, path + [neighbor])) + + return [] + +class AStarStrategy(PathFindingStrategy): + def heuristic(self, cell, exit): + return abs(cell.x - exit.x) + abs(cell.y - exit.y) + + def find_path(self, maze, start, exit): + if not start or not exit: + return [] + + open_set = [(0, id(start), start)] + came_from = {} + g_score = {start: 0} + f_score = {start: self.heuristic(start, exit)} + + while open_set: + _, _, current = heapq.heappop(open_set) + + if current == exit: + path = [] + while current in came_from: + path.append(current) + current = came_from[current] + path.append(start) + path.reverse() + return path + + for neighbor in maze.get_neighbors(current): + 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) + heapq.heappush(open_set, (f_score[neighbor], id(neighbor), neighbor)) + + return [] + +class DijkstraStrategy(PathFindingStrategy): + def find_path(self, maze, start, exit): + if not start or not exit: + return [] + + pq = [(0, id(start), start)] + distances = {start: 0} + came_from = {} + + while pq: + dist, _, current = heapq.heappop(pq) + + if current == exit: + path = [] + while current in came_from: + path.append(current) + current = came_from[current] + path.append(start) + path.reverse() + return path + + if dist > distances.get(current, float('inf')): + continue + + for neighbor in maze.get_neighbors(current): + new_dist = dist + 1 + + if new_dist < distances.get(neighbor, float('inf')): + distances[neighbor] = new_dist + came_from[neighbor] = current + heapq.heappush(pq, (new_dist, id(neighbor), neighbor)) + + return [] + +class SearchStats: + def __init__(self, time_ms, visited_cells, path_length, path=None): + self.time_ms = time_ms + self.visited_cells = visited_cells + self.path_length = path_length + self.path = path + +class MazeSolver: + def __init__(self, maze, strategy=None): + self.maze = maze + self.strategy = strategy + self.observers = [] + + def set_strategy(self, strategy): + self.strategy = strategy + + def attach(self, observer): + self.observers.append(observer) + + def notify(self, event): + for observer in self.observers: + observer.update(event) + + def solve(self): + if not self.strategy: + raise ValueError("Strategy not set") + + start_time = time.perf_counter() + path = self.strategy.find_path(self.maze, self.maze.start, self.maze.exit) + end_time = time.perf_counter() + + time_ms = (end_time - start_time) * 1000 + visited_cells = len(path) if path else 0 + path_length = len(path) if path else 0 + + self.notify(f"Path found with length {path_length} in {time_ms:.2f}ms") + + return SearchStats(time_ms, visited_cells, path_length, path) + +class Observer(ABC): + @abstractmethod + def update(self, event): + pass + +class ConsoleView(Observer): + def __init__(self): + self.last_path = None + + def update(self, event): + print(f"[ConsoleView] {event}") + + def render(self, maze, player_pos=None, path=None): + print("\n" + "=" * (maze.width * 2 + 2)) + for y in range(maze.height): + row = "" + for x in range(maze.width): + cell = maze.get_cell(x, y) + if player_pos and cell == player_pos: + row += "P " + elif path and cell in path: + row += "* " + elif cell.is_start: + row += "S " + elif cell.is_exit: + row += "E " + elif cell.is_wall: + row += "# " + else: + row += ". " + print(row) + print("=" * (maze.width * 2 + 2)) + +class Command(ABC): + @abstractmethod + def execute(self): + pass + + @abstractmethod + def undo(self): + pass + +class Player: + def __init__(self, start_cell): + self.current = start_cell + self.start = start_cell + + def move_to(self, cell): + self.current = cell + +class MoveCommand(Command): + def __init__(self, player, new_cell, maze): + self.player = player + self.new_cell = new_cell + self.old_cell = player.current + self.maze = maze + + def execute(self): + if self.new_cell.is_passable(): + self.player.move_to(self.new_cell) + return True + return False + + def undo(self): + self.player.move_to(self.old_cell) + +def generate_test_mazes(): + mazes = {} + + simple_maze = Maze(5, 5) + for y in range(5): + for x in range(5): + is_wall = (x == 2 and y == 1) or (x == 2 and y == 2) or (x == 2 and y == 3) + is_start = (x == 0 and y == 0) + is_exit = (x == 4 and y == 4) + cell = Cell(x, y, is_wall=is_wall, is_start=is_start, is_exit=is_exit) + simple_maze.set_cell(x, y, cell) + mazes["simple"] = simple_maze + + empty_maze = Maze(20, 20) + for y in range(20): + for x in range(20): + is_start = (x == 0 and y == 0) + is_exit = (x == 19 and y == 19) + cell = Cell(x, y, is_wall=False, is_start=is_start, is_exit=is_exit) + empty_maze.set_cell(x, y, cell) + mazes["empty"] = empty_maze + + return mazes + +def run_experiments(): + mazes = generate_test_mazes() + strategies = { + "BFS": BFSStrategy(), + "DFS": DFSStrategy(), + "AStar": AStarStrategy(), + "Dijkstra": DijkstraStrategy() + } + + results = [] + + for maze_name, maze in mazes.items(): + for strat_name, strategy in strategies.items(): + solver = MazeSolver(maze, strategy) + + times = [] + visited_counts = [] + path_lengths = [] + + for run in range(5): + stats = solver.solve() + times.append(stats.time_ms) + visited_counts.append(stats.visited_cells) + path_lengths.append(stats.path_length) + + avg_time = sum(times) / len(times) + avg_visited = sum(visited_counts) / len(visited_counts) + avg_length = sum(path_lengths) / len(path_lengths) + + results.append([maze_name, strat_name, avg_time, avg_visited, avg_length]) + print(f"{maze_name} | {strat_name}: {avg_time:.3f}ms, {avg_visited:.0f} cells, {avg_length:.0f} length") + + with open("maze_results.csv", "w", newline="", encoding="utf-8") as f: + writer = csv.writer(f) + writer.writerow(["Лабиринт", "Стратегия", "Время_мс", "Посещено_клеток", "Длина_пути"]) + writer.writerows(results) + + return results + +def main(): + print("Testing maze loading...") + builder = TextFileMazeBuilder() + + try: + maze = builder.build_from_file("maze.txt") + print(f"Maze loaded: {maze.width}x{maze.height}") + + solver = MazeSolver(maze) + view = ConsoleView() + solver.attach(view) + + strategies = [BFSStrategy(), DFSStrategy(), AStarStrategy(), DijkstraStrategy()] + + for strategy in strategies: + solver.set_strategy(strategy) + print(f"\n--- {strategy.__class__.__name__} ---") + stats = solver.solve() + view.render(maze, path=stats.path) + print(f"Time: {stats.time_ms:.3f}ms, Path length: {stats.path_length}") + + except FileNotFoundError: + print("maze.txt not found, running experiments with generated mazes instead") + + print("\n" + "="*50) + print("Running experiments...") + run_experiments() + +if __name__ == "__main__": + main() \ No newline at end of file