terça-feira, 23 de abril de 2013

Exemplo de lista encadeada


Como exemplo para o conceito apresentado na postagem anterior (Lista Encadeada), segue um programa simples e completo que armazena nomes em ordem crescente, abaixo segue a declaração de como será o nó da lista a ser utilizada, junto do ponteiro que indica o inicio da lista:

typedef struct tagNode
      {
            char strName[80];
            struct tagNode *next;
      } sNode;

sNode *ptrStart;

Apesar de ser ideal utilizar funções como getnode e freenode, utilizando em separado rotinas de ordenação, é mais simples construir a lista de forma já ordenada, inserindo cada novo elemento na sequencia apropriada.

INSERIR

A função LListStore recebe o novo nó e o ponteiro com o inicio da lista, a primeira verificação, é para inicializar a lista caso está esteja vazia com o novo nó.

      if ( *pStart == NULL ) {
            *pStart = pNew;
            pNew->next = NULL;
      }

A próxima parte consiste em percorrer a lista comparando o nome do novo elemento, com o que está armazenado, temos um nó pInfo para a posição atual e outro nó pPrior para a posição anterior.  Enquanto pInfo apontar para um elemento valido, avança para o próximo nó.

      sNode *pInfo = *pStart;
      sNode *pPrior = NULL;

      while( pInfo )
      {
            if ( strcmp( pNew->strName, pInfo->strName ) > 0 )
            {
                  pPrior = pInfo;
                  pInfo = pInfo->next;
            }
      }

Para o caso aonde o novo elemento será o novo inicio da lista, significa que pPrior ainda é nulo, atualizamos o endereço seguinte do novo elemento e direciona-se o ponteiro pStart para o novo nó. 

      if ( pPrior == NULL) {
            pNew->next  = pInfo;
            *pStart = pNew;
      }

Se ponteiro pPrior não for nulo, significa inserção entre dois elementos, atualiza o endereço do ponteiro pPrior para o novo nó e novo nó aponta para o elemento atual da lista.

      if ( pPrior ) {
            pPrior->next = pNew;
            pNew->next  = pInfo;
      }

Ao terminar de percorrer toda lista sem ter encontrado uma posição, significa incluir no fim da lista, portanto o ponteiro anterior pPrior aponta para o novo nó e que passa indicar fim de lista com nulo no campo de endereço seguinte.

      pPrior->next = pNew;
      pNew->next = NULL;

EXCLUIR

Para o processo de exclusão a rotina LListDelete recebe o como entrada cuja ocorrência na lista deverá ser excluída, junto do inicio da lista, repetindo a forma de percorrer a lista como visto acima, as posições são controladas por pInfo para atual e pPrior para anterior. 

Sendo o nó pPrior nulo, significa excluir o primeiro elemento, basta atualizar o ponteiro pStart que indica o inicio da fila para o seguinte.

      if ( pPrior == NULL )
            *pStart = pInfo->next;

Para as demais situações do processo de exclusão, basta copiar o valor do endereço do próximo nó do elemento a ser excluído para o nó anterior.

      if ( pPrior )
            pPrior->next = pInfo->next;

Copiar o valor de next simplifica o processo, pois o mesmo já está inicializado com o valor do próximo nó ou indicação de nulo.

Observe que a busca do nó deveria ser feito em separado da rotina para excluir o nó, entretanto por se tratar de uma lista singularmente encadeada, o processo de exclusão necessita do endereço do nó a ser excluído, junto do nó anterior, o que aumentaria também a complexidade do processo de busca do que deveria ser um simples exemplo, a modularidade desejada será atendida quando for apresentado o conceito de lista duplamente encadeada que irá incorporar o endereço anterior à estrutura do nó.

Os processos para alocar e liberar a memória usada na lista foi realizado fora de LListStore e LListDelete para manter as mesmas compactas e enfatizar somente o processo de controle de apontamento, as rotinas responsáveis por isto são Insert e Delete, fazem parte do menu com as opções de operação em lista, o programa completo segue abaixo.

A execução resulta na seguinte tela, aonde se pode escolher a ação digitando o numero entre parênteses.

Inserir  ( 1 )
Apagar   ( 2 )
Listar   ( 3 )
Sair     ( 0 )

Escolha umas das alternativas anteriores :

Após selecionar  ‘1’ para iniciar a entrada de nome para a lista e realizar a inclusão dos nomes, o usuário deve confirmar o campo nome estando vazio,  para encerrar o processo de inserir.

Escolha umas das alternativas anteriores : 1
Digite o nome : roberto
Digite o nome : vanusa
Digite o nome : mariana
Digite o nome : laura
Digite o nome : bianca
Digite o nome :


Inserir  ( 1 )
Apagar   ( 2 )
Listar   ( 3 )
Sair     ( 0 )

Escolha umas das alternativas anteriores :

Digite ‘2’ para selecionar a opção de apagar um nome na lista, após a entrada do nome, o item será excluído caso seja encontrado, do contrario, informa que não foi possível encontrar o item.

Escolha umas das alternativas anteriores : 2


Digite o nome que deseja excluir da lista : mariana

Item removido



Inserir  ( 1 )
Apagar   ( 2 )
Listar   ( 3 )
Sair     ( 0 )

Escolha umas das alternativas anteriores : 2


Digite o nome que deseja excluir da lista : mari

Nao encontrado

A terceira opção de listar os nomes, apresenta os nomes em ordem crescente junto das informações de endereço na memória, como o endereço do nó, mais o ponteiro para o próximo nó.

Name : bianca
         Address :      004F1458
         Next :         004F13D8
Name : laura
         Address :      004F13D8
         Next :         004F1258
Name : roberto
         Address :      004F1258
         Next :         004F12D8
Name : vanusa
         Address :      004F12D8
         Next :         00000000

terça-feira, 16 de abril de 2013

Lista Encadeada


Ao utilizar vetores e pilhas até o momento, tem-se feito uso de armazenamento sequencial, cuja principal desvantagem é quantidade fixa que se reserva para seu uso, ao delimitar sua área permite-se a possibilidade de estouro, ou manter ocupado todo um bloco de memória quando em alguns momentos pode estar usando uma quantidade menor ou mesmo nenhum dado.

                Numa representação sequencial temos um item q[x] e implicitamente sabemos que o próximo elemento será q[x+1], para tornar explicita essa relação, o item irá ter dois campos, primeiro com a informação e o segundo com o endereço para o item seguinte, assim temos a estrutura de dados conhecida como lista encadeada, aonde cada item será chamada de nó.

                Com nó tendo um campo informação com o real elemento da lista e o campo endereço contendo um ponteiro para o próximo elemento, a lista encadeada é acessada a partir de um ponteiro externo (não incluído dentro do nó) lista que aponta para o primeiro nó da lista, o campo endereço para o ultimo nó irá ter o valor nulo, sendo invalido e indicando o final de uma lista.



info
next

info
next

info
next

info
next
lista













>


>


>


>

nulo
































Por ser tratar de uma estrutura de dados dinâmica, o numero de nós na lista pode variar consideravelmente à medida que são inseridos e removidos. Basicamente existem duas maneiras de construir uma lista encadeada. A primeira consiste em adicionar o novo item sempre no inicio ou fim da lista. A outra é acrescentar itens em posições especificas da lista, podendo seguir a ordem crescente por exemplo.

A forma de armazenar os dados da lista dependerá do aplicativo, com três situações que podem ocorrer quando se insere um item na lista encadeada, como reflexo da inserção, quando se remove um item na lista encadeada, as três sequencias de operação se invertem:

                INSERIR

1.        Item pode se tornar o primeiro da lista;


info
next








































info
next

Info
next






lista













>


>

nulo
















·         Novo item copia o endereço de próximo que está em Lista.
·         Lista aponta para o novo item.


info
next











lista















>


>

















info
next

info
next



























>

nulo



















2.       Inserir entre dois outros itens;







info
next












































info
next








Info
next



lista

















>


>








nulo




















·         Novo item copia o endereço de próximo que está no item anterior.
·         Item anterior atualiza o endereço para o novo item.







info
next


































>









info
next








info
next



lista

















>


>








nulo





















3.       Ser o ultimo item da lista;


info
next

Info
next

info
next



lista













>


>

nulo



















·         Troca o Nulo pelo endereço do novo item no ultimo item da lista.
·         Indicar Nulo para o endereço de próximo no novo item.


info
next

info
next

info
next



lista













>


>


>

nulo


















EXCLUIR

1.       Excluir o primeiro da lista


info
next

Info
next

info
next



lista













>


>


>

nulo
















·         Copia o endereço de próximo no primeiro item para lista





Info
next

info
next



lista













>





>

nulo

















2.       Elimina numa posição intermediaria


info
next

Info
next

info
next



lista













>


>


>

nulo
















·         Copia no item anterior ao que vai ser excluído o endereço de próximo.


info
next




info
next



lista













>


>




nulo

















3.       Excluir o ultimo item


info
next

info
next

info
next



lista













>


>


>

nulo
















·         Troca o endereço que aponta para o item a ser excluído por nulo


info
next

info
next






lista













>


>

nulo





















Um modelo simples e didático de código em linguagem C para uma lista encadeada está incluído na próxima postagem “Exemplo de lista encadeada” e serve como complemento prático mostrando a programação completa das rotinas para inserir, excluir e percorrer.