├── README.md ├── Lista_Encadeada.py ├── Matriz_Adjacencias.py ├── Lista_Adjacencias.py ├── Arvore_Binaria.py ├── Lista_Adjacencias_Valorado.py ├── Matriz_Distancias.py ├── Arvore_Binaria_Busca.py ├── Euleriano.py ├── HeapMax.py ├── HeapMin.py └── Dijkstra.py /README.md: -------------------------------------------------------------------------------- 1 | # Aulas_de_Grafos 2 | Implementações em Python do curso de Grafos disponível em https://youtube.com/playlist?list=PLrOyM49ctTx-xtyVeuO7ylclgXHd4ws9a 3 | -------------------------------------------------------------------------------- /Lista_Encadeada.py: -------------------------------------------------------------------------------- 1 | class No: 2 | 3 | def __init__(self, valor): 4 | self.valor = valor 5 | self.proximo = None 6 | 7 | def obtervalor(self): 8 | return self.valor 9 | 10 | def setproximo(self, proximo): 11 | self.proximo = proximo 12 | 13 | def obterproximo(self): 14 | return self.proximo 15 | 16 | 17 | no1 = No(4) 18 | no2 = No(7) 19 | 20 | print(no1.obtervalor()) 21 | print(no2.obtervalor()) 22 | 23 | no1.setproximo(no2) 24 | 25 | print(no1.obterproximo()) 26 | print(no1.obterproximo().obtervalor()) -------------------------------------------------------------------------------- /Matriz_Adjacencias.py: -------------------------------------------------------------------------------- 1 | class Grafo: 2 | 3 | 4 | def __init__(self, vertices): 5 | self.vertices = vertices 6 | self.grafo = [[0]*self.vertices for i in range(self.vertices)] 7 | 8 | def adiciona_aresta(self, u, v): 9 | # estou pensando em grafos direcionados simples 10 | self.grafo[u-1][v-1] = 1 #trocar = por += ser for grafo múltiplo 11 | 12 | # self.grafo[v-1][u-1] = 1 (caso o grafo não seja direcionado) 13 | 14 | def mostra_matriz(self): 15 | print('A matriz de adjacências é:') 16 | for i in range(self.vertices): 17 | print(self.grafo[i]) 18 | 19 | 20 | g = Grafo(4) 21 | 22 | g.adiciona_aresta(1, 2) 23 | g.adiciona_aresta(3, 4) 24 | g.adiciona_aresta(2, 3) 25 | 26 | g.mostra_matriz() -------------------------------------------------------------------------------- /Lista_Adjacencias.py: -------------------------------------------------------------------------------- 1 | class Grafo: 2 | 3 | def __init__(self, vertices): 4 | self.vertices = vertices 5 | self.grafo = [[] for i in range(self.vertices)] 6 | 7 | def adiciona_aresta(self, u, v): 8 | # estamos pensando em grafo direcionado sem peso nas arestas 9 | self.grafo[u-1].append(v) 10 | 11 | # self.grafo[v-1].append(u) se o grafo não for direcionado 12 | 13 | def mostra_lista(self): 14 | for i in range(self.vertices): 15 | print(f'{i+1}:', end=' ') 16 | for j in self.grafo[i]: 17 | print(f'{j} ->', end=' ') 18 | print('') 19 | 20 | g = Grafo(4) 21 | 22 | g.adiciona_aresta(1,2) 23 | g.adiciona_aresta(1,3) 24 | g.adiciona_aresta(1,4) 25 | g.adiciona_aresta(2,3) 26 | 27 | g.mostra_lista() -------------------------------------------------------------------------------- /Arvore_Binaria.py: -------------------------------------------------------------------------------- 1 | class No: 2 | 3 | def __init__(self, valor): 4 | self.valor = valor 5 | self.esquerda = None 6 | self.direita = None 7 | 8 | def obtervalor(self): 9 | return self.valor 10 | 11 | def setesquerda(self, esquerda): 12 | self.esquerda = esquerda 13 | 14 | def setdireita(self, direita): 15 | self.direita = direita 16 | 17 | def obteresquerda(self): 18 | return self.esquerda 19 | 20 | def obterdireita(self): 21 | return self.direita 22 | 23 | 24 | no1 = No(4) 25 | no2 = No(2) 26 | no3 = No(5) 27 | 28 | no1.setesquerda(no2) 29 | no1.setdireita(no3) 30 | 31 | print(no1.obtervalor()) 32 | print(no1.obterdireita()) 33 | print(no1.obterdireita().obtervalor()) 34 | print(no1.obteresquerda()) 35 | print(no1.obteresquerda().obtervalor()) -------------------------------------------------------------------------------- /Lista_Adjacencias_Valorado.py: -------------------------------------------------------------------------------- 1 | class Grafo: 2 | 3 | def __init__(self, vertices): 4 | self.vertices = vertices 5 | self.grafo = [[] for i in range(self.vertices)] 6 | 7 | def adiciona_aresta(self, u, v, peso): 8 | # estamos pensando em grafo direcionado com peso nas arestas 9 | self.grafo[u-1].append([v, peso]) 10 | 11 | # self.grafo[v-1].append([u,peso]) se o grafo não for direcionado 12 | 13 | def mostra_lista(self): 14 | for i in range(self.vertices): 15 | print(f'{i+1}:', end=' ') 16 | for j in self.grafo[i]: 17 | print(f'{j} ->', end=' ') 18 | print('') 19 | 20 | g = Grafo(4) 21 | 22 | g.adiciona_aresta(1, 2, 5) 23 | g.adiciona_aresta(1, 3, 7) 24 | g.adiciona_aresta(1, 4, 6) 25 | g.adiciona_aresta(2, 3, 9) 26 | 27 | g.mostra_lista() -------------------------------------------------------------------------------- /Matriz_Distancias.py: -------------------------------------------------------------------------------- 1 | class Grafo: 2 | 3 | 4 | def __init__(self, vertices): 5 | self.vertices = vertices 6 | self.grafo = [[0]*self.vertices for i in range(self.vertices)] 7 | 8 | def adiciona_aresta(self, u, v, peso): 9 | # estou pensando em grafos direcionados simples 10 | self.grafo[u-1][v-1] = peso #trocar = por += ser for grafo múltiplo 11 | 12 | # self.grafo[v-1][u-1] = 1 (caso o grafo não seja direcionado) 13 | 14 | def mostra_matriz(self): 15 | print('A matriz de adjacências é:') 16 | for i in range(self.vertices): 17 | print(self.grafo[i]) 18 | 19 | #g = Grafo(4) 20 | 21 | #g.adiciona_aresta(1, 2, 5) 22 | #g.adiciona_aresta(3, 4, 9) 23 | #g.adiciona_aresta(2, 3, 3) 24 | 25 | #g.mostra_matriz() 26 | 27 | v = int(input('Digite a quantidade de vértices')) 28 | g = Grafo(v) 29 | 30 | a = int(input('Digite a quantidade de arestas')) 31 | for i in range(a): 32 | u = int(input('De qual vértice parte esta aresta?')) 33 | v = int(input('Para qual vértice chega esta aresta?')) 34 | p = int(input('Qual é o peso desta aresta?')) 35 | g.adiciona_aresta(u, v, p) 36 | 37 | g.mostra_matriz() 38 | -------------------------------------------------------------------------------- /Arvore_Binaria_Busca.py: -------------------------------------------------------------------------------- 1 | class No: 2 | 3 | def __init__(self, valor): 4 | self.valor = valor 5 | self.esquerda = None 6 | self.direita = None 7 | 8 | def obtervalor(self): 9 | return self.valor 10 | 11 | def setesquerda(self, esquerda): 12 | self.esquerda = esquerda 13 | 14 | def setdireita(self, direita): 15 | self.direita = direita 16 | 17 | def obteresquerda(self): 18 | return self.esquerda 19 | 20 | def obterdireita(self): 21 | return self.direita 22 | 23 | 24 | class ArvoreBinariaBusca: 25 | 26 | def __init__(self): 27 | self.raiz = None 28 | 29 | def obterraiz(self): 30 | return self.raiz 31 | 32 | def insere(self, valor): 33 | no = No(valor) 34 | if self.raiz == None: 35 | self.raiz = no 36 | else: 37 | no_pai = None 38 | no_atual = self.raiz 39 | while True: 40 | if no_atual != None: 41 | no_pai = no_atual 42 | if no.obtervalor() < no_atual.obtervalor(): 43 | no_atual = no_atual.obteresquerda() 44 | else: 45 | no_atual = no_atual.obterdireita() 46 | else: 47 | if no.obtervalor() < no_pai.obtervalor(): 48 | no_pai.setesquerda(no) 49 | else: 50 | no_pai.setdireita(no) 51 | break 52 | 53 | def mostraarvore(self, no_atual): #percursso em ordem simétrica 54 | if no_atual != None: 55 | self.mostraarvore(no_atual.obteresquerda()) 56 | print(f'{no_atual.obtervalor()}', end=' ') 57 | self.mostraarvore(no_atual.obterdireita()) 58 | 59 | 60 | t = ArvoreBinariaBusca() 61 | 62 | t.insere(8) 63 | t.insere(3) 64 | t.insere(6) 65 | t.insere(10) 66 | t.insere(14) 67 | t.insere(1) 68 | t.insere(7) 69 | t.insere(13) 70 | t.insere(4) 71 | 72 | t.mostraarvore(t.obterraiz()) -------------------------------------------------------------------------------- /Euleriano.py: -------------------------------------------------------------------------------- 1 | class Grafo: 2 | 3 | 4 | def __init__(self, vertices): 5 | self.vertices = vertices 6 | self.grafo = [[0]*self.vertices for i in range(self.vertices)] 7 | 8 | def adiciona_aresta(self, u, v): 9 | # estou pensando em grafos não direcionados 10 | self.grafo[u-1][v-1] += 1 11 | if u != v: 12 | self.grafo[v-1][u-1] += 1 13 | 14 | def mostra_matriz(self): 15 | print('A matriz de adjacências é:') 16 | for i in range(self.vertices): 17 | print(self.grafo[i]) 18 | 19 | def tem_aresta(self, u, v): 20 | if self.grafo[u-1][v-1] == 0: 21 | print(f'Não tem aresta entre os vértices {u} e {v}') 22 | else: 23 | print(f'Existe {self.grafo[u-1][v-1]} de arestas entre os vértices {u} e {v}') 24 | 25 | def eh_euleriano(self): 26 | contador = 0 27 | for i in range(self.vertices): 28 | grau = 0 29 | for j in range(self.vertices): 30 | if i == j: 31 | grau = grau + 2 * self.grafo[i][j] 32 | else: 33 | grau += self.grafo[i][j] 34 | if grau % 2 != 0: 35 | contador += 1 36 | if contador == 0: 37 | print('É um grafo euleriano!') 38 | elif contador == 2: 39 | print('É um grafo semieuleriano!') 40 | else: 41 | print('O grafo não é euleriano e nem semieulariano!') 42 | 43 | 44 | g = Grafo(4) 45 | 46 | g.adiciona_aresta(1, 2) 47 | g.adiciona_aresta(3, 4) 48 | #g.adiciona_aresta(2, 3) 49 | #g.adiciona_aresta(1,4) 50 | 51 | #g.tem_aresta(2,4) 52 | 53 | g.eh_euleriano() 54 | 55 | g.mostra_matriz() -------------------------------------------------------------------------------- /HeapMax.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class HeapMax: 4 | 5 | def __init__(self): 6 | self.nos = 0 7 | self.heap = [] 8 | 9 | def adiciona_no(self, u): 10 | self.heap.append(u) 11 | self.nos += 1 12 | f = self.nos 13 | while True: 14 | if f == 1: 15 | break 16 | p = f // 2 17 | if self.heap[p-1] >= self.heap[f-1]: # <= HeapMin 18 | break 19 | else: 20 | self.heap[p-1], self.heap[f-1] = self.heap[f-1], self.heap[p-1] 21 | f = p 22 | 23 | def mostra_heap(self): 24 | #print(self.heap) 25 | print('A estrutura heap é a seguinte:') 26 | nivel = int(math.log(self.nos, 2)) 27 | a = 0 28 | for i in range(nivel): 29 | for j in range(2 ** i): 30 | print(f'{self.heap[a]}', end = ' ') 31 | a += 1 32 | print('') 33 | for i in range(self.nos - a): 34 | print(f'{self.heap[a]}', end = ' ') 35 | a += 1 36 | print('') 37 | 38 | def remove_no(self): 39 | x = self.heap[0] 40 | self.heap[0] = self.heap[self.nos - 1] 41 | self.heap.pop() 42 | self.nos -= 1 43 | p = 1 44 | while True: 45 | f = 2 * p 46 | if f > self.nos: 47 | break 48 | if f+1 <= self.nos: 49 | if self.heap[f] > self.heap[f-1]: # < se for HeapMin 50 | f += 1 51 | if self.heap[p-1] >= self.heap[f-1]: # <= se for HeapMin 52 | break 53 | else: 54 | self.heap[f-1], self.heap[p-1] = self.heap[p-1], self.heap[f-1] 55 | p = f 56 | return x 57 | 58 | def tamanho(self): 59 | return self.nos 60 | 61 | def maior_elemento(self): 62 | if self.nos != 0: 63 | return self.heap[0] 64 | return 'A árvore está vazia' 65 | 66 | def filho_esqueda(self, i): 67 | if self.nos >= 2*i: 68 | return self.heap[2*i - 1] 69 | return 'Esse nó não tem filho!' 70 | 71 | def filho_direita(self, i): 72 | if self.nos >= 2*i+1: 73 | return self.heap[2*i] 74 | return 'Esse nó não tem filho à direita!' 75 | 76 | def pai(self, i): 77 | return self.heap[i // 2] 78 | 79 | 80 | 81 | 82 | h = HeapMax() 83 | 84 | h.adiciona_no(17) 85 | h.adiciona_no(36) 86 | h.adiciona_no(25) 87 | h.adiciona_no(7) 88 | h.adiciona_no(3) 89 | h.adiciona_no(100) 90 | h.adiciona_no(1) 91 | h.adiciona_no(2) 92 | h.adiciona_no(19) 93 | 94 | elementomax = h.remove_no() 95 | print(f'O elemento máximo é: {elementomax}') 96 | 97 | h.mostra_heap() 98 | 99 | print(f'Tamanho: {h.tamanho()}') 100 | 101 | print(f'Filho à esquerda de 17: {h.filho_esqueda(4)}') 102 | print(f'Filho à direita de 17: {h.filho_direita(4)}') -------------------------------------------------------------------------------- /HeapMin.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class HeapMin: 4 | 5 | def __init__(self): 6 | self.nos = 0 7 | self.heap = [] 8 | 9 | def adiciona_no(self, u): 10 | self.heap.append(u) 11 | self.nos += 1 12 | f = self.nos 13 | while True: 14 | if f == 1: 15 | break 16 | p = f // 2 17 | if self.heap[p-1] <= self.heap[f-1]: # >= HeapMax 18 | break 19 | else: 20 | self.heap[p-1], self.heap[f-1] = self.heap[f-1], self.heap[p-1] 21 | f = p 22 | 23 | def mostra_heap(self): 24 | #print(self.heap) 25 | print('A estrutura heap é a seguinte:') 26 | nivel = int(math.log(self.nos, 2)) 27 | a = 0 28 | for i in range(nivel): 29 | for j in range(2 ** i): 30 | print(f'{self.heap[a]}', end = ' ') 31 | a += 1 32 | print('') 33 | for i in range(self.nos - a): 34 | print(f'{self.heap[a]}', end = ' ') 35 | a += 1 36 | print('') 37 | 38 | def remove_no(self): 39 | x = self.heap[0] 40 | self.heap[0] = self.heap[self.nos - 1] 41 | self.heap.pop() 42 | self.nos -= 1 43 | p = 1 44 | while True: 45 | f = 2 * p 46 | if f > self.nos: 47 | break 48 | if f+1 <= self.nos: 49 | if self.heap[f] < self.heap[f-1]: # > se for HeapMax 50 | f += 1 51 | if self.heap[p-1] <= self.heap[f-1]: # >= se for HeapMax 52 | break 53 | else: 54 | self.heap[f-1], self.heap[p-1] = self.heap[p-1], self.heap[f-1] 55 | p = f 56 | return x 57 | 58 | def tamanho(self): 59 | return self.nos 60 | 61 | def menor_elemento(self): 62 | if self.nos != 0: 63 | return self.heap[0] 64 | return 'A árvore está vazia' 65 | 66 | def filho_esqueda(self, i): 67 | if self.nos >= 2*i: 68 | return self.heap[2*i - 1] 69 | return 'Esse nó não tem filho!' 70 | 71 | def filho_direita(self, i): 72 | if self.nos >= 2*i+1: 73 | return self.heap[2*i] 74 | return 'Esse nó não tem filho à direita!' 75 | 76 | def pai(self, i): 77 | return self.heap[i // 2] 78 | 79 | 80 | 81 | 82 | h = HeapMin() 83 | 84 | h.adiciona_no(17) 85 | h.adiciona_no(36) 86 | h.adiciona_no(25) 87 | h.adiciona_no(7) 88 | h.adiciona_no(3) 89 | h.adiciona_no(100) 90 | h.adiciona_no(1) 91 | h.adiciona_no(2) 92 | h.adiciona_no(19) 93 | 94 | elementomin = h.remove_no() 95 | print(f'O elemento minimo é: {elementomin}') 96 | 97 | h.mostra_heap() 98 | 99 | print(f'Tamanho: {h.tamanho()}') 100 | 101 | print(f'Filho à esquerda de 17: {h.filho_esqueda(5)}') 102 | print(f'Filho à direita de 17: {h.filho_direita(5)}') -------------------------------------------------------------------------------- /Dijkstra.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | class HeapMin: 5 | 6 | def __init__(self): 7 | self.nos = 0 8 | self.heap = [] 9 | 10 | def adiciona_no(self, u, indice): 11 | self.heap.append([u, indice]) 12 | self.nos += 1 13 | f = self.nos 14 | while True: 15 | if f == 1: 16 | break 17 | p = f // 2 18 | if self.heap[p-1][0] <= self.heap[f-1][0]: 19 | break 20 | else: 21 | self.heap[p-1], self.heap[f-1] = self.heap[f-1], self.heap[p-1] 22 | f = p 23 | 24 | def mostra_heap(self): 25 | print('A estrutura heap é a seguinte:') 26 | nivel = int(math.log(self.nos, 2)) 27 | a = 0 28 | for i in range(nivel): 29 | for j in range(2 ** i): 30 | print(f'{self.heap[a]}', end=' ') 31 | a += 1 32 | print('') 33 | for i in range(self.nos-a): 34 | print(f'{self.heap[a]}', end=' ') 35 | a += 1 36 | print('') 37 | 38 | def remove_no(self): 39 | x = self.heap[0] 40 | self.heap[0] = self.heap[self.nos - 1] 41 | self.heap.pop() 42 | self.nos -= 1 43 | p = 1 44 | while True: 45 | f = 2 * p 46 | if f > self.nos: 47 | break 48 | if f + 1 <= self.nos: 49 | if self.heap[f][0] < self.heap[f-1][0]: 50 | f += 1 51 | if self.heap[p-1][0] <= self.heap[f-1][0]: 52 | break 53 | else: 54 | self.heap[p-1], self.heap[f-1] = self.heap[f-1], self.heap[p-1] 55 | p = f 56 | return x 57 | 58 | def tamanho(self): 59 | return self.nos 60 | 61 | def menor_elemento(self): 62 | if self.nos != 0: 63 | return self.heap[0] 64 | return 'A árvore está vazia' 65 | 66 | def filho_esquerda(self, u): 67 | if self.nos >= 2*u: 68 | return self.heap[2*u-1] 69 | return 'Esse nó não tem filho' 70 | 71 | def filho_direita(self, u): 72 | if self.nos >= 2*u+1: 73 | return self.heap[2*u] 74 | return 'Esse nó não tem filho da direita' 75 | 76 | def pai(self, u): 77 | return self.heap[u // 2] 78 | 79 | 80 | class Grafo: 81 | 82 | def __init__(self, vertices): 83 | self.vertices = vertices 84 | self.grafo = [[0] * self.vertices for i in range(self.vertices)] 85 | 86 | def adiciona_aresta(self, u, v, peso): 87 | self.grafo[u-1][v-1] = peso 88 | self.grafo[v-1][u-1] = peso 89 | 90 | def mostra_matriz(self): 91 | print('A matriz de adjacências é:') 92 | for i in range(self.vertices): 93 | print(self.grafo[i]) 94 | 95 | def dijkstra(self, origem): 96 | custo_vem = [[-1, 0] for i in range(self.vertices)] 97 | custo_vem[origem - 1] = [0, origem] 98 | h = HeapMin() 99 | h.adiciona_no(0, origem) 100 | while h.tamanho() > 0: 101 | dist, v = h.remove_no() 102 | for i in range(self.vertices): 103 | if self.grafo[v-1][i] != 0: 104 | if custo_vem[i][0] == -1 or custo_vem[i][0] > dist + self.grafo[v-1][i]: 105 | custo_vem[i] = [dist + self.grafo[v-1][i], v] 106 | h.adiciona_no(dist + self.grafo[v-1][i], i+1) 107 | return custo_vem 108 | 109 | 110 | 111 | 112 | 113 | g = Grafo(7) 114 | 115 | g.adiciona_aresta(1, 2, 5) 116 | g.adiciona_aresta(1, 3, 6) 117 | g.adiciona_aresta(1, 4, 10) 118 | g.adiciona_aresta(2, 5, 13) 119 | g.adiciona_aresta(3, 4, 3) 120 | g.adiciona_aresta(3, 5, 11) 121 | g.adiciona_aresta(3, 6, 6) 122 | g.adiciona_aresta(4, 5, 6) 123 | g.adiciona_aresta(4, 6, 4) 124 | g.adiciona_aresta(5, 7, 3) 125 | g.adiciona_aresta(6, 7, 8) 126 | 127 | g.mostra_matriz() 128 | 129 | resultado_dijkstra = g.dijkstra(1) 130 | print(resultado_dijkstra) 131 | --------------------------------------------------------------------------------