Pilhas, Filas e Listas

Propaganda
Pilhas, Filas e Listas
1. Explique como implementar duas pillhas em um único vetor de tamanho n, de tal
modo que nenhuma das pilhas sofra estouro positivo (rejeite uma nova inserção
por estar lotada), a menos que o número total de elementos em ambas as pilhas
juntas seja n. As operações PUSH e POP devem ser executadas no tempo O(1).
2. Enquanto uma pilha permite a inserção e a eliminação de elementos em apenas
uma extremidade e um fila permite a inserção em uma extremidade e a eliminação
na outra extremidade, uma deque (double-ended queue, ou fila de extremidade
dupla) permite a inserção e a eliminação em ambas as extremidades. Escreva
quatro procedimentos de tempo O(1) para inserir elementos e eliminar elementos
de ambas as extremidades de uma deque construída a partir de um vetor.
3. Mostre como implementar uma fila usando duas pilhas. Analise o tempo de
execução das operações sobre as filas.
4. Mostre como implementar uma pilha usando duas filas. Analise o tempo de
execução das operações sobre pilhas.
5. Implemente uma pilha usando uma lista simplesmente encadeada. As operações
PUSH e POP devem demorar o tempo O(1).
6. Implemente uma fila usando uma lista simplesmente encadeada. As operações
ENQUEUE e DEQUEUE devem demorar o tempo O(1).
7. Forneça um procedimento não recursivo de tempo Θ(݊) que inverta uma lista
simplesmente encadeada de n elementos. Qualquer consumo de memória além do
espaço de armazenamento necessário para a própria lista deve ter tamanho O(1).
8. Explique como implementar listas duplamente encadeadas usando apenas um
valor de ponteiro np[x] por item, em lugar dos dois valores usuais (próximo e
anterior). Suponha que todos os valores de ponteiros possam ser interpretados
como inteiros de k bits e defina np[x] como np[x] = próximo[x] XOR anterior[x], o
“ou exclusivo” de k bits de próximo [x] e anterior[x].(O valor NULL é representado
por 0). Certifique-se de descrever as informações necessárias para obter acesso ao
início da lista. Mostre como implementar operações para inserir, remover e
recuperar elementos nesta lista. Mostre também como inverter a ordem dos
elementos nesta lista em tempo O(1).
9. Considere uma lista seqüencial definida pelas estruturas de dados abaixo:
typedef struct
{ char nome[41];
char matricula[11];
float cr;
} ALUNO;
// registro de um aluno
//
nome do aluno
//
matricula do aluno
//
C.R. do aluno
typedef struct
// lista de alunos
{
ALUNO aluno[200]; //
registros dos alunos
int numAlunos;
//
numero de alunos na lista
} LISTA_ALUNOS;
a. Calcule o tamanho (em bytes) dos tipos de dados ALUNO e
LISTA_ALUNOS, considerando que o tipo char tem tamanho de 1 byte e
os tipos int e float têm tamanho de 4 bytes.
b. Construa uma função que retorne a quantidade de alunos com coeficiente
de rendimento maior ou igual a 7.
Protótipo: int numAlunosCrAlto(LISTA_ALUNOS *pLista)
c. Construa uma função que receba a matrícula de um aluno e exclua este
aluno da lista. A função deve retornar o valor 0 caso a exclusão seja bemsucedida, ou o valor 1 caso o aluno não seja encontrado na lista.
Protótipo: int excluirAluno(LISTA_ALUNOS *pLista, char
*matricula)
10. Considere uma lista ordenada de itens disponíveis no almoxarifado de uma fábrica,
sendo que cada item é identificado por um código numérico exclusivo:
typedef struct
{
int codItem;
char descricao[21];
int qtdEstoque;
} ITEM;
typedef struct
{
ITEM item[5000];
int numItens;
} LISTA_ITENS;
// item do almoxarifado
// código de identificação do item
// texto descritivo do item
// quantidade disponível em estoque
// lista de itens
// registros dos itens
// numero de itens na lista
a. Supondo que a lista não esteja ordenada, construa uma função que receba
um código de identificação de item e retorne a quantidade disponível em
estoque para o item correspondente (caso o item não exista na lista, deve
ser retornado o valor 0).
Protótipo: int pesquisar(LISTA_ITENS *pLista, int cod)
b. Supondo agora que a lista esteja ordenada, construa uma nova versão da
mesma função construída no item (a) utilizando pesquisa binária.
11. Nesta questão, você implementará uma pilha de caracteres e a utilizará em uma
aplicação.
a)
Defina um tipo de dado denominado PILHA que represente uma pilha
capaz de armazenar até 200 elementos do tipo primitivo char e construa
as funções empilhar e desempilhar para esta estrutura.
Protótipos:
int empilhar(PILHA *pPilha, char c
int desempilhar(PILHA *pPilha, char *c)
b)
Construa uma função que verifique se uma palavra é palíndroma, ou seja,
se a palavra se mantém igual quando lida de trás para frente (exemplos:
"radar", "arara", etc.). A função deve declarar uma variável do tipo PILHA
e utilizar as funções empilhar e desempilhar construídas no item (a).
Deve ser retornado o valor inteiro 0 quando a palavra for palíndroma, 1
quando não for palíndroma e 2 quando ocorrer estouro de pilha.
Protótipo: int palindroma(char *palavra)
12. Uma empresa de manutenção de equipamentos está implementando um sistema
de controle de atendimento a chamados de clientes. O sistema deve ser capaz de
cadastrar os chamados solicitados pelos clientes e deve garantir que os chamados
sejam atendidos na mesma ordem em que tiverem sido cadastrados. Supondo que
já exista um tipo de dados definido como CHAMADO que contém todas as
informações necessárias para o cadastramento e atendimento de um chamado,
implemente o que se pede abaixo:
a. Defina um tipo de dados denominado FILA_CHAMADOS, que implemente
uma fila circular de registros do tipo CHAMADO, com capacidade máxima de
500 chamados simultâneos.
b. Construa uma função para cadastramento de chamados, cuja finalidade
seja enfileirar um novo registro do tipo CHAMADO em uma fila circular do
tipo FILA_CHAMADOS.
cadastrarChamado(FILA_CHAMADOS
*pFila,
Protótipo: int
CHAMADO *pChamado)
c. Construa uma função para atendimento de chamados, cuja finalidade seja
desenfileirar um registro do tipo CHAMADO de uma fila circular do tipo
FILA_CHAMADOS.
Protótipo:
int
atenderChamado(FILA_CHAMADOS
*pFila,
CHAMADO *pChamado)
obs: as funções para cadastrar e atender chamados devem retornar o valor 0
quando a operação for bem-sucedida, ou um valor diferente de 0, quando
ocorrer algum erro que impossibilite a operação.
13. Considere uma lista dos clientes de uma empresa, definida pelas seguintes
estruturas de dados:
typedef struct
{
char nome[41];
int
idade;
float rendaMensal;
} CLIENTE;
// dados do cliente
//
//
//
nome do cliente
idade do cliente
renda mensal do cliente
typedef struct
// lista de clientes
{
CLIENTE cliente[5000]; //
registros dos clientes
int numClientes ;
//
número de clientes armazenados
} LISTA_CLIENTES;
Escreva funções em linguagem C para ordenar uma lista do tipo LISTA_CLIENTES,
utilizando algoritmo de ordenação de sua livre escolha, conforme com os seguintes
critérios:
a. Pelo campo “nome” (ordem lexicográfica crescente)
Protótipo: ordenarNome(LISTA_CLIENTES *pLista)
b. Pelos campos “idade” (ordem crescente) + “rendaMensal” (ordem
decrescente)
Protótipo: ordenarIdadeRenda(LISTA_CLIENTES *pLista)
14. Considere agora uma versão encadeada da lista de clientes descrita na questão
anterior, definida pelas seguintes estruturas de dados:
typedef struct
{
CLIENTE cliente;
void * pProximo;
} ELEMENTO;
// Estrutura de um elemento da lista
// dados do cliente
// ponteiro para o próximo elemento
typedef struct
// Estrutura da lista encadeada
{
CLIENTE * pPrimeiro; // ponteiro para o primeiro elemento
} LISTA_ENCADEADA;
Escreva funções em linguagem C para efetuar as operações solicitadas em cada item a
seguir:
a. Retornar o número de clientes com renda mensal igual ou superior a 1000.
Protótipo: int numClientesRendaAlta(LISTA_ENCADEADA *pLista)
b. Retornar ponteiro para o cliente mais velho da lista (retornar NULL em
caso de lista vazia).
Protótipo: CLIENTE *clienteMaisVelho(LISTA_ENCADEADA
*pLista)
15. Escreva funções em linguagem C para enfileirar e desenfileirar pacientes
de uma fila circular do tipo FILA_PACIENTES, conforme os protótipos abaixo:
int enfileirar(FILA_PACIENTES *pFila, PACIENTE *pPaciente)
int desenfileirar(FILA_PACIENTES*pFila,PACIENTE *pPaciente)
O valor de retorno deve ser igual a 0 quando a operação for bem sucedida, ou igual
a 1 quando ocorrer alguma situação em que a operação não possa ser efetuada.
16. Nesta questão, você implementará uma pilha de caracteres e a utilizará em uma
aplicação.
a. Defina um tipo de dado que represente uma pilha capaz de armazenar até
200 elementos do tipo primitivo char e construa as funções empilhar e
desempilhar para esta estrutura.
b. Construa uma função que receba como parâmetro uma string contendo
uma instrução em linguagem C e verifique se os parênteses e colchetes
estão consistentes, utilizando a pilha que você definiu (exemplo:
"x=2*(a[5*(2+b[i])]-c[j]);" é uma expressão consistente, mas
"x=2*(a[5*(2+b[i])-c[j]);" e "x=2*a[5*(2+b[i])]-c[j]);" não
são).
17. Considere uma lista simplesmente encadeada cujos elementos possuam a
estrutura abaixo, onde o tipo ALUNO foi definido na questão 1:
typedef struct
{
ALUNO aluno;
// dados do aluno
void * pProximoAluno; // ponteiro para próximo aluno
} ELEMENTO;
A lista deve ser representada por um ponteiro do tipo ELEMENTO * apontando
para um "nó-cabeça" cujo campo pProximoAluno aponta para o primeiro aluno
da lista.
Escreva os algoritmos necessários para efetuar cada as operações especificadas
abaixo:
a. Retornar a quantidade de alunos com coeficiente de rendimento maior ou
igual a 7.
→ int numAlunosCrAlto(ELEMENTO *pLista)
b. Excluir da lista todos os alunos com coeficiente de rendimento menor que
5.
→ void excluirAlunosCrBaixo(ELEMENTO *pLista)
c. Retornar o nome do aluno com o maior coeficiente de rendimento da lista.
→ char * nomeAlunoMaiorCr(ELEMENTO *pLista)
18. Nesta questão, você trabalhará com filas circulares e construirá um sistema de
gerenciamento de filas de impressão (spooler). Um spooler é utilizado quando uma
impressora de rede é compartilhada por diversos usuários. Ao se inserir um
arquivo no spooler, especifica-se um nível de prioridade para aquele arquivo.
Arquivos com mesmo nível de prioridade são processados em ordem de chegada,
mas arquivos com nível de prioridade mais alto são sempre processados antes dos
arquivos com prioridade mais baixa (mesmo tendo chegado depois).
Considere um spooler composto por 3 filas, conforme a estrutura abaixo, onde o
tipo de dado FILA é uma implementação padrão de fila circular:
typedef
{
FILA FilaAlta;
FILA FilaMedia;
FILA FilaBaixa;
} SPOOLER;
// Fila de prioridade alta
// Fila de prioridade média
// Fila de prioridade baixa
a. Defina o tipo de dado FILA para uma fila circular capaz de armazenar até
50 elementos do tipo FILE * e construa as funções enfileirar e
desenfileirar para esta estrutura. Estas funções devem retornar um
código indicando se foi possível realizar a operação.
b. Construa a função inserirSpooler(SPOOLER *,FILE *,char), que
enfileira o ponteiro de arquivo recebido na fila com a prioridade
especificada
('A'=alta;
'M'=média;
'B'=baixa),
e
a
função
retirarSpooler(SPOOLER *,FILE *), que desenfileira o ponteiro de
arquivo que estiver no início da fila de mais alta prioridade que não esteja
vazia.
19. Considere uma versão duplamente encadeada (com "nó-cabeça") da lista descrita
na questão anterior, cujos elementos possuam a estrutura
typedef struct
{
DADOS_CLIENTE dados;
// dados do cliente
void * pProximoCliente;
// ponteiro para próximo
cliente
void * pClienteAnterior;
// ponteiro para cliente
anterior
} ELEMENTO;
Escreva os algoritmos necessários para efetuar cada as operações definidas abaixo:
a. Trocar um elemento de posição com o seu sucessor
→ void trocarPosicao(ELEMENTO *pElemento)
b. Ordenar os elementos da lista em ordem crescente de idade, utilizando
bubblesort.
→ void ordenarBolha(ELEMENTO *pLista)
20. Considere uma lista encadeada que armazena os clientes de uma empresa,
definida pelas seguintes estruturas de dados:
typedef struct
{
char nome[41];
char telefone[15];
int idade;
} DADOS_CLIENTE;
// Dados de um cliente da empresa
//
//
//
nome do cliente
telefone do cliente
idade do cliente
typedef struct
// Nó da lista encadeada
{
DADOS_CLIENTE dados;
//
dados do cliente
void * pProximoCliente; //
ponteiro para próximo cliente
} CLIENTE;
typedef struct
// Lista encadeada de clientes
{
CLIENTE * pPrimeiroCliente; // ponteiro p/ primeiro cliente
} LISTA_CLIENTES;
Escreva funções em linguagem C para efetuar as operações solicitadas em cada item a
seguir:
a. Retornar o número total de clientes armazenados na lista.
→ int numElementos(LISTA_CLIENTES *pLista)
b. Retornar os dados do cliente mais velho da lista.
→ DADOS_CLIENTE *dadosClienteMaisVelho(LISTA_CLIENTES
*pLista)
c. Excluir da lista todos os clientes com idade maior ou igual a 65 anos.
→ void excluirIdosos(LISTA_CLIENTES *pLista)
Árvores
1. Forneça um algoritmo não recursivo que execute um percurso de árvore em
ordem. (Sugestão: Existe uma solução fácil que usa uma pilha como uma estrutura
de dados auxiliar e uma solução mais complicada, embora elegante, que não
emprega nenhuma pilha mas pressupõe que é possível testar a igualdade entre
dois ponteiros.)
2. Forneça algoritmos recursivos que executem caminhos de árvores de pré-ordem e
pós-ordem no tempo Θ(݊) em uma árvore de n nós.
3. Mostre que, se um nó em uma árvore de pesquisa binária tem dois filhos, então
seu sucessor não tem nenhum filho da esquerda e seu predecessor não tem
nenhum filho da direita.
4. Um percurso de árvore em ordem de uma árvore de pesquisa binária de n nós
pode ser implementado encontrando-se o elemento mínimo na árvore com TREEMINIMUM e, em seguida, fazendo-se n-1 chamadas a TREE-SUCESSOR. Prove que
este algoritmo é executado em tempo Θ(݊).
5. Podemos classificar um dado conjunto de n números construindo primeiro uma
árvore de pesquisa binária contendo esses números ( usando TREE-INSERT
repetidamente para inserir os números um a um), e depois imprimindo os
números por meio de um percurso de árvore em ordem. Quais são os tempos de
execução no pior caso e no melhor caso para esse algoritmo de ordenação?
6. Dadas duas cadeias ܽ = ܽ଴ ܽଵ … ܽ௣ ݁ ܾ = ܾ଴ ܾଵ … ܾ௤ onde cada ܽ௜ e cada ܾ௝
pertencem a algum conjunto ordenado de caracteres, dizemos que a cadeia a é
lexicograficamente menor que a cadeia b se
1- Existe um inteiro j, onde 0 ≤ ݆ ≤ min (‫݌‬, ‫)ݍ‬, tal que ܽ௜ = ܾ௝ para todo
݅ = 0, 1, … ݆ − 1 ݁ ܽ௝ < ܾ௝ , ou
2- ‫ܽ ݁ ݍ < ݌‬௜ = ܾ௜ para todo ݅ = 0, 1, … , ‫݌‬.
Por exemplo, se a e b são cadeias de bits, então 10100 < 10110 pela regra 1
(fazendo-se j = 3) e 10100 < 101000 pela regra 2. Isso é semelhante à ordenação
utilizada nos dicionários de idiomas.
A estrutura de dados raiz de árvore mostrada na figura abaixo armazena as cadeias
de bits 1011, 10, 011, 100 e 0. Quando procuramos por uma chave ܽ = ܽ଴ ܽଵ … ܽ௣ ,
vamos para a esquerda em um nó de profundidade i se ܽ௜ = 0 e para a direita se
ܽ௜ = 1. Seja S um conjunto de cadeias binárias distintas cujos comprimentos
produzem a soma n. Mostre como usar uma raiz de árvore para ordenar
lexicograficamente o conjunto S no tempo Θ(݊). No caso do exemplo da Figura, a
saída da ordenação deve ser a sequência 0, 011, 10, 100, 1011.
7. Considere a árvore binária de busca representada no diagrama abaixo, no qual são
exibidos os valores das chaves de ordenação numéricas correspondentes a cada
nó:
a. Indique a ordem em que os nós da árvore acima seriam visitados em um percurso
pré-ordem e em um percurso pós-ordem.
b. Mostre que é árvore acima é AVL, indicando, para cada nó, as alturas das subárvores esquerda e direita e o fator de balanço correspondente.
c. Redesenhe a árvore após a inserção de um novo elemento cuja chave de ordenação
tenha valor 60 e demonstre que a árvore deixará de ser AVL, indicando os nós que
ficarão desregulados e seus respectivos balanços.
d. Indique qual o tipo de rotação que deve ser aplicada para que a árvore volte a ser
AVL após a inclusão do novo elemento e redesenhe a árvore após a aplicação dessa
rotação.
8. Considere uma lista telefônica armazenada na forma de uma árvore binária de
busca, representada pelas estruturas de dados definidas abaixo:
typedef struct {char nome[41]; char telefone[11];} ASSINANTE;
typedef struct {ASSINANTE a; void *pDir; void *pEsq;} NO;
a. Construa uma função recursiva que receba o nome de um assinante e
retorne o seu telefone (a função deve retornar NULL caso o assinante não
seja encontrado na lista).
Protótipo: char * pesquisarTelefone(NO * pNoRaiz, char
*nomeAssinante)
b. Construa uma função recursiva que exiba a lista de assinantes em ordem
alfabética (dica: faça um percurso em ordem simétrica, imprimindo nome
e telefone para cada nó visitado).
Protótipo: void exibirLista(NO *pNoRaiz)
c. Construa uma função recursiva que retorne a altura da árvore.
Protótipo: int determinarAltura(NO *pNoRaiz)
9. Considere um cadastro de alunos armazenado em uma árvore binária de busca
representada pelas estruturas de dados abaixo, utilizando o campo nome como
chave de ordenação:
typedef struct { char nome[51]; int idade; } ALUNO;
typedef struct { ALUNO raiz; void *pSubArvDir;
void *pSubArvEsq; } ARVORE;
a. Construa uma função recursiva que receba o nome de um aluno e retorne
a sua idade (a função deve retornar NULL caso o aluno não seja
encontrado na árvore).
Protótipo: int pesquisarIdadeAluno(ARVORE *pArvore, char
*nomeAluno)
b. Construa uma função recursiva que imprima os nomes de todos os alunos
cadastrados na árvore em ordem alfabética (dica: implemente um
percurso em ordem simétrica).
Protótipo: void imprimirNomes(ARVORE *pArvore)
c. Construa uma função recursiva que receba um ponteiro para uma
estrutura do tipo ARVORE e execute uma rotação dupla à direita na raiz da
árvore AVL representada nesta estrutura.
Protótipo: void rotacaoDuplaDireita(ARVORE *pArvore)
10. Considere um cadastro de funcionários armazenado na forma de uma árvore
binária de busca representada pelas estruturas de dados definidas abaixo:
typedef struct
{ int
matricula;
char nome[41];
float salario;
} FUNCIONARIO;
// DADOS DO FUNCIONARIO
//
matricula do funcionario
//
nome do funcionario
//
salario do funcionario
typedef struct
{ FUNCIONARIO raiz;
void
*pSubArvoreEsq;
void
*pSubArvoreDir;
} ARVORE;
// ARVORE BINARIA DE BUSCA
//
dados do funcionario
// ponteiro para subarvore esquerda
// ponteiro para subarvore direita
Construa uma função recursiva que receba a matrícula de um funcionário e
retorne o seu salário.
Protótipo:
float salarioFuncionario(ARVORE *pArvore, int matricula)
Download