19.04.2013 Views

Pilhas, Filas e Listas - DEL

Pilhas, Filas e Listas - DEL

Pilhas, Filas e Listas - DEL

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Pilhas</strong>, <strong>Filas</strong> e <strong>Listas</strong><br />

1. Explique como implementar duas pillhas em um único vetor de tamanho n, de tal<br />

modo que nenhuma das pilhas sofra estouro positivo (rejeite uma nova inserção<br />

por estar lotada), a menos que o número total de elementos em ambas as pilhas<br />

juntas seja n. As operações PUSH e POP devem ser executadas no tempo O(1).<br />

2. Enquanto uma pilha permite a inserção e a eliminação de elementos em apenas<br />

uma extremidade e um fila permite a inserção em uma extremidade e a eliminação<br />

na outra extremidade, uma deque (double-ended queue, ou fila de extremidade<br />

dupla) permite a inserção e a eliminação em ambas as extremidades. Escreva<br />

quatro procedimentos de tempo O(1) para inserir elementos e eliminar elementos<br />

de ambas as extremidades de uma deque construída a partir de um vetor.<br />

3. Mostre como implementar uma fila usando duas pilhas. Analise o tempo de<br />

execução das operações sobre as filas.<br />

4. Mostre como implementar uma pilha usando duas filas. Analise o tempo de<br />

execução das operações sobre pilhas.<br />

5. Implemente uma pilha usando uma lista simplesmente encadeada. As operações<br />

PUSH e POP devem demorar o tempo O(1).<br />

6. Implemente uma fila usando uma lista simplesmente encadeada. As operações<br />

ENQUEUE e DEQUEUE devem demorar o tempo O(1).<br />

7. Forneça um procedimento não recursivo de tempo Θ() que inverta uma lista<br />

simplesmente encadeada de n elementos. Qualquer consumo de memória além do<br />

espaço de armazenamento necessário para a própria lista deve ter tamanho O(1).<br />

8. Explique como implementar listas duplamente encadeadas usando apenas um<br />

valor de ponteiro np[x] por item, em lugar dos dois valores usuais (próximo e<br />

anterior). Suponha que todos os valores de ponteiros possam ser interpretados<br />

como inteiros de k bits e defina np[x] como np[x] = próximo[x] XOR anterior[x], o<br />

“ou exclusivo” de k bits de próximo [x] e anterior[x].(O valor NULL é representado<br />

por 0). Certifique-se de descrever as informações necessárias para obter acesso ao<br />

início da lista. Mostre como implementar operações para inserir, remover e<br />

recuperar elementos nesta lista. Mostre também como inverter a ordem dos<br />

elementos nesta lista em tempo O(1).<br />

9. Considere uma lista seqüencial definida pelas estruturas de dados abaixo:<br />

typedef struct // registro de um aluno<br />

{ char nome[41]; // nome do aluno<br />

char matricula[11]; // matricula do aluno<br />

float cr; // C.R. do aluno<br />

} ALUNO;<br />

typedef struct // lista de alunos<br />

{ ALUNO aluno[200]; // registros dos alunos<br />

int numAlunos; // numero de alunos na lista<br />

} LISTA_ALUNOS;


a. Calcule o tamanho (em bytes) dos tipos de dados ALUNO e<br />

LISTA_ALUNOS, considerando que o tipo char tem tamanho de 1 byte e<br />

os tipos int e float têm tamanho de 4 bytes.<br />

b. Construa uma função que retorne a quantidade de alunos com coeficiente<br />

de rendimento maior ou igual a 7.<br />

Protótipo: int numAlunosCrAlto(LISTA_ALUNOS *pLista)<br />

c. Construa uma função que receba a matrícula de um aluno e exclua este<br />

aluno da lista. A função deve retornar o valor 0 caso a exclusão seja bemsucedida,<br />

ou o valor 1 caso o aluno não seja encontrado na lista.<br />

Protótipo: int excluirAluno(LISTA_ALUNOS *pLista, char<br />

*matricula)<br />

10. Considere uma lista ordenada de itens disponíveis no almoxarifado de uma fábrica,<br />

sendo que cada item é identificado por um código numérico exclusivo:<br />

typedef struct // item do almoxarifado<br />

{<br />

int codItem; // código de identificação do item<br />

char descricao[21]; // texto descritivo do item<br />

int qtdEstoque; // quantidade disponível em estoque<br />

} ITEM;<br />

typedef struct // lista de itens<br />

{<br />

ITEM item[5000]; // registros dos itens<br />

int numItens; // numero de itens na lista<br />

} LISTA_ITENS;<br />

a. Supondo que a lista não esteja ordenada, construa uma função que receba<br />

um código de identificação de item e retorne a quantidade disponível em<br />

estoque para o item correspondente (caso o item não exista na lista, deve<br />

ser retornado o valor 0).<br />

Protótipo: int pesquisar(LISTA_ITENS *pLista, int cod)<br />

b. Supondo agora que a lista esteja ordenada, construa uma nova versão da<br />

mesma função construída no item (a) utilizando pesquisa binária.<br />

11. Nesta questão, você implementará uma pilha de caracteres e a utilizará em uma<br />

aplicação.<br />

a) Defina um tipo de dado denominado PILHA que represente uma pilha<br />

capaz de armazenar até 200 elementos do tipo primitivo char e construa<br />

as funções empilhar e desempilhar para esta estrutura.<br />

Protótipos:<br />

int empilhar(PILHA *pPilha, char c<br />

int desempilhar(PILHA *pPilha, char *c)<br />

b) Construa uma função que verifique se uma palavra é palíndroma, ou seja,<br />

se a palavra se mantém igual quando lida de trás para frente (exemplos:<br />

"radar", "arara", etc.). A função deve declarar uma variável do tipo PILHA<br />

e utilizar as funções empilhar e desempilhar construídas no item (a).<br />

Deve ser retornado o valor inteiro 0 quando a palavra for palíndroma, 1<br />

quando não for palíndroma e 2 quando ocorrer estouro de pilha.<br />

Protótipo: int palindroma(char *palavra)


12. Uma empresa de manutenção de equipamentos está implementando um sistema<br />

de controle de atendimento a chamados de clientes. O sistema deve ser capaz de<br />

cadastrar os chamados solicitados pelos clientes e deve garantir que os chamados<br />

sejam atendidos na mesma ordem em que tiverem sido cadastrados. Supondo que<br />

já exista um tipo de dados definido como CHAMADO que contém todas as<br />

informações necessárias para o cadastramento e atendimento de um chamado,<br />

implemente o que se pede abaixo:<br />

a. Defina um tipo de dados denominado FILA_CHAMADOS, que implemente<br />

uma fila circular de registros do tipo CHAMADO, com capacidade máxima de<br />

500 chamados simultâneos.<br />

b. Construa uma função para cadastramento de chamados, cuja finalidade<br />

seja enfileirar um novo registro do tipo CHAMADO em uma fila circular do<br />

tipo FILA_CHAMADOS.<br />

Protótipo: int cadastrarChamado(FILA_CHAMADOS *pFila,<br />

CHAMADO *pChamado)<br />

c. Construa uma função para atendimento de chamados, cuja finalidade seja<br />

desenfileirar um registro do tipo CHAMADO de uma fila circular do tipo<br />

FILA_CHAMADOS.<br />

Protótipo: int atenderChamado(FILA_CHAMADOS *pFila,<br />

CHAMADO *pChamado)<br />

obs: as funções para cadastrar e atender chamados devem retornar o valor 0<br />

quando a operação for bem-sucedida, ou um valor diferente de 0, quando<br />

ocorrer algum erro que impossibilite a operação.<br />

13. Considere uma lista dos clientes de uma empresa, definida pelas seguintes<br />

estruturas de dados:<br />

typedef struct // dados do cliente<br />

{<br />

char nome[41]; // nome do cliente<br />

int idade; // idade do cliente<br />

float rendaMensal; // renda mensal do cliente<br />

} CLIENTE;<br />

typedef struct // lista de clientes<br />

{<br />

CLIENTE cliente[5000]; // registros dos clientes<br />

int numClientes ; // número de clientes armazenados<br />

} LISTA_CLIENTES;<br />

Escreva funções em linguagem C para ordenar uma lista do tipo LISTA_CLIENTES,<br />

utilizando algoritmo de ordenação de sua livre escolha, conforme com os seguintes<br />

critérios:<br />

a. Pelo campo “nome” (ordem lexicográfica crescente)<br />

Protótipo: ordenarNome(LISTA_CLIENTES *pLista)<br />

b. Pelos campos “idade” (ordem crescente) + “rendaMensal” (ordem<br />

decrescente)<br />

Protótipo: ordenarIdadeRenda(LISTA_CLIENTES *pLista)


14. Considere agora uma versão encadeada da lista de clientes descrita na questão<br />

anterior, definida pelas seguintes estruturas de dados:<br />

typedef struct // Estrutura de um elemento da lista<br />

{<br />

CLIENTE cliente; // dados do cliente<br />

void * pProximo; // ponteiro para o próximo elemento<br />

} ELEMENTO;<br />

typedef struct // Estrutura da lista encadeada<br />

{<br />

CLIENTE * pPrimeiro; // ponteiro para o primeiro elemento<br />

} LISTA_ENCADEADA;<br />

Escreva funções em linguagem C para efetuar as operações solicitadas em cada item a<br />

seguir:<br />

a. Retornar o número de clientes com renda mensal igual ou superior a 1000.<br />

Protótipo: int numClientesRendaAlta(LISTA_ENCADEADA *pLista)<br />

b. Retornar ponteiro para o cliente mais velho da lista (retornar NULL em<br />

caso de lista vazia).<br />

Protótipo: CLIENTE *clienteMaisVelho(LISTA_ENCADEADA<br />

*pLista)<br />

15. Escreva funções em linguagem C para enfileirar e desenfileirar pacientes<br />

de uma fila circular do tipo FILA_PACIENTES, conforme os protótipos abaixo:<br />

int enfileirar(FILA_PACIENTES *pFila, PACIENTE *pPaciente)<br />

int desenfileirar(FILA_PACIENTES*pFila,PACIENTE *pPaciente)<br />

O valor de retorno deve ser igual a 0 quando a operação for bem sucedida, ou igual<br />

a 1 quando ocorrer alguma situação em que a operação não possa ser efetuada.<br />

16. Nesta questão, você implementará uma pilha de caracteres e a utilizará em uma<br />

aplicação.<br />

a. Defina um tipo de dado que represente uma pilha capaz de armazenar até<br />

200 elementos do tipo primitivo char e construa as funções empilhar e<br />

desempilhar para esta estrutura.<br />

b. Construa uma função que receba como parâmetro uma string contendo<br />

uma instrução em linguagem C e verifique se os parênteses e colchetes<br />

estão consistentes, utilizando a pilha que você definiu (exemplo:<br />

"x=2*(a[5*(2+b[i])]-c[j]);" é uma expressão consistente, mas<br />

"x=2*(a[5*(2+b[i])-c[j]);" e "x=2*a[5*(2+b[i])]-c[j]);" não<br />

são).<br />

17. Considere uma lista simplesmente encadeada cujos elementos possuam a<br />

estrutura abaixo, onde o tipo ALUNO foi definido na questão 1:<br />

typedef struct<br />

{<br />

ALUNO aluno; // dados do aluno<br />

void * pProximoAluno; // ponteiro para próximo aluno<br />

} ELEMENTO;


A lista deve ser representada por um ponteiro do tipo ELEMENTO * apontando<br />

para um "nó-cabeça" cujo campo pProximoAluno aponta para o primeiro aluno<br />

da lista.<br />

Escreva os algoritmos necessários para efetuar cada as operações especificadas<br />

abaixo:<br />

a. Retornar a quantidade de alunos com coeficiente de rendimento maior ou<br />

igual a 7.<br />

→ int numAlunosCrAlto(ELEMENTO *pLista)<br />

b. Excluir da lista todos os alunos com coeficiente de rendimento menor que<br />

5.<br />

→ void excluirAlunosCrBaixo(ELEMENTO *pLista)<br />

c. Retornar o nome do aluno com o maior coeficiente de rendimento da lista.<br />

→ char * nomeAlunoMaiorCr(ELEMENTO *pLista)<br />

18. Nesta questão, você trabalhará com filas circulares e construirá um sistema de<br />

gerenciamento de filas de impressão (spooler). Um spooler é utilizado quando uma<br />

impressora de rede é compartilhada por diversos usuários. Ao se inserir um<br />

arquivo no spooler, especifica-se um nível de prioridade para aquele arquivo.<br />

Arquivos com mesmo nível de prioridade são processados em ordem de chegada,<br />

mas arquivos com nível de prioridade mais alto são sempre processados antes dos<br />

arquivos com prioridade mais baixa (mesmo tendo chegado depois).<br />

Considere um spooler composto por 3 filas, conforme a estrutura abaixo, onde o<br />

tipo de dado FILA é uma implementação padrão de fila circular:<br />

typedef<br />

{ FILA FilaAlta; // Fila de prioridade alta<br />

FILA FilaMedia; // Fila de prioridade média<br />

FILA FilaBaixa; // Fila de prioridade baixa<br />

} SPOOLER;<br />

a. Defina o tipo de dado FILA para uma fila circular capaz de armazenar até<br />

50 elementos do tipo FILE * e construa as funções enfileirar e<br />

desenfileirar para esta estrutura. Estas funções devem retornar um<br />

código indicando se foi possível realizar a operação.<br />

b. Construa a função inserirSpooler(SPOOLER *,FILE *,char), que<br />

enfileira o ponteiro de arquivo recebido na fila com a prioridade<br />

especificada ('A'=alta; 'M'=média; 'B'=baixa), e a função<br />

retirarSpooler(SPOOLER *,FILE *), que desenfileira o ponteiro de<br />

arquivo que estiver no início da fila de mais alta prioridade que não esteja<br />

vazia.<br />

19. Considere uma versão duplamente encadeada (com "nó-cabeça") da lista descrita<br />

na questão anterior, cujos elementos possuam a estrutura<br />

typedef struct<br />

{<br />

DADOS_CLIENTE dados; // dados do cliente<br />

void * pProximoCliente; // ponteiro para próximo<br />

cliente<br />

void * pClienteAnterior; // ponteiro para cliente<br />

anterior<br />

} ELEMENTO;<br />

Escreva os algoritmos necessários para efetuar cada as operações definidas abaixo:


a. Trocar um elemento de posição com o seu sucessor<br />

→ void trocarPosicao(ELEMENTO *pElemento)<br />

b. Ordenar os elementos da lista em ordem crescente de idade, utilizando<br />

bubblesort.<br />

→ void ordenarBolha(ELEMENTO *pLista)<br />

20. Considere uma lista encadeada que armazena os clientes de uma empresa,<br />

definida pelas seguintes estruturas de dados:<br />

typedef struct // Dados de um cliente da empresa<br />

{<br />

char nome[41]; // nome do cliente<br />

char telefone[15]; // telefone do cliente<br />

int idade; // idade do cliente<br />

} DADOS_CLIENTE;<br />

typedef struct // Nó da lista encadeada<br />

{<br />

DADOS_CLIENTE dados; // dados do cliente<br />

void * pProximoCliente; // ponteiro para próximo cliente<br />

} CLIENTE;<br />

typedef struct // Lista encadeada de clientes<br />

{<br />

CLIENTE * pPrimeiroCliente; // ponteiro p/ primeiro cliente<br />

} LISTA_CLIENTES;<br />

Escreva funções em linguagem C para efetuar as operações solicitadas em cada item a<br />

seguir:<br />

a. Retornar o número total de clientes armazenados na lista.<br />

→ int numElementos(LISTA_CLIENTES *pLista)<br />

b. Retornar os dados do cliente mais velho da lista.<br />

→ DADOS_CLIENTE *dadosClienteMaisVelho(LISTA_CLIENTES<br />

*pLista)<br />

c. Excluir da lista todos os clientes com idade maior ou igual a 65 anos.<br />

→ void excluirIdosos(LISTA_CLIENTES *pLista)


Árvores<br />

1. Forneça um algoritmo não recursivo que execute um percurso de árvore em<br />

ordem. (Sugestão: Existe uma solução fácil que usa uma pilha como uma estrutura<br />

de dados auxiliar e uma solução mais complicada, embora elegante, que não<br />

emprega nenhuma pilha mas pressupõe que é possível testar a igualdade entre<br />

dois ponteiros.)<br />

2. Forneça algoritmos recursivos que executem caminhos de árvores de pré-ordem e<br />

pós-ordem no tempo Θ() em uma árvore de n nós.<br />

3. Mostre que, se um nó em uma árvore de pesquisa binária tem dois filhos, então<br />

seu sucessor não tem nenhum filho da esquerda e seu predecessor não tem<br />

nenhum filho da direita.<br />

4. Um percurso de árvore em ordem de uma árvore de pesquisa binária de n nós<br />

pode ser implementado encontrando-se o elemento mínimo na árvore com TREE-<br />

MINIMUM e, em seguida, fazendo-se n-1 chamadas a TREE-SUCESSOR. Prove que<br />

este algoritmo é executado em tempo Θ().<br />

5. Podemos classificar um dado conjunto de n números construindo primeiro uma<br />

árvore de pesquisa binária contendo esses números ( usando TREE-INSERT<br />

repetidamente para inserir os números um a um), e depois imprimindo os<br />

números por meio de um percurso de árvore em ordem. Quais são os tempos de<br />

execução no pior caso e no melhor caso para esse algoritmo de ordenação?<br />

6. Dadas duas cadeias = … = … onde cada e cada <br />

pertencem a algum conjunto ordenado de caracteres, dizemos que a cadeia a é<br />

lexicograficamente menor que a cadeia b se


1- Existe um inteiro j, onde 0 ≤ ≤ min (, ), tal que = para todo<br />

= 0, 1, … − 1 < , ou<br />

2- < = para todo = 0, 1, … , .<br />

Por exemplo, se a e b são cadeias de bits, então 10100 < 10110 pela regra 1<br />

(fazendo-se j = 3) e 10100 < 101000 pela regra 2. Isso é semelhante à ordenação<br />

utilizada nos dicionários de idiomas.<br />

A estrutura de dados raiz de árvore mostrada na figura abaixo armazena as cadeias<br />

de bits 1011, 10, 011, 100 e 0. Quando procuramos por uma chave = … ,<br />

vamos para a esquerda em um nó de profundidade i se = 0 e para a direita se<br />

= 1. Seja S um conjunto de cadeias binárias distintas cujos comprimentos<br />

produzem a soma n. Mostre como usar uma raiz de árvore para ordenar<br />

lexicograficamente o conjunto S no tempo Θ(). No caso do exemplo da Figura, a<br />

saída da ordenação deve ser a sequência 0, 011, 10, 100, 1011.<br />

7. Considere a árvore binária de busca representada no diagrama abaixo, no qual são<br />

exibidos os valores das chaves de ordenação numéricas correspondentes a cada<br />

nó:<br />

a. Indique a ordem em que os nós da árvore acima seriam visitados em um percurso<br />

pré-ordem e em um percurso pós-ordem.<br />

b. Mostre que é árvore acima é AVL, indicando, para cada nó, as alturas das subárvores<br />

esquerda e direita e o fator de balanço correspondente.<br />

c. Redesenhe a árvore após a inserção de um novo elemento cuja chave de ordenação<br />

tenha valor 60 e demonstre que a árvore deixará de ser AVL, indicando os nós que<br />

ficarão desregulados e seus respectivos balanços.<br />

d. Indique qual o tipo de rotação que deve ser aplicada para que a árvore volte a ser<br />

AVL após a inclusão do novo elemento e redesenhe a árvore após a aplicação dessa<br />

rotação.


8. Considere uma lista telefônica armazenada na forma de uma árvore binária de<br />

busca, representada pelas estruturas de dados definidas abaixo:<br />

typedef struct {char nome[41]; char telefone[11];} ASSINANTE;<br />

typedef struct {ASSINANTE a; void *pDir; void *pEsq;} NO;<br />

a. Construa uma função recursiva que receba o nome de um assinante e<br />

retorne o seu telefone (a função deve retornar NULL caso o assinante não<br />

seja encontrado na lista).<br />

Protótipo: char * pesquisarTelefone(NO * pNoRaiz, char<br />

*nomeAssinante)<br />

b. Construa uma função recursiva que exiba a lista de assinantes em ordem<br />

alfabética (dica: faça um percurso em ordem simétrica, imprimindo nome<br />

e telefone para cada nó visitado).<br />

Protótipo: void exibirLista(NO *pNoRaiz)<br />

c. Construa uma função recursiva que retorne a altura da árvore.<br />

Protótipo: int determinarAltura(NO *pNoRaiz)<br />

9. Considere um cadastro de alunos armazenado em uma árvore binária de busca<br />

representada pelas estruturas de dados abaixo, utilizando o campo nome como<br />

chave de ordenação:<br />

typedef struct { char nome[51]; int idade; } ALUNO;<br />

typedef struct { ALUNO raiz; void *pSubArvDir;<br />

void *pSubArvEsq; } ARVORE;<br />

a. Construa uma função recursiva que receba o nome de um aluno e retorne<br />

a sua idade (a função deve retornar NULL caso o aluno não seja<br />

encontrado na árvore).<br />

Protótipo: int pesquisarIdadeAluno(ARVORE *pArvore, char<br />

*nomeAluno)<br />

b. Construa uma função recursiva que imprima os nomes de todos os alunos<br />

cadastrados na árvore em ordem alfabética (dica: implemente um<br />

percurso em ordem simétrica).<br />

Protótipo: void imprimirNomes(ARVORE *pArvore)<br />

c. Construa uma função recursiva que receba um ponteiro para uma<br />

estrutura do tipo ARVORE e execute uma rotação dupla à direita na raiz da<br />

árvore AVL representada nesta estrutura.<br />

Protótipo: void rotacaoDuplaDireita(ARVORE *pArvore)


10. Considere um cadastro de funcionários armazenado na forma de uma árvore<br />

binária de busca representada pelas estruturas de dados definidas abaixo:<br />

typedef struct // DADOS DO FUNCIONARIO<br />

{ int matricula; // matricula do funcionario<br />

char nome[41]; // nome do funcionario<br />

float salario; // salario do funcionario<br />

} FUNCIONARIO;<br />

typedef struct // ARVORE BINARIA DE BUSCA<br />

{ FUNCIONARIO raiz; // dados do funcionario<br />

void *pSubArvoreEsq; // ponteiro para subarvore esquerda<br />

void *pSubArvoreDir; // ponteiro para subarvore direita<br />

} ARVORE;<br />

Construa uma função recursiva que receba a matrícula de um funcionário e<br />

retorne o seu salário.<br />

Protótipo:<br />

float salarioFuncionario(ARVORE *pArvore, int matricula)

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!