This repository has been archived by the owner on Aug 26, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathListaSimples.py
337 lines (308 loc) · 12.4 KB
/
ListaSimples.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
# -*- coding: utf-8 -*-
"""
Universidade Federal de Pernambuco (UFPE) (http://www.ufpe.br)
Centro de Informática (CIn) (http://www.cin.ufpe.br)
Bacharelado em Sistemas de Informacao
IF 969 - Algoritmos e Estruturas de Dados
Author: Antônio Paulino de Lima Neto (apln2)
Email: apln2@cin.ufpe.br
Created on Tue Jul 10 22:18:48 2018
Descricao: Código da classe de listas simples. Também contém o código da classe
auxiliar de nós, usados na construção da lista.
Licenca: The MIT License (MIT)
Copyright(c) 2018 Antônio Paulino de Lima Neto
"""
#------------------------------------------------------------------------------
# Demonstração gráfica simples de uma lista de encadeamento simples de tamanho
# n, onde os números entre colchetes representam os índices de cada nó
#
# Primeiro
# |
# \/
# [Cabeça] -> [0] -> [1] -> ... -> [n-1] -> None
# /\
# |
# Último
#
#------------------------------------------------------------------------------
class _No():
'''
Classe auxiliar nó. Guarda um valor e uma referência para o próximo nó da
lista. Quando não há um próximo nó, a referência é None.
item: objeto ou valor a ser guardado no nó
prox: referência para o próximo nó
'''
def __init__(self, item = None, prox = None):
self.item = item
self.prox = prox
def __repr__(self):
return "_No({})".format(self.item.__repr__())
def __str__(self):
return self.item.__str__()
class Lista():
'''
Classe principal de Lista simplesmente encadeada. Os nós dessa lista
pertencem a classe _No. Esses nós guardam referências para o nó sucessor,
caso ele exista, ou para None, caso não haja nó sucessor.
'''
def __init__(self, iteravel = None):
'''
Método construtor da Lista.
Esse é o método que será chamado no momento em que um objeto do tipo
Lista for instanciado. Logo, são os parâmetros desse método que
determinam quais parâmetros são necessários a construção do objeto.
No caso desse método em espeífico, ele pode ser construído a partir de
um outro iterável (como uma tupla, dicionário, lista ou string) ou pode
ser construído como uma lista vazia.
'''
self.primeiro = self.ultimo = _No()
if not iteravel is None:
for obj in iteravel:
self.anexar(obj)
def anexar(self, item):
'''
Método insere um item na última posição da lista.
'''
self.ultimo.prox = _No(item)
self.ultimo = self.ultimo.prox
def inserir(self, index, item):
'''
Método usado para inserir um item numa posição específica da lista,
colocando todos os itens subsequentes uma posição para a direita.
Caso o indice dado seja maior que o indíce do último elemento da lista,
o item é inserido na última posição.
'''
atual = self.primeiro
cont = 0
while cont < index and atual.prox is not None:
atual = atual.prox
cont += 1
atual.prox = _No(item, atual.prox)
# A próxima linha verifica se o novo nó foi inserido na última posição
# da lista
if atual.prox.prox is None:
self.ultimo = atual.prox
def modificar(self, index, item):
'''
Método usado para modificar valor de um nó existente na lista.
Caso o nó não exista na lista, o método levanta uma exceção IndexError.
'''
if self.primeiro == self.ultimo:
raise IndexError ("lista vazia")
atual = self.primeiro
cont = -1
while cont < index:
if atual.prox is None:
raise IndexError ("índice fora de alcance")
else:
atual = atual.prox
cont += 1
atual.item = item
def buscar(self, index):
'''
Método usado para acessar um elemento da lista através de seu índice.
Caso o índice não pertença a lista, uma exceção IndexError é levantada.
Esse método faz a busca da esquerda para a direita (indice >= 0)
'''
atual = self.primeiro
cont = -1
while cont < index:
if atual.prox is None:
raise IndexError ("índice fora de alcance")
else:
atual = atual.prox
cont += 1
return atual.item
def indice(self, item, inicio = None, fim = None):
'''
Método usado para encontrar o índice dado um elemento da lista. Esse
método retorna o índice da primeira posição em que o elemento aparece,
caso ele apareça mais de uma vez na mesma lista.
É possível limitar a busca a um determinado intervalo da lista
informando os parametros inicio e fim.
Caso o item não pertença a lista, uma exceção ValueError é levantada.
'''
if inicio is not None and not isinstance(inicio, int):
raise ValueError ("inicio deve ser um número inteiro")
elif fim is not None and not isinstance(fim, int):
raise ValueError ("fim deve ser um número inteiro")
else:
if inicio is None:
inicio = 0
if fim is None:
fim = float('inf')
atual = self.primeiro
cont = 0
while atual.prox is not None:
if atual.prox.item == item and (cont >= inicio and cont <= fim):
return cont
else:
atual = atual.prox
cont += 1
raise ValueError ("{} não pertencem a lista".format(repr(item)))
def retirar(self, index = 0):
'''
Método usado para remover um nó da lista e recuperar o valor que o nó
guardava.
Equivalente ao método .pop das listas nativas de Python.
'''
# Se a lista estiver vazia o método levanta uma exceção IndexError
if self.primeiro == self.ultimo:
raise IndexError ("não é possível retirar valores de lista vazia")
atual = self.primeiro
cont = 0
while cont < index:
if atual.prox is None:
raise IndexError("índice fora de alcance")
else:
atual = atual.prox
cont += 1
aux = atual.prox
atual.prox = aux.prox
aux.prox = None
# Se o nó que estiver para ser deletado for o último, o último então
# passa a ser o nó anterior a ele
if self.ultimo == aux:
self.ultimo = atual
valor = aux.item
del aux
return valor
def remover(self, item):
'''
Método usaod para remover um determinado nó que contenha um item
específico.
Caso não o item informado não esteja na lista, o método levanta uma
exceção ValueError.
'''
# Se a lista estiver vazia o método levanta uma exceção ValueError
if self.primeiro == self.ultimo:
raise ValueError ("não é possível remover itens de uma lista vazia")
anterior = self.primeiro
atual = anterior.prox
while not atual is None and atual.item != item:
anterior = atual
atual = anterior.prox
if atual is None:
raise ValueError("{} não pertence a lista".format(repr(item)))
else:
anterior.prox = atual.prox
atual.prox = None
if self.ultimo == atual:
self.ultimo = anterior
del atual
# Adiante estão os métodos especiais (magic operators) de Python.
# Note que alguns deles apenas chamam funções criadas anteriormente
def __contains__(self, item):
'''
Método usado para verificar se um determinado item pertence ou não a
lista.
Esse é o método utilizado quando o operador in é chamado. Deve retornar
True caso o objeto pertença a lista e False caso contrário.
'''
if self.primeiro == self.ultimo:
return False
atual = self.primeiro.prox
while atual is not None:
if atual.item == item:
return True
else:
atual = atual.prox
return False
def __delitem__(self, index):
'''
Essa função é chamada sempre que o usuário tentar deletar um item da
Lista usando a keyword del.
Por exemplo del lista[0].
Essa função funciona quase da mesma maneira que a função retirar (pop),
com a diferença de que nenhum valor precisa ser retornado.
'''
if self.primeiro == self.ultimo:
raise IndexError ("não é possível retirar valores de lista vazia")
atual = self.primeiro
cont = 0
while cont < index:
if atual.prox is None:
raise IndexError("índice fora de alcance")
else:
atual = atual.prox
cont += 1
aux = atual.prox
atual.prox = aux.prox
aux.prox = None
if self.ultimo == aux:
self.ultimo = atual
del aux
def __len__(self):
'''
Esse é o método que retorna o tamanho de uma lista.
Nessa implementação em específico, o método conta quantos nós fazem
parte da lista.
'''
no = self.primeiro.prox
cont = 0
while no is not None:
cont += 1
no = no.prox
return cont
def __str__(self):
'''
Método de conversão do objeto para string. Esse é o método chamado, por
exemplo, quando se usa a função print(obj)
'''
string = ''
anterior = self.primeiro
atual = anterior.prox
while not atual is None:
string += atual.item.__repr__()
if atual.prox is not None:
string += ', '
anterior = atual
atual = anterior.prox
return "[{}]".format(string)
def __repr__(self):
'''
Método usado para se obter uma representação válida de um objeto. Esse
é o método chamado quando, por exemplo, você digita o nome de um objeto
ou variável no console e recebe como output uma string contendo uma
representação do valor do objeto.
'''
return "Lista({0})".format(self.__str__())
def __getitem__(self, i):
'''
Método usado para se obter um objeto através do acesso direto por
índice. Por exemplo:
Em uma lista com o seguinte valor: ['abc', 123, True, inf], o
método __getitem__ permite se obter os valores dos elementos a
partir de seus índices.
In: lista[0]
Out: 'abc'
In: lista[1]
Out: 123
...e assim sucessivamente....
'''
return self.buscar(i)
def __setitem__(self, index, item):
'''
Esse método funciona de forma similar ao método __getitem__, mas ao
invés de retornar o valor desejado, ele muda o valor do elemento na
posição específicada.
'''
self.modificar(index, item)
def __iter__(self):
'''
Método usado para retornar um iterador (objeto do tipo iter) do objeto.
Esse método permite a iteração através do for.
'''
self.__atual = self.primeiro.prox
return self
def __next__(self):
'''
Define o comportamento do iterador do objeto.
O fim da iteração é marcado com o levantamento da exceção StopIteration
'''
if self.__atual is None:
raise StopIteration
else:
item = self.__atual.item
self.__atual = self.__atual.prox
return item