"""
Файл с описанием структур данных,
используемых в лабораторных работах
по ПРЗИ
"""

class Stack:
    """Реализация стека с помощью списка"""
    
    def __init__(self):
        self._items = []
        
    def is_empty(self):
        return len(self._items) == 0
    
    def push(self, item):
        self._items.append(item)
        
    def pop(self):
        return self._items.pop()
    
    def peek(self):
        return self._items[-1]
    
    def size(self):
        return len(self._items)
    
    def __str__(self):
        return f"Содержимое стека: {str(self._items)}\
{'⮀вершина' if not self.is_empty() else ''}"


class Queue:
    """Реализация очереди с помощью списка"""
    def __init__(self):
        self._items = []
        
    def is_empty(self):
        return len(self._items) == 0
    
    def enqueue(self, item):
        self._items.insert(0, item)
        
    def dequeue(self):
        return self._items.pop()
    
    def peek(self):
        return self._items[-1]
    
    def size(self):
        return len(self._items)
    
    def __str__(self):
        return f"Содержимое очереди: {'конец🡢' if not self.is_empty() else ''}\
{str(self._items)}{'🡢начало' if not self.is_empty() else ''}"


class Graph:
    """
    Реализация неориентированного невзвешенного графа
    через матрицу смежности.
    """
    def __init__(self, size):
        """Создание графа. size - максимальное количество вершин."""
        self.node_values = [""] * size
        self.num_edges = 0
        self.matrix = [[0] * size for _ in range(size)]
        
    def node_count(self):
        """Возвращает количество вершин."""
        return len(self.node_values)
    
    def edge_count(self):
        """Возвращает количество рёбер."""
        return self.num_edges
    
    def set_value(self, e, value):
        """Сохраняет значение value в вершине e."""
        self.node_values[e] = value
        
    def get_value(self, e):
        """Возвращает значение, сохранённое в вершине e."""
        return self.node_values[e]
    
    def add_edge(self, v, w):
        """Делает вершины v и w смежными."""
        if self.matrix[v][w] == 0:
            self.matrix[v][w] = 1
            self.matrix[w][v] = 1
            self.num_edges += 1
        
    def del_edge(self, v, w):
        """Удаляет ребро между вершинами v и w."""
        if self.matrix[v][w] != 0:
            self.matrix[v][w] = 0
            self.matrix[w][v] = 0
            self.num_edges -= 1
    
    def has_edge(self, v, w):
        """Проверяет, являются ли смежными вершины v и w."""
        return self.matrix[v][w] != 0
    
    def neighbors(self, v):
        """Возвращает список вершин смежных с вершиной v."""
        temp = []
        for i in range(len(self.node_values)):
            if self.has_edge(v, i):
                temp.append(i)
        return temp
    
    def abj(self):
        """
        Выводит на экран матрицу смежности графа
        и возвращает её.
        """
        print("Матрица смежности")
        print("   ", end="")
        for i in range(len(self.matrix)):
            print(f"{i:2}", end="")
        print()
        print("   " + "--" * len(self.matrix))
        for row in range(len(self.matrix)):
            for el in range(-1, len(self.matrix)):
                if el == -1:
                    print(f"{row:2}|", end="")
                else:
                    print(f"{self.matrix[row][el]:2}", end="")
            print()
        return self.matrix

class Node:
    def __init__(self, value, left=None, right=None):
        self.value = value
        self.left = left
        self.right = right

    def is_leaf(self):
        return self.left == None and self.right == None


if __name__ == "__main__":
    g = Graph(3)
    g.add_edge(0,2)
    a = g.abj()
    print(a)
    
    
