Sie sind auf Seite 1von 26

LISTAS LINEARES

Introdução

Neste capítulo iremos discutir alguns aspectos de listas e como podemos implementar esta
estrutura de dados em C.

Listas

Listas - Definições Básicas

Uma lista linear de informações é uma estrutura de dados simples que armazena
informações sobre dados que apresentam uma relação entre seus elementos.

As operações mais freqüentes em listas são a busca, inserção e remoção de um determinado


elemento. Outras operações que costumam ocorrer são a alteração de um elemento particular da
lista, ordenação dos elementos da lista segundo uma determinada chave, procura do último ou do
primeiro elemento da lista, etc.

Os elementos da lista podem ser armazenados em posições contíguas da memória e neste


caso temos uma lista seqüencial. Podemos também armazenar os elementos em posições quaisquer
da memória e neste caso temos de armazenar em cada elemento um indicador de onde está o
próximo elemento da lista. Este último método é conhecido como alocação encadeada.

Listas com Alocação Seqüencial

A maneira mais simples de se manter uma lista na memória do computador é colocar seus
nós em posições contíguas. Neste caso o elemento j+c estará c bytes (ou palavras, depende do
sistema) à frente do elemento j da lista. A constante c corresponde ao número de bytes (ou palavras)
necessário para armazenar cada elemento da lista. Cada elemento da lista é comumente chamado de
nó. Um nó da lista pode conter vários tipos de informações que são armazenados em campos. Cada
nó contém um (ou mais) elemento(s) que identificam unicamente o nó, a chave. Uma lista pode
estar ordenada ou não de acordo com a chave.

A seguir, temos dois exemplos de implementações de listas lineares

#include <stdlib.h>
#include <stdio.h>

int *PtrIni = 0;
int *PtrFim = 0;
int tam = 0;

void insereInilst(int *vetor, int valor);


void insereFimlst(int *vetor, int valor);
void inserePoslst(int *vetor, int valor, int pos);
int retiraIniLst(int *vetor);
int retiraFimLst(int *vetor);

int main(){
int vetor[10], valor, pos, retiraini, retirafim, i;

for (i=0; i<10; i++) vetor[i]=0;

valor=10;

insereInilst(vetor, valor);

printf("\n\ninsercao no inicio da lista\n\n");


for (i=0; i<10; i++){
printf("\nvalor armz no item vetor[ %d ] = %d\n",i, vetor[i]);
}

printf("\ntamanho da lista: %d\n", tam);


system("pause");

valor=11;

insereInilst(vetor, valor);

printf("\n\ninsercao no inicio da lista\n\n");


for (i=0; i<10; i++){
printf("\nvalor armz no item vetor[ %d ] = %d\n",i, vetor[i]);
}

printf("\n%d\t%d\n\n", vetor[0], vetor[1]);

printf("\ntamanho da lista: %d\n", tam);


system("pause");

valor=12;
insereFimlst(vetor,valor);

printf("\n\ninsercao no final da lista\n\n");


for (i=0; i<10; i++){
printf("\nvalor armz no item vetor[ %d ] = %d\n",i, vetor[i]);
}

printf("\n%d\t%d\t%d\t\n", vetor[0], vetor[1], vetor[2]);


printf("\ntamanho da lista: %d\n", tam);
system("pause");

valor=13;
pos = 2;
inserePoslst(vetor,valor,pos);

printf("\n\ninsercao em uma posicao da lista\n\n");


for (i=0; i<10; i++){
printf("\nvalor armz no item vetor[ %d ] = %d\n",i, vetor[i]);
}
printf("\n%d\t%d\t%d\t%d\t", vetor[0], vetor[1], vetor[2], vetor[3]);
printf("\ntamanho da lista: %d\n", tam);
system("pause");

retiraini=retiraIniLst(vetor);
printf("\n\nretirada do inicio da lista\n\n");
for (i=0; i<10; i++){
printf("\nvalor armz no item vetor[ %d ] = %d\n",i, vetor[i]);
}

printf("\nvalor retirado do inicio foi %d\n ", retiraini);

printf("\n%d\t%d\t%d\t\n\n", vetor[0], vetor[1], vetor[2]);

printf("\ntamanho da lista: %d\n", tam);

system("pause");

valor=20;

insereInilst(vetor, valor);

printf("\n\ninsercao no inicio da lista\n\n");


for (i=0; i<10; i++){
printf("\nvalor armz no item vetor[ %d ] = %d\n",i, vetor[i]);
}

printf("\n%d\t%d\t%d\t%d\t\n", vetor[0], vetor[1], vetor[2], vetor[3]);

printf("\ntamanho da lista: %d\n", tam);

system("pause");

retirafim=retiraFimLst(vetor);
printf("\n\nretirada do fim da lista\n\n");
for (i=0; i<10; i++){
printf("\nvalor armz no item vetor[ %d ] = %d\n",i, vetor[i]);
}

printf("\nvalor retirado do final da lista foi %d\n ", retirafim);

printf("\n%d\t%d\t%d\t\n\n", vetor[0], vetor[1], vetor[2], vetor[3]);

printf("\ntamanho da lista: %d\n", tam);

system("pause");

}
void insereInilst(int *vetor, int valor){

int *PtrTrb, *PtrAux;

if (tam <= 10) {


if (PtrIni==0) {
PtrIni = &vetor[0];
PtrFim = &vetor[0];
}
else {
PtrAux = &vetor[0];
PtrTrb = PtrFim+1;
while (PtrTrb >= PtrAux) {
*PtrTrb = *(PtrTrb - 1);
PtrTrb = PtrTrb -1;
}
PtrFim++;
}

*PtrIni = valor;
tam++;
}
else {
printf("Limite de memoria alcancado - overflow\n");
}
}

int retiraIniLst(int *vetor) {

int *PtrTrb, retirado;


PtrTrb = PtrIni;
retirado = *PtrIni;

if (PtrIni==PtrFim) {
PtrIni=0;
PtrFim=0;
}
else {
while (PtrTrb!=PtrFim) {
*PtrTrb = *(PtrTrb+1);
PtrTrb++;
}
PtrFim=PtrFim - 1;
}
tam--;
return retirado;
}

void inserePoslst(int *vetor, int valor, int pos){


int *PtrTrb=0;
int *PtrAux;

PtrTrb=PtrFim;

if (pos>tam){
exit(1);
}
else {
PtrAux = &vetor[pos-1];
while (PtrTrb >= PtrAux) {
*(PtrTrb+1) = *PtrTrb;
PtrTrb = PtrTrb -1;
}
PtrFim = PtrFim + 1;
}
*PtrAux = valor;
tam++;
}

int retiraPosLst(int *vetor, int pos){

int *PtrTrb, *PtrAux, retirado;


PtrTrb = &vetor[pos];
PtrAux = PtrFim;

if (pos > tam) {


exit(1);
}
else {
retirado = vetor[pos];
while (PtrTrb<=PtrAux){
*PtrTrb = *(PtrTrb+1);
PtrTrb = PtrTrb + 1;
}
PtrFim--;
tam--;
}

void insereFimlst(int *vetor, int valor){

if (PtrIni==0) {
PtrIni = &vetor[0];
PtrFim = &vetor[0];
}
else {
PtrFim = PtrFim + 1;
}
*PtrFim = valor;
tam++;
}

int retiraFimLst(int *vetor){

int retirado;
retirado = *PtrFim;
if (PtrIni==PtrFim){
PtrIni = 0;
PtrFim = 0;}
else {
PtrFim--;
}
tam--;
return retirado;
}

O programa mostra um exemplo de busca em uma lista seqüencial. O algoritmo, contido na


função busca1, é simples e percorre a lista toda até encontrar o elemento. A função recebe a lista e o
elemento a ser procurado. Note que o número de elementos na lista n é conhecido pelo algoritmo.

/* list01.c */
#include <stdio.h>
#define MAX 4

struct Taluno {
char nome[40];
unsigned long int dre;
};

int busca1 ( struct Taluno t[], unsigned long int );


void le ( struct Taluno t[]);
void imprime ( struct Taluno t[]);

void main ()
{
int aluno;
unsigned long dre;
char linha[80];
struct Taluno turma[MAX];

le (turma); /* le dados da turma de MAX alunos */


imprime (turma); /* imprime dados para verificar se correto */
/* uso sscanf, mais seguro que scanf */
puts("Qual o DRE a procurar? "); gets(linha);
sscanf(linha, "%lu", &dre);

aluno = busca1 (turma, dre);


if (aluno == -1)
puts("Nao ha aluno com este dre.");
else
printf("O aluno com dre %lu chama-se %s\n",
turma[aluno].dre, turma[aluno].nome);

exit(0);
}

void le (struct Taluno t[]) {


int i;
char linha[80];

for (i=0; i<MAX; i++) {


puts("Nome ? "); gets (t[i].nome);
puts("DRE ? "); gets(linha);
sscanf(linha, "%lu", &t[i].dre);
}
}

void imprime (struct Taluno t[]) {


int i;

puts("Dados da turma");
for (i=0; i<MAX; i++) {
printf("\nAluno %d\n", i);
printf("Nome = %s\n", t[i].nome);
printf("Nome = %lu\n", t[i].dre);
}
}

/* Busca um elemento na lista L */


int busca1 (struct Taluno turma[], unsigned long int dre) {
int i=0; int aluno=-1;

/* vou assumir que a lista contem MAX alunos */


while (i < MAX) {
if ( turma[i].dre == dre) {
aluno = i;
i=MAX;
}
else i++;
}
return aluno; /* se -1 nao achei, senao indice do aluno */
}

No exemplo anterior são feitas duas comparações a cada interação ( i < MAX e turma[i].dre
== dre). Para diminuir o número de comparações vamos usar um artifício simples: colocar uma
posição extra no final da lista e sempre que for necessário buscar um elemento na lista, o seu valor
será inserido nesta posição extra. Deste modo sempre acharemos o elemento na lista. No entanto, se
o elemento estiver no final da lista significa que o elemento não foi encontrado. Observar que a lista
passa ter agora uma posição a mais, que é reservada para o elemento a ser procurado.

O programa list02.c mostra um exemplo de busca em uma lista seqüencial com uma posição a mais.
/* programa list02.c */
#include <stdio.h>

/* A lista cabem 4 elementos o elemento 5


e para a elemento a ser procurado
*/
#define MAX 5

struct Taluno {
char nome[40];
unsigned long int dre;
};

int busca1 ( struct Taluno t[], unsigned long int );


void le ( struct Taluno t[]);
void imprime ( struct Taluno t[]);

void main ()
{
int aluno;
unsigned long dre;
char linha[80];
struct Taluno turma[MAX];

le (turma);
imprime (turma);
puts("Qual o DRE a procurar? "); gets(linha);
sscanf(linha, "%lu", &dre);
aluno = busca1 (turma, dre);
if (aluno == -1)
puts("Nao ha aluno com este dre.");
else
printf("O aluno com dre %lu chama-se %s\n",
turma[aluno].dre, turma[aluno].nome);
exit(0);

void le (struct Taluno t[]) {


int i;
char linha[80];

for (i=0; i<MAX-1; i++) {


puts("Nome ? "); gets (t[i].nome);
puts("DRE ? "); gets(linha);
sscanf(linha, "%lu", &t[i].dre);
}
}

void imprime (struct Taluno t[]) {


int i;
puts("Dados da turma");
for (i=0; i<MAX-1; i++) {
printf("\nAluno %d\n", i);
printf("Nome = %s\n", t[i].nome);
printf("Nome = %lu\n", t[i].dre);
}
}

/* Busca um elemento na lista L */


int busca1 (struct Taluno turma[], unsigned long int dre) {
int i=0;

turma[MAX-1].dre=dre;
while (turma[i].dre != dre) i++;
if (i != MAX-1 ) return i;
else return -1;
}

Os exemplos anteriores assumiam dois fatos a cerca da lista: a lista está cheia e desordenada.
Quando a lista está ordenada a procura pode ser interrompida antes de chegar ao fim da lista. Neste
algoritmo ao invés de procurar o elemento, o teste é se o elemento da lista é menor que o procurado.

O programa list03.c mostra um exemplo de busca em uma lista ordenada. Para facilitar
vamos mostrar apenas a rotina busca_ord que executa este algoritmo, já que todo o restante do
programa é similar ao anterior. No arquivo indicado na ligação mostramos o arquivo todo.

/* programa list03.c */

/* Busca um elemento na lista L */


int busca_ord ( Taluno turma[], unsigned long int dre) {
int i=0;

turma[MAX-1].dre=dre;
while (turma[i].dre < dre) i++;
if (i == (MAX-1) || turma[i].dre != dre ) return -1; /* nao achei. */
else return i;
}

Um algoritmo mais eficiente para busca em uma lista ordenada é o algoritmo de busca
binária. Primeiro o algoritmo procura o elemento no elemento do meio da tabela. Caso não esteja
ele descarta a metade onde o elemento não está e passa a procurar no meio da metade que sobrou. O
algoritmo vai dividindo a lista em duas metades, sempre descartando a metade onde o elemento não
está.

O programa list04.c mostra um exemplo de busca binária em uma lista ordenada. Para
facilitar vamos mostrar somente a rotina busca_bin que implementa este algoritmo.
/* programa list04.c */
/* Busca um elemento na lista L */
int busca_bin ( Taluno t[], unsigned long int dre) {
int inf=0, sup=MAX-1, achou=-1, meio;

while (inf <= sup)


{
meio = 1/2*(inf+sup);
if (t[meio].dre == dre)
{
achou=meio;
inf = sup+1;
}
else if (t[meio].dre<dre)
inf = meio+1;
else sup = meio - 1 ;
}
return achou;
}

Agora passaremos a apresentar algoritmos para inserir e remover elementos de uma lista.
Ambos os algoritmos utilizam a rotina de busca para inserir e remover.

Primeiro vamos apresentar um algoritmo de inserção que não precisa que a lista esteja
ordenada. Neste algoritmo, o elemento, caso ele não já esteja na lista, é inserido após o último
elemento. O algoritmo de remoção move, a partir do último elemento até o elemento seguinte ao
que será removido, todos os elementos uma posição para à esquerda.

O exemplo list06.c abaixo mostra um programa que inclui estes dois algoritmos. Como a
lista não estará sempre cheia, já que estaremos removendo e inserindo elementos a todo instante,
iremos modificar as rotinas de busca. A modificação adiciona uma variável n que contém o número
de elementos na lista no instante em questão. O programa pede ao usuário que indique através de
uma letra qual operação deseja executar. As operações possíveis são as seguintes: [I]nserir,
[R]emover, [L]istar e [S]air. Para facilitar o entendimento a lista utilizada contém somente números
inteiros.

/* programa list06.c */
/* Busca um elemento na lista L */
#define MAX 5
#include <stdio.h>
#include <ctype.h>

char meu_menu();
void insere(int item[], int *n);
void meu_remove(int item[], int *n);
void listar(int item[], int n);
void ordena(int item[], int n);
int busca_bin (int item[], int n, int x);

int main()
{
int item[MAX];
int n=0, sair=0;
int a, b, t;

char opcao;

do {
opcao = meu_menu();
switch (opcao) {
case 'i':
insere(item, &n);
break;
case 'r':
meu_remove(item, &n);
break;
case 'l':
listar(item, n);
break;
case 's':
sair = 1;
break;
default:
puts("Opcao invalida.");
break;
}
} while (!sair);
}

void ordena(int item[], int n){

int a, b, t;

for (a=1; a<n; ++a)


{
t = item[a];
for (b=a-1; b>=0 && t < item[b]; b--) {
item[b+1]=item[b];
}
item[b+1]=t;
}
}

int busca_bin (int item[], int n, int x) {


int inf=0, sup, meio, achou=-1;

sup = n-1;
while (inf <= sup) {
meio = (1/2)*(inf+sup);
if (item[meio]==x) {
achou=meio;
inf = sup + 1;
}
else if (item[meio]<x)
inf = meio+1;
else
sup = meio-1;
}
return achou;
}

void listar (int item[], int n) {

int i;

for (i=0; i<n; i++) printf("elemento %d = %d \n", i, item[i]);

char meu_menu () {

char opcao, linha[80];


// limpa();
puts("Qual a sua opcao?");
puts("[L]istar, [I]nserir, [R]emover, [S]air");
gets(linha);
sscanf(linha, "%c", &opcao);
return tolower(opcao);
}

void imprime (int item[])


{
int i;

for (i=0; i<5; i++) {


printf("%d ", item[i]);
}
printf("\n");
}

void insere (int item[], int *n) {


int t;
char linha[80];

printf("Valor a inserir? ");


gets(linha); sscanf(linha, "%d", &t);

if (*n < MAX-1) {


if ( busca_bin(item, *n, t) == -1) {
item[*n] = t;
*n=*n+1;
ordena (item, *n);
}
else puts("Elemento ja existe na tabela.");
}
else puts("Lista ja cheia.");

void meu_remove (int item[], int *n) {

int x, indice, i;
char linha[80];

if (*n != 0) {
printf("Valor a remover? ");
gets(linha); sscanf(linha, "%d", &x);
indice = busca_bin(item, *n, x);
printf("Indice = %d\n", indice);
if (indice != -1) {
for (i=indice; i<*n; i++) item[i] = item[i+1];
*n = *n - 1;
}
else puts("Nao existe este elemento.");
}
else puts("Lista vazia");
}

Listas com Alocação Encadeada

Listas Simplesmente Encadeadas

A Figura lista encadeada abaixo mostra como seria uma lista usando ponteiros para encadear
os elementos da lista. O ponteiro pt aponta para o nó inicial da lista. Cada nó está representado por
um retângulo dividido em duas partes. Uma das partes contém a informação e a outra o ponteiro
para o próximo nó. Observar que no último nó a seta aponta para a terra (ponteiro nulo), que indica
fim da lista.
Lista Linear Simplesmente Encadeada

O algoritmo LEnc mostra as operações de inserção e retirada que podem ser feitas em
qualquer posição de uma lista encadeada e a operação de percurso (listar) da lista.

#include <stdio.h>
#include <stdlib.h>

struct node {
int info;
struct node *prox;
};

struct node *frente=0;


struct node *tras=0;
struct node *aux=0;
struct node *trb=0;

void insereIni(int valor);


void insereFim(int valor);
void menu();
void percurso();
int retiraFrente();
int retiraFim();
void destroi();
void inserepos(int valor, int pos);

int main( ){

int escolha;
int valor,pos,retira;
printf("Lista Linear Encadeada\n");

do {
menu();
printf("escolha uma das opcoes \n");
scanf("%d", &escolha);
switch(escolha)
{
case 1:
printf("\nINSERE NO DO FIM DA LISTA\n");
printf("\n\n DIGITE O NUMERO PARA INSERCAO NO FINAL DA LISTA ");
scanf("%d",&valor);
insereFim(valor);
printf("\n\n o valor inserido no final da lista foi %d \n\n\n", *tras);
system("pause");
break;
case 2:
printf("\n\n INSERE NO INICIO DA LISTA \n");
printf("\n\n DIGITE O NUMERO PARA INSERCAO NO INICIO DA LISTA ");
scanf("%d", &valor);
insereIni(valor);
printf("\n\n o valor inserido no inicio da lista foi %d ", *frente);
system("pause");
break;
case 3:
printf("\n\n INSERE EM UMA POSICAO DA LISTA \n");
printf("\n\n DIGITE O NUMERO PARA INSERCAO EM UMA POSICAO DA
LISTA ");
scanf("%d",&valor);
printf("\n\n DIGITE A POSICAO NA LISTA ");
scanf("%d", &pos);
inserepos(valor,pos);
system("pause");
break;
case 4:
printf("\n\n RETIRA DO FINAL DA LISTA \n");
retira=retiraFim();
printf("\nO valor retirado do final da lista foi %d ", retira);
system("pause");
break;
case 5:
printf("\n\n RETIRA DO INICIO DA LISTA \n");
retira=retiraFrente();
printf("\n\n O VALOR DO PRIMEIRO ELEMENTO RETIRADO DA LISTA %d\n", retira);
system("pause");
break;
case 6:
printf("\n\n RETIRA DE UMA POSICAO DA LISTA \n");
system("pause");
break;
case 7:
printf("\n\n imprimir a lista \n");
percurso();
system("pause");
break;
case 8:
printf("\n\n terminar o processamento da lista \n");
destroi();
system("pause");
break;
default:
destroi();
printf("\n\n FIM DO PROGRAMA \n");
system("pause");
break;
}
}while(escolha < 8);

printf("\n\n______________FIM DO
PROGRAMA_____________________________\n\n");
}

void menu()
{
system("cls");
printf("\n\n ESCOLHA UMA DAS OPCOES \n\n");
printf(" 1 : para inserir no final da lista \n");
printf(" 2 : para inserir no inicio da lista \n");
printf(" 3 : para inserir em uma posicao da lista \n");
printf(" 4 : retirar do final da lista \n");
printf(" 5 : retirar do inicio da lista \n");
printf(" 6 : retirar de uma posicao da lista \n");
printf(" 7 : imprimir a lista \n\n");
}

void insereFim(int valor)


{
struct node *p = 0;
p=(node *) malloc(sizeof(struct node));
printf("o valor de p e %X ",p, "\n\n");
p->info=valor;
p->prox=0;
printf("\n o valor armazenado e %d", p->info);
printf("\n o campo p->prox e %d", p->prox);
printf("\n\n");

if (frente==0) {
frente=tras=p;
}
else
{
tras->prox=p;
tras=p;
}
}

void inserepos(int valor, int pos) {

int i = 1;
struct node *p = 0;
struct node *ptrtrb, *ptraux;
p=(node *) malloc(sizeof(struct node));
printf("o valor de p e %X ",p, "\n\n");
p->info=valor;
p->prox=0;

/* if (pos > tam+1) {


printf("nao foi possivel inserir no na lista /n");
return 0;
}
*/
ptrtrb=frente;
while ((ptrtrb != 0) && (i<pos)){
ptraux=ptrtrb;
ptrtrb=ptrtrb->prox;
i++;
}

if (pos==1) {
p->prox=frente;
frente=p;
if(tras==0) tras=frente;
}
else {
if ((ptrtrb==0) && (i==pos)) {
tras->prox=p;
tras=p;
}
else {
ptraux->prox=p;
p->prox=ptrtrb;
}
}
}

void insereIni(int valor)


{
struct node *p = 0;
p=(node *) malloc(sizeof(struct node));
printf("o valor de p e %X ",p, "\n\n");
p->info=valor;
if (frente==0) {
frente=tras=p;
frente->prox=0;
}
else
{
p->prox=frente;
frente=p;
}
printf("\n o valor armazenado e %d", p->info);
printf("\n o campo p->prox e %d", frente->prox);
printf("\n\n");
}

void percurso()
{
struct node *aux=0;

if (frente==0)
printf("\n\n fila vazia \n");
else {
aux=frente;
printf("\n o endereco do primeiro no da fila e %X \n", frente);
while(aux->prox!=0) {
printf("\n aux -> info %d \n", aux->info);
printf("\n aux -> prox %X \n", aux->prox);
aux=aux->prox;
}
printf("\n o endereco do ultimo no e %X \n", tras);
printf("\n aux -> info %d \n", aux -> info);
printf("\n aux -> prox %X \n", aux -> prox);
aux=0;
}
}

void destroi()
{
struct node *aux=0;

aux=frente;
while(aux!=0) {
trb=aux;
aux=aux->prox;
free(trb);
}
aux=0;
frente=0;
tras=0;
trb=0;
}

int retiraFrente()
{
int retirado;

if (frente==0)
printf("\nfila vazia\n");
else
{
if (frente==tras) {
retirado=frente->info;
aux=frente;
frente=tras=0;
}
else
{
aux=frente;
retirado=frente->info;
frente=frente->prox;
}
free(aux);
return(retirado);
}
}
int retiraFim()
{
int retirado;
struct node *ptrtrb, *ptraux;

if (tras==0) {
printf("\nfila vazia\n");
system("pause");
return 0;
}

if (frente==tras) {
retirado=frente->info;
ptrtrb=frente;
frente=tras=0;
}
else {
retirado=tras->info;
ptrtrb=ptraux=frente;
while(ptrtrb->prox!=0) {
ptraux=ptrtrb;
ptrtrb=ptrtrb->prox;
};
tras=ptraux;
tras->prox=0;
}
free(ptrtrb);
return(retirado);
}

O algoritmo implista mostra uma implementação alternativa de como percorrer uma lista
encadeada simples.

void listar (struct tElemento *ptlista) {

int i=0;
struct tElemento *pont;

pont = ptlista;
while (pont) {
printf("Elemento %d = %d\n", i++, pont->info);
pont = pont->prox;
}
}

Outros algoritmos relevantes em listas são: busca, inserção e remoção. Para facilitar a busca
e localização dos nós a serem removidos e das posições de inserção modificaremos a lista para
incluir o que costuma ser chamado de nó cabeça. Neste tipo de lista o primeiro nó não irá conter
informação, ele apenas faz com que o algoritmo de busca não necessite diferenciar o primeiro nó
dos demais. A figura lista encadeada com nó cabeça ilustra esta lista.
lista encadeada com nó cabeça

A rotina de busca que iremos mostrar é um algoritmo simples que tem como protótipo
ponteiros para ponteiros. O primeiro **ant aponta para o nó anterior ao nó procurado e **ponte
aponta para o nó procurado.

void busca ( tElemento *ptlista, int x, tElemento **ant, tElemento **ponte) {


/* *ptlista ponteiro para inicio da lista
x elemento a ser procurado
**ant ponteiro para ponteiro do elemento anterior
**pont ponteiro para ponteiro do elemento procurado
*/
tElemento *ptr;

*ant = ptlista; /* aponta no anterior */


*ponte = NULL; /* aponta no procurado, se nao achar retorna nulo */
ptr = ptlista->prox; /* aponta no procurado */

while (ptr) { /* procura enquanto houver chance */


if (ptr->info < x) { /* ainda nao chegou no no */
*ant = ptr;
ptr = ptr->prox;
}
else { /* pode ser aqui */
if (ptr->info == x) *ponte = ptr; /* achou */
ptr = NULL; /* nao estava na lista */
}
}
}

A figura remoção de lista encadeada com nó cabeça ilustra o algoritmo de remoção, que tem
o código mostrado abaixo.
remocao de lista encadeada com nó cabeça

void remover ( tElemento *ptlista) {

int x;
char linha[80];
tElemento **ant, **pont;

printf("Valor a remover? ");


fgets(linha, 80, stdin); sscanf(linha, "%d", &x);

ant = ( tElemento **) malloc(sizeof ( tElemento *));


pont = ( tElemento **) malloc(sizeof ( tElemento *));
busca (ptlista, x, ant, pont);
if (*pont) {
(*ant)->prox = (*pont)->prox;
printf("Retirei %d\n", (*pont)->info);
free(*pont);
}
else puts("Nao achei na lista.");
}

O algoritmo de inserção tem o seguinte código:

void insere ( tElemento *ptlista) {

tElemento *pt, /* ponteiro para o novo no a inserir */


**ant, /* ponteiro para ponteiro na lista */
**pont; /* ponteiro para ponteiro do no anterior */
int x;
char linha[80];

printf("Valor a inserir? ");


fgets(linha, 80, stdin); sscanf(linha, "%d", &x);

ant = ( tElemento **) malloc(sizeof ( tElemento *));


pont = ( tElemento **) malloc(sizeof ( tElemento *));

busca (ptlista, x, ant, pont);


if (!*pont) {
pt = ( tElemento *) malloc(sizeof( tElemento));
pt->info = x;
pt->prox = (*ant)->prox;
(*ant)->prox = pt;
} else puts("Elemento ja existe na tabela.");
}

Listas Circulares

O algoritmo de busca em uma lista encadeada pode ser melhorado se modificarmos a lista de
modo que ela passe a ser circular como está mostrado na figura listcirc abaixo.

Lista Circular Encadeada

Neste caso o algoritmo não tem como testar o final da lista. A solução é armazenar o dado
que se está procurando no nó cabeça. Ao término do algoritmo a chave é sempre encontrada, e
pode-se descobrir se ela pertencia ou não a lista pelo ponteiro que foi dado como resposta. Caso o
ponteiro termine apontando para o nó cabeça, podemos afirmar que o elemento não se encontra na
lista.

Os algoritmos de procura, inserção e remoção em uma lista circular encadeada estão


mostrados no programa list23.c. O algoritmo de busca aparece como parte das rotinas de inserção e
remoção. Neste algoritmos primeiro se procura o elemento depois se decide o que fazer. No
algoritmo de busca, caso o elemento já exista na lista, não há nada a fazer, caso contrário o ponteiro
ant aponta para o elemento após o qual o novo elemento será inserido. No algoritmo de remoção, a
busca termina apontando para o elemento a ser removido (ponteiro pont) ou com a indicação que o
elemento não se encontra na lista (pont apontando para o nó cabeça).

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>

struct tElemento {
int info;
struct tElemento *prox;
};
char tela();
struct tElemento *cria_no();
void insere (struct tElemento *, int );
void meu_remove (struct tElemento *, int);
void listar(struct tElemento *);

void main()
{
struct tElemento *ptlista;
char linha[80];
char opcao;
int sair = 0, valor;

ptlista = cria_no();
ptlista->prox=ptlista;

do {
opcao = tela();
switch (opcao) {
case 'i':
puts("Qual dado a inserir?"); gets(linha);
sscanf(linha, "%d", &valor);
insere(ptlista, valor);
break;
case 'r':
puts("Qual dado a remover?"); gets(linha);
sscanf(linha, "%d", &valor);
meu_remove(ptlista, valor);
break;
case 'l':
listar(ptlista);
break;
case 's':
sair = 1;
break;
default:
puts("Opcao invalida.");
break;
}
} while (!sair);
}

char tela () {

char opcao, linha[80];

puts("Qual a sua opcao?");


puts("[L]istar, [I]nserir, [R]emover, [S]air");
gets(linha);
sscanf(linha, "%c", &opcao);
return tolower(opcao);
}

void listar (struct tElemento *ptlista) {

int i=0;
struct tElemento *pont;

pont = ptlista->prox;
while (pont != ptlista) {
printf("Elemento %d = %d\n", i++, pont->info);
pont = pont->prox;
}
}

void insere (struct tElemento *ptlista, int valor) {

struct tElemento *pont, *ant, *pt;

/* Aqui esta o algoritmo de busca em uma lista circular */

ant = ptlista; pont = ptlista->prox;


ptlista->info = valor;

while (pont->info < valor) {


ant = pont;
pont = pont->prox;
}

if (pont->info == valor && pont != ptlista)


puts("Elemento ja existe na tabela.");
else {
pt = cria_no();
pt->info = valor;
pt->prox = pont;
ant->prox = pt;
}
}

void meu_remove (struct tElemento *ptlista, int valor) {


struct tElemento *pont, *ant;

ant = ptlista; pont = ptlista->prox;


ptlista->info = valor;

while (pont->info < valor) {


if (pont->info < valor) {
ant = pont;
pont = pont->prox;
}
}

if (pont->info == valor && pont != ptlista) {


ant->prox = pont->prox;
free(pont);
}
else puts("Elemento nao existe na tabela.");
}

struct tElemento *cria_no() {

struct tElemento *pt;

if (( pt = (struct tElemento *) malloc(sizeof(struct tElemento)) ) == NULL )


{
puts("Nao há espaço.");
exit(1);
}
pt->info = -1;
pt->prox = NULL;
return pt;
}

------------------------------------------------------------------------
Exercícios

1. Escreva um programa similar ao list06.c. Neste programa a lista conterá elementos do seguinte
tipo.

typedef struct {
char nome[40];
unsigned long int dre;
} Taluno;

typdef struct {
int n; /* numero de elementos na lista em determinado instante */
Taluno alunos[50]; /* lista propriamente dita */
} Tlista;

2. Escreva um programa que converta uma expressão em notação com parênteses e converta
para notação polonesa reversa. Assuma que todas as operações da expressão são escritas
com parênteses. Por exemplo: (A * (B + C)).

3. Um palíndromo é um conjunto de caracteres que lido nos dois sentidos fornece o mesmo
resultado. Por exemplo: osso, 63736, orava o avaro. Escreva um programa que leia um
conjunto de caracteres e utilizando uma pilha verifique se um conjunto de caracteres é um
palíndromo. A pilha servirá para armazenar o conjunto de caracteres e permitir que ele seja
lido da direita para à esquerda.
4. Escreva um programa que mantenha duas pilhas em um único vetor (int vetor[MAXSIZE];),
de tal maneira que nenhuma das duas pilhas forneça mensagem de pilha cheia até que todo o
vetor esteja cheio e uma pilha não pode ser movida para uma posição diferente dentro do
vetor. Escreva as rotinas insere1, retira1, insere2 e retira2 para manter as duas pilhas.
(Sugestão: as duas pilhas devem crescer, uma em direção à outra.).

5. Escreva um programa que leia um texto de tamanho MAXLINES em que cada linha tem
tamanho MAXCARACS. Imprima em ordem crescente cada palavra contida no texto e
quantas vezes ela aparece. Assuma que as palavras são separadas por um ou mais caracteres
brancos. Use uma lista ordenada para ir armazenando cada uma das diferentes palavras que
foram sendo encontradas. O texto pode conter caracteres maiúsculos e minúsculos mas
palavras escritas em diferentes caixas (maiúsculas e minúsculas) serão contadas e impressas
uma vez apenas.

Das könnte Ihnen auch gefallen