Você está na página 1de 5

Universidade Estadual de Santa Cruz

Ciência da Computação – Linguagem de Programação 2 – 2011.1

Lista de Exercícios L2 – Listas Encadeadas

Exercício 4.1

Considere uma lista simplesmente encadeada com a seguinte estrutura:

struct nodo { int dado; struct nodo* prox; };

Escreva a função RemoveUltimo que

recebe um ponteiro para a lista L,

remove o último nodo de L, e

não retorna nada.

A função deve funcionar corretamente em todos os casos, incluindo:

lista vazia,

lista com um único nodo,

lista com dois nodos, e

lista com n nodos.

Exercício 4.2

Considere uma lista simplesmente encadeada com a mesma estrutura do Exercício 4.1. Escreva a função MoveParaInicio que

recebe um ponteiro para a lista L e o inteiro N,

caso N se encontre em um ou mais nodos de L, move os nodos contendo N para o início de L, e

retorna um booleano indicando se N encontra-se ou não em L; suponha que o tipo Bool já existe e que pode assumir os valores TRUE ou FALSE.

Essa função deve manipular apenas ponteiros, ou seja, não deve criar nodos com malloc() nem des- truí-los com free(). Além disso, a função deve funcionar corretamente em todos os casos, incluindo:

lista vazia,

lista com um único nodo contendo N,

lista com um único nodo não contendo N,

lista com dois nodos, nenhum deles contendo N,

lista com dois nodos, apenas um contendo N,

lista com dois nodos, ambos contendo N,

lista com n nodos, nenhum deles contendo N,

lista com n nodos, apenas um contendo N, e

lista com n nodos, vários contendo N, mas não todos, e

lista com n nodos, todos contendo N.

Exercício 4.3

Considere a função

int Tamanho (struct nodo* lista)

que recebe um ponteiro para uma lista linear (veja figura no Exercício 4.6) e retorna o número de nodos da lista. Uma forma de implementar essa função consiste em percorrer toda a lista contando o número de nodos visitados. Uma implementação alternativa envolve o uso de uma variável global

static int tamLista

Assim, ao invés de percorrer toda a lista contando o número de nodos, a função Tamanho() apenas re- torna o valor armazenado em tamLista.

Responda as seguintes perguntas:

1) Por que tamLista deve ser global? Por que não pode ser local a Tamanho()? 2) Por que tamLista é declarada como static? 3) Quais as vantagens dessa implementação alternativa? 4) Quais as desvantagens?

Exercício 4.4

Considere uma lista duplamente encadeada com a seguinte estrutura:

struct nodo { char letra; struct nodo* antes; struct nodo* depois; };

Escreva a função ehPalindromo que

recebe dois ponteiros para a lista L (um para o início e outro para o fim de L),

determina se a palavra formada pelas letras em L é um palíndromo (veja a lista L3, Exercício 3.3), e

retorna um booleano indicando se trata-se ou não de um palíndromo; suponha que o tipo Bool existe e que pode assumir os valores TRUE ou FALSE.

A função deve ser iterativa (ou seja, não use recursão). Além disso, a função deve funcionar corretamente em todos os casos, incluindo:

lista vazia,

lista com um único nodo,

lista com dois nodos contendo letras iguais,

lista com dois nodos contendo letras diferentes,

lista com três, quatro e n nodos contendo um palíndromo, e

lista com três, quatro e n nodos contendo um não-palíndromo.

Exercício 4.5

Implemente a versão recursiva da função ehPalindromo do exercício anterior.

Exercício 4.6

Considere a função abaixo. Suponha que tDado , nodo , dado e prox já estejam definidos.

/* Dada uma lista nao-vazia, remove o nodo inicial */

/* e retorna o dado nele contido

tDado TiraDoInicio (struct nodo* lista) { struct nodo* inicio; tDado dadoNoInicio; inicio = lista; if (inicio == NULL) exit (-1); dadoNoInicio = inicio->dado; lista = inicio->prox; free (inicio); return (dadoNoInicio);

}

*/

Essa função realiza corretamente a operação esperada (remover o primeiro nodo de uma lista e retornar o valor nele armazenado)? Justifique.

Exercício 4.7

Uma lista circular simplesmente encadeada é uma lista linear onde o último nodo aponta de volta para o primeiro. A lista linear é acessada através de um ponteiro para o primeiro nodo; a circular, através de um ponteiro para o último nodo. Isso permite um acesso fácil a ambas as extremidades da lista circular.

Considere uma lista linear L e uma lista circular C, ambas simplesmente encadeadas e com
Considere uma lista linear L e uma lista circular C, ambas simplesmente encadeadas e com a mesma
estrutura do Exercício 4.1.

1) Escreva a função TornaCircular que

recebe um ponteiro para a lista linear L,

transforma L em uma lista circular, e

não retorna nada.

2) Escreva a função TornaLinear que faz o oposto da função anterior.

3) Escreva a função TamanhoCircular que

recebe um ponteiro para a lista circular C,

conta o número de nodos em C, e

retorna esse número.

As três funções acima devem funcionar corretamente em todos os casos, incluindo:

lista vazia,

lista com um único nodo,

lista com dois nodos, e

lista com n nodos.

4) Escreva a função UneCirculares que

recebe dois ponteiro para as listas circulares C e D,

une C e D em uma única lista circular,

coloca o resultado da união em C,

deixa D vazia, e

não retorna nada.

A função acima deve executar em tempo constante, independente do tamanho de C e D. Além disso, a função deve funcionar corretamente em todos os casos, incluindo as seguintes combinações:

Nodos em D

0

1

2

n

Nodos em C

0

1

2

n

Exercício 4.8

Considere uma lista simplesmente encadeada com a mesma estrutura do Exercício 4.1, onde os todos os inteiros estão entre 0 e 9 inclusive.

1) Escreva a função ListaParaInt que

recebe um ponteiro para a lista L,

interpreta os números em L como dígitos de um long unsigned int, e

retorna o número resultante.

Suponha que o dígito mais significativo esteja no início da lista, e que o número final pode ser armaze- nado em um long unsigned int sem causar overflow .

A função deve funcionar corretamente em todos os casos, incluindo:

lista vazia (nesse caso a função deve retornar 0),

lista com um único nodo,

lista com dois nodos, e

lista com n nodos.

2) Escreva a função IntParaLista que faz o oposto da função acima, ou seja:

recebe um inteiro N do tipo unsigned long int,

coloca cada um dos dígitos decimais de N em uma lista L, e

retorna um ponteiro para o início de L.

Exercício 4.9

Considere uma lista circular L duplamente encadeada, como na figura abaixo.

circular L duplamente encadeada, como na figura abaixo. Os nodos da lista possuem a seguinte estrutura:

Os nodos da lista possuem a seguinte estrutura:

struct nodo { struct nodo* antes; int dado; struct nodo* depois;

};

Considere também a função abaixo, onde *fim aponta para o último nodo de L.

void funcao (struct nodo **fim) { struct nodo *p; if (*fim == NULL) return; p = *fim->depois; p->antes = NULL; *fim->depois = NULL; *fim = p;

}

Qual o objetivo dessa função? Ou seja, o que ela faz?

Exercício 4.10

Considere a função abaixo. Suponha que nodo e prox já estejam definidos como no exercício 4.9.

void funcao (struct nodo** lista) { struct nodo* resultado = NULL; struct nodo* atual = *lista; struct nodo* prox; while (atual != NULL) { prox = atual->prox; atual->prox = resultado; resultado = atual; atual = prox;

}

*lista = resultado;

}

Qual o objetivo dessa função? Ou seja, o que ela faz?

Exercício 4.11

Considere a função abaixo. Suponha que nodo e prox já estejam definidos como no exercício 4.9.

void funcaoRecursiva (struct nodo** lista) { struct nodo* primeiro; struct nodo* resto; if (*lista == NULL) return; primeiro = *lista; resto = primeiro->prox; if (resto == NULL) return; funcaoRecursiva (&resto); primeiro->prox->prox = primeiro; primeiro->prox = NULL; *lista = resto;

}

Qual o objetivo dessa função? Ou seja, o que ela faz?