Estou tentando entender a complexidade de tempo de uma fila implementada com uma estrutura de dados de lista vinculada. Meu livro diz que podemos implementar uma fila no tempo O (1):
- enfileiramento na parte de trás
- desenfileiramento na cabeça
e também diz
Observe que, embora adicionar um elemento à cauda seja tempo constante, remover um elemento da cauda é O (n), pois precisamos encontrar a nova cauda
Eu sei que adicionar um novo nó à minha fila na cabeça (enfileirar) leva O (1), pois tenho o ponteiro da cabeça. Da mesma forma, a remoção de um nó na cabeça (desenfileirar) também levará O (1). Mas não entendo por que adicionar um elemento na parte de trás (enfileirar) leva O (1), enquanto removê-lo (desenfileirar) leva O (n). Faria mais sentido para mim se enfileirar na parte de trás pegasse O (n) em vez de O (1), pois em ambos os casos (adicionar / remover na parte de trás) precisaria encontrar o ponteiro da cauda e, portanto, atravessaria a lista inteira.
Respostas:
Enfileiramento
Você não precisa percorrer a lista inteira para encontrar a nova cauda, basta adicionar um novo nó para onde a cauda atual aponta e definir esse nó como a nova cauda.
Pseudocódigo (assumindo que
head != null
etail != null
):A partir do qual podemos concluir que a complexidade do tempo é .O ( 1 )
Retirar da fila
Para desenfileirar, precisamos apenas definir o próximo nó da cabeça atual como a nova cabeça e retornar o valor da cabeça antiga.
Nota : Não esqueça que se o novo cabeçote estiver definido como
null
, a cauda também deverá estar definidanull
:Pseudocódigo (assumindo que
head != null
etail != null
):Todas essas operações possuem complexidade de tempo , o que torna a complexidade de tempo da função de desenfileiramento também.O ( 1 ) O ( 1 )
Procurando
A busca de um valor é feita percorrendo todos os itens, começando pela cabeça. No pior cenário, você precisaria atravessar a fila inteira, o que torna a complexidade do pior caso .O ( n )
Por exemplo, se você deseja remover a cauda, a complexidade do tempo seria . Isso ocorre porque você precisaria encontrar a nova cauda para a fila e, como a cauda não tem acesso ao elemento anterior em uma lista vinculada individualmente, seria necessário procurar a nova cauda na fila inteira.O ( n )
Pseudocódigo (assumindo que
head != null
etail != null
):A partir do qual se pode observar que a complexidade do tempo é de fato .O ( n )
fonte
O comentário no livro aparentemente pressupõe que a implementação da lista vinculada mantém dois ponteiros,
head
que apontam para o primeiro nó da lista elast
que apontam para o último nó.Com esse design, anexar à lista é simplesmente:
Mas remover o último nó requer encontrar o segundo ao último nó, para que você possa limpar seu
next
link e alterar olast
ponteiro para apontar para ele. Isso requer a varredura da lista para encontrar o nó em quenode.next == list.last
.É possível que você também tenha um
list.secondToLast
ponteiro, mas isso não resolve o problema, porque quando você remove o último nó, é necessário alterá-lo para apontar para o terceiro para o último nó anterior, e esse problema se repete na lista inteira.fonte