├── .gitignore ├── pilha ├── node.py └── stack.py ├── listas_encadeadas ├── node.py ├── raw │ └── linkedlist.py └── linkedlist.py ├── viz └── viz.py ├── listas └── busca.py ├── arvores ├── treeviz.py ├── test.py ├── examples.py ├── queue.py └── tree.py └── fila └── queue.py /.gitignore: -------------------------------------------------------------------------------- 1 | */*.pyc 2 | */__pycache__/* 3 | draft/* 4 | .DS_Store 5 | venv/* 6 | -------------------------------------------------------------------------------- /pilha/node.py: -------------------------------------------------------------------------------- 1 | class Node: 2 | def __init__(self, data): 3 | self.data = data 4 | self.next = None 5 | -------------------------------------------------------------------------------- /listas_encadeadas/node.py: -------------------------------------------------------------------------------- 1 | class Node: 2 | def __init__(self, data): 3 | self.data = data 4 | self.next = None 5 | -------------------------------------------------------------------------------- /viz/viz.py: -------------------------------------------------------------------------------- 1 | import graphviz 2 | 3 | dot = graphviz.Digraph(comment='The Round Table') 4 | 5 | dot.node('A', 'King Arthur') 6 | dot.node('B', 'Sir Bedevere the Wise') 7 | dot.node('L', 'Sir Lancelot the Brave') 8 | 9 | dot.edges(['AB', 'AL']) 10 | dot.edge('B', 'L', constraint='false') 11 | 12 | dot.render('viz/round-table.gv', view=True).replace('\\', '/') -------------------------------------------------------------------------------- /listas/busca.py: -------------------------------------------------------------------------------- 1 | # Busca linear em lista em alocação sequencial 2 | 3 | def busca(lista, elem): 4 | """Retorna o índice elem se ele estiver na lista ou None, caso contrário""" 5 | for i in range(len(lista)): 6 | if lista[i] == elem: 7 | return i 8 | return None 9 | 10 | lista_estranha = [8, "5", 32, 0, "python", 11] 11 | elemento = "python" 12 | 13 | indice = busca(lista_estranha, elemento) 14 | if indice is not None: 15 | print("O índice do elemento {} é {}".format(elemento, indice)) 16 | else: 17 | print("O elemento {} não se encontra na lista".format(elemento)) 18 | -------------------------------------------------------------------------------- /arvores/treeviz.py: -------------------------------------------------------------------------------- 1 | import graphviz 2 | from examples import inorder_example_tree 3 | from test import random_tree 4 | 5 | 6 | def preorder_traversal(tree, dot): 7 | # visita a raiz 8 | dot.node(str(tree.data), str(tree.data)) 9 | if tree.left: 10 | preorder_traversal(tree.left, dot) 11 | dot.edge(str(tree.data), str(tree.left.data)) 12 | if tree.right: 13 | preorder_traversal(tree.right, dot) 14 | dot.edge(str(tree.data), str(tree.right.data)) 15 | 16 | def make_viz(tree, name): 17 | dot = graphviz.Digraph(comment=name) 18 | preorder_traversal(tree.root, dot) 19 | dot.render(f'viz/{name}.gv', view=True).replace('\\', '/') 20 | 21 | if __name__ == '__main__': 22 | # tree = inorder_example_tree() 23 | # make_viz(tree, "expressao") 24 | tree = random_tree(16) 25 | make_viz(tree, "aleatoria") -------------------------------------------------------------------------------- /arvores/test.py: -------------------------------------------------------------------------------- 1 | import random 2 | from tree import BinarySearchTree 3 | 4 | random.seed(77) 5 | 6 | def random_tree(size=42): 7 | values = random.sample(range(1, 1000), size) 8 | tree = BinarySearchTree() 9 | for v in values: 10 | tree.insert(v) 11 | return tree 12 | 13 | def example_tree(): 14 | values = [61, 89, 66, 43, 51, 16, 55, 11, 79, 77, 82, 32] 15 | tree = BinarySearchTree() 16 | for v in values: 17 | tree.insert(v) 18 | return tree 19 | 20 | def extended_tree(): 21 | values = [61, 89, 66, 43, 51, 16, 55, 11, 79, 77, 82, 32, 100, 90] 22 | tree = BinarySearchTree() 23 | for v in values: 24 | tree.insert(v) 25 | return tree 26 | 27 | bst = extended_tree() 28 | bst.inorder_traversal() 29 | 30 | # testar remoção da árvore 31 | print('\n----') 32 | v = 61 33 | bst.remove(v) 34 | print("Após remover {}".format(v)) 35 | bst.inorder_traversal() 36 | print('\n') 37 | bst.levelorder_traversal() 38 | 39 | print("\n-------") 40 | print("Máximo:", bst.max()) 41 | print("Mínimo:", bst.min()) 42 | 43 | # print('\n-----') 44 | # items = [1, 3, 981, 510, 1000] 45 | # for item in items: 46 | # r = bst.search(item) 47 | # if r is None: 48 | # print(item, "não encontrado") 49 | # else: 50 | # print(r.root.data, 'encontrado') -------------------------------------------------------------------------------- /pilha/stack.py: -------------------------------------------------------------------------------- 1 | from node import Node 2 | 3 | # inserir na pilha 4 | # remover da pilha 5 | # observar o topo da pilha 6 | class Stack: 7 | def __init__(self): 8 | self.top = None 9 | self._size = 0 10 | 11 | def push(self, elem): 12 | #insere um elemento na pilha 13 | node = Node(elem) 14 | node.next = self.top 15 | self.top = node 16 | self._size = self._size + 1 17 | 18 | def pop(self): 19 | # remove o elemento do topo da pilha 20 | if self._size > 0: 21 | node = self.top 22 | self.top = self.top.next 23 | self._size = self._size - 1 24 | return node.data 25 | raise IndexError("The stack is empty") 26 | 27 | def peek(self): 28 | # retorna o topo sem remover 29 | if self._size > 0: 30 | return self.top.data 31 | raise IndexError("The stack is empty") 32 | 33 | 34 | def __len__(self): 35 | """Retorna o tamanho da lista""" 36 | return self._size 37 | 38 | def __repr__(self): 39 | r = "" 40 | pointer = self.top 41 | while(pointer): 42 | r = r + str(pointer.data) + "\n" 43 | pointer = pointer.next 44 | return r 45 | 46 | def __str__(self): 47 | return self.__repr__() 48 | -------------------------------------------------------------------------------- /arvores/examples.py: -------------------------------------------------------------------------------- 1 | from tree import BinaryTree, Node 2 | 3 | # Vídeo Implementando uma árvore binária: https://youtu.be/6E169kShoNU 4 | def inorder_example_tree(): 5 | tree = BinaryTree() 6 | n1 = Node('a') 7 | n2 = Node('+') 8 | n3 = Node('*') 9 | n4 = Node('b') 10 | n5 = Node('-') 11 | n6 = Node('/') 12 | n7 = Node('c') 13 | n8 = Node('d') 14 | n9 = Node('e') 15 | 16 | n6.left = n7 17 | n6.right = n8 18 | n5.left = n6 19 | n5.right = n9 20 | n3.left = n4 21 | n3.right = n5 22 | n2.left = n1 23 | n2.right = n3 24 | 25 | tree.root = n2 26 | return tree 27 | # tree.simetric_traversal() 28 | # print() 29 | 30 | # '+' 31 | # / \ 32 | # 'a' '*' 33 | # / \ 34 | # 'b' '-' 35 | # / \ 36 | # '/' 'e' 37 | # / \ 38 | # 'c' 'd' 39 | 40 | # (a + (b * ((c/d) - e))) 41 | 42 | # Vídeo Percurso em Pós-Ordem: 43 | def postorder_example_tree(): 44 | tree = BinaryTree() 45 | n1 = Node('I') 46 | n2 = Node('N') 47 | n3 = Node('S') 48 | n4 = Node('C') 49 | n5 = Node('R') 50 | n6 = Node('E') 51 | n7 = Node('V') 52 | n8 = Node('A') 53 | n9 = Node('5') 54 | n0 = Node('3') 55 | 56 | n0.left = n6 57 | n0.right = n9 58 | n6.left = n1 59 | n6.right = n5 60 | n5.left = n2 61 | n5.right = n4 62 | n4.right = n3 63 | n9.left = n8 64 | n8.right = n7 65 | 66 | tree.root = n0 67 | return tree 68 | 69 | 70 | if __name__ == "__main__": 71 | tree = postorder_example_tree() 72 | print("Percurso em pós ordem:") 73 | tree.postorder_traversal() 74 | print("Altura: ", tree.height()) 75 | 76 | 77 | -------------------------------------------------------------------------------- /fila/queue.py: -------------------------------------------------------------------------------- 1 | # Nó para alocação de uma Fila 2 | class Node: 3 | def __init__(self, data): 4 | self.data = data 5 | self.next = None 6 | 7 | # Classe que define uma Fila 8 | class Queue: 9 | def __init__(self): 10 | self.first = None 11 | self.last = None 12 | self._size = 0 13 | 14 | # inserir na fila 15 | def push(self, elem): 16 | """Insere um elemento na fila""" 17 | node = Node(elem) 18 | if self.last is None: 19 | self.last = node 20 | else: 21 | self.last.next = node 22 | self.last = node 23 | 24 | if self.first is None: 25 | self.first = node 26 | 27 | self._size = self._size + 1 28 | 29 | # remover da fila 30 | def pop(self): 31 | """Remove o elemento do topo da pilha""" 32 | if self._size > 0: 33 | elem = self.first.data 34 | self.first = self.first.next 35 | # faltou tratar este caso no vídeo # 36 | if self.first is None: 37 | self.last = None 38 | #################################### 39 | self._size = self._size - 1 40 | return elem 41 | raise IndexError("The queue is empty") 42 | 43 | # observar o primeiro da fila 44 | def peek(self): 45 | """Retorna o topo sem remover""" 46 | if self._size > 0: 47 | elem = self.first.data 48 | return elem 49 | raise IndexError("The queue is empty") 50 | 51 | 52 | def __len__(self): 53 | """Retorna o tamanho da lista""" 54 | return self._size 55 | 56 | 57 | def __repr__(self): 58 | if self._size > 0: 59 | r = "" 60 | pointer = self.first 61 | while(pointer): 62 | r = r + str(pointer.data) + " " 63 | pointer = pointer.next 64 | return r 65 | return "Empty Queue" 66 | 67 | def __str__(self): 68 | return self.__repr__() 69 | -------------------------------------------------------------------------------- /arvores/queue.py: -------------------------------------------------------------------------------- 1 | # Nó para alocação de uma Fila 2 | class Node: 3 | def __init__(self, data): 4 | self.data = data 5 | self.next = None 6 | 7 | # Classe que define uma Fila 8 | class Queue: 9 | def __init__(self): 10 | self.first = None 11 | self.last = None 12 | self._size = 0 13 | 14 | # inserir na fila 15 | def push(self, elem): 16 | """Insere um elemento na fila""" 17 | node = Node(elem) 18 | if self.last is None: 19 | self.last = node 20 | else: 21 | self.last.next = node 22 | self.last = node 23 | 24 | if self.first is None: 25 | self.first = node 26 | 27 | self._size = self._size + 1 28 | 29 | # remover da fila 30 | def pop(self): 31 | """Remove o elemento do topo da pilha""" 32 | if self._size > 0: 33 | elem = self.first.data 34 | self.first = self.first.next 35 | # faltou tratar este caso no vídeo # 36 | if self.first is None: 37 | self.last = None 38 | #################################### 39 | self._size = self._size - 1 40 | return elem 41 | raise IndexError("The queue is empty") 42 | 43 | # observar o primeiro da fila 44 | def peek(self): 45 | """Retorna o topo sem remover""" 46 | if self._size > 0: 47 | elem = self.first.data 48 | return elem 49 | raise IndexError("The queue is empty") 50 | 51 | 52 | def __len__(self): 53 | """Retorna o tamanho da lista""" 54 | return self._size 55 | 56 | 57 | def __repr__(self): 58 | if self._size > 0: 59 | r = "" 60 | pointer = self.first 61 | while(pointer): 62 | r = r + str(pointer.data) + " " 63 | pointer = pointer.next 64 | return r 65 | return "Empty Queue" 66 | 67 | def __str__(self): 68 | return self.__repr__() 69 | -------------------------------------------------------------------------------- /listas_encadeadas/raw/linkedlist.py: -------------------------------------------------------------------------------- 1 | from node import Node 2 | 3 | class LinkedList: 4 | 5 | def __init__(self): 6 | self.head = None 7 | self._size = 0 8 | 9 | def append(self, elem): 10 | """Insere elem ao final da lista""" 11 | if self.head: 12 | pointer = self.head 13 | while(pointer.next): 14 | pointer = pointer.next 15 | pointer.next = Node(elem) 16 | else: 17 | self.head = Node(elem) 18 | self._size = self._size + 1 19 | 20 | def __getitem__(self, index): 21 | pointer = self.head 22 | for i in range(index): 23 | if pointer: 24 | pointer = pointer.next 25 | else: 26 | raise IndexError("list index out of range") 27 | if pointer: 28 | return pointer.data 29 | raise IndexError("list index out of range") 30 | 31 | def __setitem__(self, index, elem): 32 | pointer = self.head 33 | for i in range(index): 34 | if pointer: 35 | pointer = pointer.next 36 | else: 37 | raise IndexError("list index out of range") 38 | if pointer: 39 | pointer.data = elem 40 | else: 41 | raise IndexError("list index out of range") 42 | 43 | def index(self, elem): 44 | """Retorna o índice de elem na lista""" 45 | pointer = self.head 46 | i = 0 47 | while(pointer): 48 | if pointer.data == elem: 49 | return i 50 | pointer = pointer.next 51 | i = i+1 52 | return -1 53 | 54 | def __len__(self): 55 | return self._size 56 | 57 | # def remove(self, elem): 58 | # pointer = self.head 59 | # if pointer.data == elem: #queremos remover o primeiro elemento 60 | # self.head = pointer.next 61 | # else: 62 | # while(pointer.next): 63 | # if pointer.next.data == elem: 64 | # pointer.next = pointer.next.next 65 | lista.append(7) 66 | lista.append(8) 67 | lista.append(9) 68 | -------------------------------------------------------------------------------- /listas_encadeadas/linkedlist.py: -------------------------------------------------------------------------------- 1 | from node import Node 2 | 3 | 4 | class LinkedList: 5 | def __init__(self): 6 | self.head = None 7 | self._size = 0 8 | 9 | def append(self, elem): 10 | if self.head: 11 | # inserção quando a lista já possui elementos 12 | pointer = self.head 13 | while(pointer.next): 14 | pointer = pointer.next 15 | pointer.next = Node(elem) 16 | else: 17 | # primeira inserção 18 | self.head = Node(elem) 19 | self._size = self._size + 1 20 | 21 | def __len__(self): 22 | """Retorna o tamanho da lista""" 23 | return self._size 24 | 25 | def _getnode(self, index): 26 | pointer = self.head 27 | for i in range(index): 28 | if pointer: 29 | pointer = pointer.next 30 | else: 31 | raise IndexError("list index out of range") #return None 32 | return pointer 33 | 34 | def set(self, index, elem): 35 | # lista.set(5, 9) 36 | pass 37 | 38 | def __getitem__(self, index): 39 | # a = lista[6] 40 | pointer = self._getnode(index) 41 | if pointer: 42 | return pointer.data 43 | else: 44 | raise IndexError("list index out of range") 45 | 46 | def __setitem__(self, index, elem): 47 | # lista[5] = 9 48 | pointer = self._getnode(index) 49 | if pointer: 50 | pointer.data = elem 51 | else: 52 | raise IndexError("list index out of range") 53 | 54 | def index(self, elem): 55 | """Retorna o índice do elem na lista""" 56 | pointer = self.head 57 | i = 0 58 | while(pointer): 59 | if pointer.data == elem: 60 | return i 61 | pointer = pointer.next 62 | i = i+1 63 | raise ValueError("{} is not in list".format(elem)) 64 | 65 | def insert(self, index, elem): 66 | node = Node(elem) 67 | if index == 0: 68 | node.next = self.head 69 | self.head = node 70 | else: 71 | pointer = self._getnode(index-1) 72 | node.next = pointer.next 73 | pointer.next = node 74 | self._size = self._size + 1 75 | 76 | def remove(self, elem): 77 | if self.head == None: 78 | raise ValueError("{} is not in list".format(elem)) 79 | elif self.head.data == elem: 80 | self.head = self.head.next 81 | self._size = self._size - 1 82 | return True 83 | else: 84 | ancestor = self.head 85 | pointer = self.head.next 86 | while(pointer): 87 | if pointer.data == elem: 88 | ancestor.next = pointer.next 89 | pointer.next = None 90 | self._size = self._size - 1 91 | return True 92 | ancestor = pointer 93 | pointer = pointer.next 94 | raise ValueError("{} is not in list".format(elem)) 95 | 96 | def __repr__(self): 97 | r = "" 98 | pointer = self.head 99 | while(pointer): 100 | r = r + str(pointer.data) + "->" 101 | pointer = pointer.next 102 | return r 103 | 104 | def __str__(self): 105 | return self.__repr__() 106 | 107 | if __name__ == '__main__': 108 | # sequencial = [] 109 | # sequencial.append(7) 110 | lista = LinkedList() 111 | lista.append(7) 112 | lista.append(80) 113 | lista.append(56) 114 | lista.append(32) 115 | lista.append(17) 116 | -------------------------------------------------------------------------------- /arvores/tree.py: -------------------------------------------------------------------------------- 1 | # Programação Dinâmica - Estruturas de Dados 2 | # Implementação de Árvores e seus algoritmos - by hallpaz 3 | # https://youtube.com/programacaodinamica 4 | 5 | from queue import Queue 6 | 7 | 8 | ROOT = "root" 9 | # Implementando uma Árvore Binária: https://youtu.be/6E169kShoNU 10 | class Node: 11 | def __init__(self, data): 12 | self.data = data 13 | self.left = None 14 | self.right = None 15 | 16 | def __str__(self): 17 | return str(self.data) 18 | 19 | class BinaryTree: 20 | def __init__(self, data=None, node=None): 21 | if node: 22 | self.root = node 23 | elif data: 24 | node = Node(data) 25 | self.root = node 26 | else: 27 | self.root = None 28 | 29 | # Percurso em ordem simétrica (o correto é "inorder" em inglês) 30 | def simetric_traversal(self, node=None): 31 | if node is None: 32 | node = self.root 33 | if node.left: 34 | # parênteses são específicos para o nosso exemplo, 35 | # um percurso em ordem simétrica não precisa deles 36 | print('(', end='') 37 | self.simetric_traversal(node.left) 38 | print(node, end='') 39 | if node.right: 40 | self.simetric_traversal(node.right) 41 | print(')', end='') 42 | 43 | # Percurso em PÓS ORDEM em ÁRVORE BINÁRIA: https://youtu.be/QC8oiQnlYos 44 | def postorder_traversal(self, node=None): 45 | if node is None: 46 | node = self.root 47 | if node.left: 48 | self.postorder_traversal(node.left) 49 | if node.right: 50 | self.postorder_traversal(node.right) 51 | print(node) 52 | 53 | def height(self, node=None): 54 | if node is None: 55 | node = self.root 56 | hleft = 0 57 | hright = 0 58 | if node.left: 59 | hleft = self.height(node.left) 60 | if node.right: 61 | hright = self.height(node.right) 62 | if hright > hleft: 63 | return hright + 1 64 | return hleft + 1 65 | 66 | def inorder_traversal(self, node=None): 67 | if node is None: 68 | node = self.root 69 | if node.left: 70 | self.inorder_traversal(node.left) 71 | print(node, end=' ') 72 | if node.right: 73 | self.inorder_traversal(node.right) 74 | 75 | # Percurso em Nível em Árvore Binária: https://youtu.be/UOK7nS2E9xM 76 | def levelorder_traversal(self, node=ROOT): 77 | if node == ROOT: 78 | node = self.root 79 | 80 | queue = Queue() 81 | queue.push(node) 82 | while len(queue): 83 | node = queue.pop() 84 | if node.left: 85 | queue.push(node.left) 86 | if node.right: 87 | queue.push(node.right) 88 | print(node, end=" ") 89 | 90 | # Árvore Binária de Busca: https://youtu.be/rviJVdt_icw 91 | class BinarySearchTree(BinaryTree): 92 | 93 | def insert(self, value): 94 | parent = None 95 | x = self.root 96 | while(x): 97 | parent = x 98 | if value < x.data: 99 | x = x.left 100 | else: 101 | x = x.right 102 | if parent is None: 103 | self.root = Node(value) 104 | elif value < parent.data: 105 | parent.left = Node(value) 106 | else: 107 | parent.right = Node(value) 108 | 109 | def search(self, value): 110 | return self._search(value, self.root) 111 | 112 | def _search(self, value, node): 113 | if node is None: 114 | return node 115 | if node.data == value: 116 | return BinarySearchTree(node) 117 | if value < node.data: 118 | return self._search(value, node.left) 119 | return self._search(value, node.right) 120 | 121 | # Encontrando o MAIOR e o MENOR elemento numa ÁRVORE Binária de Busca: https://youtu.be/Q9s_XyJpHTI 122 | def min(self, node=ROOT): 123 | if node == ROOT: 124 | node = self.root 125 | while node.left: 126 | node = node.left 127 | return node.data 128 | 129 | def max(self, node=ROOT): 130 | if node == ROOT: 131 | node = self.root 132 | while node.right: 133 | node = node.right 134 | return node.data 135 | 136 | # REMOVENDO da Árvore Binária de Busca: https://youtu.be/dyLwOXBA3Ws 137 | def remove(self, value, node=ROOT): 138 | # Se for o valor padrão, executa a partir da raiz 139 | if node == ROOT: 140 | node = self.root 141 | # Se desceu até um ramo nulo, não há nada a fazer 142 | if node is None: 143 | return node 144 | # Se o valor for menor, desce à esquerda 145 | if value < node.data: 146 | node.left = self.remove(value, node.left) 147 | # Se o valor for maior, desce à direita 148 | elif value > node.data: 149 | node.right = self.remove(value, node.right) 150 | # Se não for nem menor, nem maior, encontramos! Vamos remover... 151 | else: 152 | if node.left is None: 153 | return node.right 154 | elif node.right is None: 155 | return node.left 156 | else: 157 | # Substituto é o sucessor do valor a ser removido 158 | substitute = self.min(node.right) 159 | # Ao invés de trocar a posição dos nós, troca o valor 160 | node.data = substitute 161 | # Depois, remove o substituto da subárvore à direita 162 | node.right = self.remove(substitute, node.right) 163 | 164 | return node 165 | 166 | 167 | # def search(self, value, node=ROOT): 168 | # if node == ROOT: 169 | # node = self.root 170 | # if node is None or node.data == value: 171 | # return BinarySearchTree(node) 172 | # if value < node.data: 173 | # return self.search(value, node.left) 174 | # return self.search(value, node.right) 175 | 176 | 177 | 178 | if __name__ == "__main__": 179 | tree = BinaryTree(7) 180 | tree.root.left = Node(18) 181 | tree.root.right = Node(14) 182 | 183 | print(tree.root) 184 | print(tree.root.right) 185 | print(tree.root.left) 186 | 187 | --------------------------------------------------------------------------------