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)