Se estivermos buscando um elemento x em uma lista encadeada, podemos ter algo similar a:
while (p <> nil) and (p^.info <> x) do p := p^.lig;
Que problema temos no comando acima ?
No caso de p = nil o comando pode ser inválido pois p^.info não existe!
OBS.: Se o compilador não realiza o segundo teste no caso do primeiro falhar, não haveria problema. Em nível de algoritmo, é melhor resolver o problema evitando a possibilidade desse tipo de erro ocorrer, ao invés de usar soluções que dependem do compilador.
O que fizemos nos nossos algoritmos foi algo similar a:
acabou := false; While (p <> nil) and (not acabou) do If p^. info = x Then acabou := true Else p := p^.lig;
Um elemento sentinela pode ser utilizado na busca em lista linear encadeada: usamos para isso um registro no final da lista.
Supondo que inicializamos uma lista apontada por L com a lista vazia, faremos:
Procedure Create(L: Lista); Var sentinela: Lista; Begin new(sentinela); L := sentinela; End;
O algoritmo seguinte implementa uma busca por um elemento x na lista apontada por L não ordenada. Retorna p = nil se o elemento não for encontrado; caso contrário p aponta o registro que contém o elemento.
Procedure busca(x: T; var L, p: Lista); var p: Lista; Begin p := L; sentinela^.info := x; While p^.info <> x do p := p^.lig; If (p = sentinela) Then p := nil; {elemento não encontrado} End;
Caso o elemento não seja encontrado e quisermos inseri-lo no final da lista, teremos o procedimento abaixo:
Procedure busca_insere(x: T; Var L, p: Lista); var p: Lista; Begin p := L; sentinela^.info := x; While p^.info <> x do p := p^.lig; If (p = sentinela) Then Begin { inserção no começo da lista} p := L; {aponta primeiro} new(L); {novo registro é primeiro} L^.info := x; L^.lig := p; End; End;
No algoritmo acima, ao realizar uma busca sequencial numa lista encadeada anulamos a vantagem de utilizar listas encadeadas. Neste caso, esta implementação só pode ser considerada para listas com um número pequeno de elementos.
No caso da lista estar ordenada, a busca termina assim que encontrarmos um elemento maior que aquele que buscamos. A ordenação é obtida ao inserirmos cada novo elemento na sua posição correta, ao invés de na cabeça da lista.
Essa "ordenação" na realidade não tem custo algum, porque fazemos uso das características da lista encadeada. Isso não ocorre com estruturas estáticas como o array e os arquivos sequenciais.
O procedimento abaixo elimina um registro que contém o elemento v de uma lista apontada por L.
O bloco de busca pelo elemento realiza dois testes para cada elemento da lista. Esse esforço pode ser reduzido introduzindo o recurso de sentinela.
Depois da busca, testes devem ser efetuados para verificar se:
Procedure elimina(v: integer; Var Prim: Lista); Var p, pa: Lista; acabou: boolean; Begin pa := nil; p := L; acabou := (p = nil); While (not acabou) do If p^.info < v Then Begin pa := p; p := p^.lig; acabou := (p = nil); End Else acabou := true; { p = nil ou p^.info = v ou p^.info > v } If (p = nil) Then "lista não contém v" Else If p^.info > v Then "lista não contém v" Else Begin If pa = nil Then L := p^.lig Else pa^.lig := p^.lig; dispose(p); End; End;
Dada a seguinte inicialização:
new(root); new(sentinel); root^.lig := sentinel;
Temos acima um lista com dois elementos: o elemento apontado por root vai ser sempre um dummy (elemento sem conteúdo), e o sentinela sempre marca o final da lista.
O algoritmo abaixo realiza a busca de um elemento e o insere na posição correta caso ele não seja encontrado.
Procedure busca_insere(x: T; Var root: Lista); Var w1, w2, w3: Lista; Begin w2 := root; w1 := w2^.lig; sentinel^.info := x; While w1^.info < x do Begin w2 := w1; w1 := w1^.lig; End; If (w1^.info = x) and (w1 <> sentinel) Then {elemento já existe} Else Begin new(w3); {insere w3 entre w1 e w2} w3^.info := x; w3^.lig := w1; w2^.lig := w3; End; End;