Revisão Prova AED1 (Função, Recursão, Ponteiros e Lista Encadeada ) | Questões Resolvidas de Linguagem C
A revisão para a prova de Algoritmos e Estruturas de Dados 1 (AED1) abrange os seguintes tópicos: função, recursão, ponteiros e lista encadeada. Através da resolução de questões em Linguagem C, é possível aprimorar o entendimento e a aplicação desses conceitos.
No tópico de função, é importante compreender como declarar, definir e chamar funções em C, bem como entender os diferentes tipos de retorno e parâmetros. Além disso, é fundamental entender como as funções podem ser usadas para modularizar o código e melhorar a organização e reutilização do código.
A recursão é uma técnica em que uma função chama a si mesma para resolver um problema de forma iterativa. É necessário compreender como criar funções recursivas corretamente, estabelecendo as condições de parada e as chamadas recursivas adequadas.
Os ponteiros são elementos cruciais em C, permitindo o acesso e a manipulação direta da memória. É importante entender como declarar, inicializar e usar ponteiros, bem como compreender conceitos como endereços de memória, alocação dinâmica e ponteiros para funções.
A lista encadeada é uma estrutura de dados fundamental, onde cada elemento possui um valor e um ponteiro para o próximo elemento. É necessário conhecer como criar, manipular e percorrer listas encadeadas, bem como lidar com casos especiais, como inserção e remoção de elementos.
A resolução de questões em Linguagem C envolvendo esses tópicos permitirá consolidar os conhecimentos adquiridos e estar preparado para a prova de AED1. É recomendado praticar a escrita de código, resolver problemas e entender os conceitos por trás das soluções.
Lembrando que a prática e a compreensão teórica caminham lado a lado, e é importante também revisar a teoria relacionada a cada um desses tópicos para um melhor desempenho na prova.
Boa sorte na sua revisão e na prova de AED1!
Escreva uma função recursiva que faça o seguinte: leia um número; se o número for negativo, a função pára; caso contrário, a função imprime o número e faz uma chamada recursiva a si mesma.
#include <stdio.h>
void imprimirNumeroRecursivo() {
int numero;
printf("Digite um número: ");
scanf("%d", &numero);
if (numero < 0) {
return;
}
printf("Número digitado: %d\n", numero);
imprimirNumeroRecursivo();
}
int main() {
imprimirNumeroRecursivo();
return 0;
}
Escreva uma função recursiva, ImprimeSerie (i,j,k: inteiro), que imprime na tela a série de valores do
intervalo [i,j], com incremento k.
#include <stdio.h>
void ImprimeSerie(int i, int j, int k) {
if (i <= j) {
printf("%d ", i);
ImprimeSerie(i + k, j, k);
}
}
int main() {
int inicio, fim, incremento;
printf("Digite o valor inicial da série: ");
scanf("%d", &inicio);
printf("Digite o valor final da série: ");
scanf("%d", &fim);
printf("Digite o incremento da série: ");
scanf("%d", &incremento);
printf("Série: ");
ImprimeSerie(inicio, fim, incremento);
return 0;
}
Escreva uma função recursiva, SomaSerie (i,j,k: inteiro): inteiro, que devolva a soma da série de valores do intervalo [i,j], com incremento k.
#include <stdio.h>
int SomaSerie(int i, int j, int k) {
if (i > j) {
return 0;
} else {
return i + SomaSerie(i + k, j, k);
}
}
int main() {
int inicio, fim, incremento;
printf("Digite o valor inicial da série: ");
scanf("%d", &inicio);
printf("Digite o valor final da série: ");
scanf("%d", &fim);
printf("Digite o incremento da série: ");
scanf("%d", &incremento);
int soma = SomaSerie(inicio, fim, incremento);
printf("Soma da série: %d\n", soma);
return 0;
}
Faça uma função recursiva, em linguagem C, que calcule o valor da série S descrita a seguir para um valor n>0 a ser fornecido como parâmetro para a mesma:
S = 1 + 1/1! + 1/2! + 1/3! + 1 /n!
#include <stdio.h>
double CalcularFatorial(int n) {
if (n == 0) {
return 1;
} else {
return n * CalcularFatorial(n - 1);
}
}
double CalcularSerie(int n) {
if (n == 0) {
return 1;
} else {
return 1.0 / CalcularFatorial(n) + CalcularSerie(n - 1);
}
}
int main() {
int n;
printf("Digite um valor para n: ");
scanf("%d", &n);
double resultado = CalcularSerie(n);
printf("Valor da série S: %.4f\n", resultado);
return 0;
}
Escreva uma função que encontre uma célula de conteúdo mínimo. Faça duas versões: uma iterativa e uma recursiva.
Iterativa
#include <stdio.h>
int encontrarMinimoIterativo(int arr[], int tamanho) {
int minimo = arr[0];
for (int i = 1; i < tamanho; i++) {
if (arr[i] < minimo) {
minimo = arr[i];
}
}
return minimo;
}
int main() {
int arr[] = {5, 3, 9, 1, 7};
int tamanho = sizeof(arr) / sizeof(arr[0]);
int minimo = encontrarMinimoIterativo(arr, tamanho);
printf("O conteúdo mínimo é: %d\n", minimo);
return 0;
}
Recursiva
#include <stdio.h>
int encontrarMinimoRecursivo(int arr[], int inicio, int tamanho) {
if (inicio == tamanho - 1) {
return arr[inicio];
}
int minimoRestante = encontrarMinimoRecursivo(arr, inicio + 1, tamanho);
if (arr[inicio] < minimoRestante) {
return arr[inicio];
} else {
return minimoRestante;
}
}
int main() {
int arr[] = {5, 3, 9, 1, 7};
int tamanho = sizeof(arr) / sizeof(arr[0]);
int minimo = encontrarMinimoRecursivo(arr, 0, tamanho);
printf("O conteúdo mínimo é: %d\n", minimo);
return 0;
}
Escreva uma função que faça uma busca em uma lista crescente. Faça versões recursiva e iterativa
Iterativa
#include <stdio.h>
int buscaIterativa(int lista[], int tamanho, int chave) {
int inicio = 0;
int fim = tamanho - 1;
while (inicio <= fim) {
int meio = (inicio + fim) / 2;
if (lista[meio] == chave) {
return meio; // Chave encontrada
} else if (lista[meio] > chave) {
fim = meio - 1; // Atualiza o índice final para buscar na metade inferior
} else {
inicio = meio + 1; // Atualiza o índice inicial para buscar na metade superior
}
}
return -1; // Chave não encontrada
}
int main() {
int lista[] = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
int tamanho = sizeof(lista) / sizeof(lista[0]);
int chave = 12;
int indice = buscaIterativa(lista, tamanho, chave);
if (indice != -1) {
printf("Chave encontrada no índice: %d\n", indice);
} else {
printf("Chave não encontrada na lista.\n");
}
return 0;
}
Recursiva
#include <stdio.h>
int buscaRecursiva(int lista[], int inicio, int fim, int chave) {
if (inicio > fim) {
return -1; // Chave não encontrada
}
int meio = (inicio + fim) / 2;
if (lista[meio] == chave) {
return meio; // Chave encontrada
} else if (lista[meio] > chave) {
return buscaRecursiva(lista, inicio, meio - 1, chave); // Busca na metade inferior da lista
} else {
return buscaRecursiva(lista, meio + 1, fim, chave); // Busca na metade superior da lista
}
}
int main() {
int lista[] = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
int tamanho = sizeof(lista) / sizeof(lista[0]);
int chave = 12;
int indice = buscaRecursiva(lista, 0, tamanho - 1, chave);
if (indice != -1) {
printf("Chave encontrada no índice: %d\n", indice);
} else {
printf("Chave não encontrada na lista.\n");
}
return 0;
}
Escreva uma função que copie um vetor para uma lista encadeada. Faça duas versões: uma iterativa e uma recursiva.
Iterativa
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
Node* copiarVetorParaListaIterativa(int vetor[], int tamanho) {
Node* head = NULL;
Node* tail = NULL;
for (int i = 0; i < tamanho; i++) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = vetor[i];
newNode->next = NULL;
if (head == NULL) {
head = newNode;
tail = newNode;
} else {
tail->next = newNode;
tail = tail->next;
}
}
return head;
}
void imprimirLista(Node* head) {
Node* current = head;
while (current != NULL) {
printf("%d ", current->data);
current = current->next;
}
printf("\n");
}
void liberarLista(Node* head) {
Node* current = head;
while (current != NULL) {
Node* temp = current;
current = current->next;
free(temp);
}
}
int main() {
int vetor[] = {1, 2, 3, 4, 5};
int tamanho = sizeof(vetor) / sizeof(vetor[0]);
Node* head = copiarVetorParaListaIterativa(vetor, tamanho);
printf("Lista copiada iterativamente: ");
imprimirLista(head);
liberarLista(head);
return 0;
}
Recursiva
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
Node* copiarVetorParaListaRecursiva(int vetor[], int tamanho, int index) {
if (index >= tamanho) {
return NULL;
}
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = vetor[index];
newNode->next = copiarVetorParaListaRecursiva(vetor, tamanho, index + 1);
return newNode;
}
void imprimirLista(Node* head) {
if (head == NULL) {
printf("\n");
return;
}
printf("%d ", head->data);
imprimirLista(head->next);
}
void liberarLista(Node* head) {
if (head == NULL) {
return;
}
liberarLista(head->next);
free(head);
}
int main() {
int vetor[] = {1, 2, 3, 4, 5};
int tamanho = sizeof(vetor) / sizeof(vetor[0]);
Node* head = copiarVetorParaListaRecursiva(vetor, tamanho, 0);
printf("Lista copiada recursivamente: ");
imprimirLista(head);
liberarLista(head);
return 0;
}
Escreva uma função que copie uma lista encadeada para um vetor. Faça duas versões: uma iterativa e uma recursiva.
Iterativa
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
int* copiarListaParaVetorIterativa(Node* head, int tamanho) {
int* vetor = (int*)malloc(sizeof(int) * tamanho);
Node* current = head;
int index = 0;
while (current != NULL) {
vetor[index++] = current->data;
current = current->next;
}
return vetor;
}
void imprimirVetor(int* vetor, int tamanho) {
for (int i = 0; i < tamanho; i++) {
printf("%d ", vetor[i]);
}
printf("\n");
}
void liberarVetor(int* vetor) {
free(vetor);
}
int main() {
Node* head = (Node*)malloc(sizeof(Node));
head->data = 1;
Node* node2 = (Node*)malloc(sizeof(Node));
node2->data = 2;
Node* node3 = (Node*)malloc(sizeof(Node));
node3->data = 3;
head->next = node2;
node2->next = node3;
node3->next = NULL;
int tamanho = 3;
int* vetor = copiarListaParaVetorIterativa(head, tamanho);
printf("Vetor copiado iterativamente: ");
imprimirVetor(vetor, tamanho);
liberarVetor(vetor);
free(node3);
free(node2);
free(head);
return 0;
}
Recursiva
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
int* copiarListaParaVetorRecursiva(Node* head, int tamanho) {
if (head == NULL) {
return NULL;
}
int* vetor = (int*)malloc(sizeof(int) * tamanho);
copiarListaParaVetorRecursivaAux(head, vetor, 0);
return vetor;
}
void copiarListaParaVetorRecursivaAux(Node* current, int* vetor, int index) {
if (current == NULL) {
return;
}
vetor[index] = current->data;
copiarListaParaVetorRecursivaAux(current->next, vetor, index + 1);
}
void imprimirVetor(int* vetor, int tamanho) {
for (int i = 0; i < tamanho; i++) {
printf("%d ", vetor[i]);
}
printf("\n");
}
void liberarVetor(int* vetor) {
free(vetor);
}
int main() {
Node* head = (Node*)malloc(sizeof(Node));
head->data = 1;
Node* node2 = (Node*)malloc(sizeof(Node));
node2->data = 2;
Node* node3 = (Node*)malloc(sizeof(Node));
node3->data = 3;
head->next = node2;
node2->next = node3;
node3->next = NULL;
int tamanho = 3;
int* vetor = copiarListaParaVetorRecursiva(head, tamanho);
printf("Vetor copiado recursivamente: ");
imprimirVetor(vetor, tamanho);
liberarVetor(vetor);
free(node3);
free(node2);
free(head);
return 0;
}
Escreva uma função que inverte a ordem das células de uma lista encadeada (a primeira passa a ser a última, a segunda passa a ser a penúltima etc.). Faça isso sem usar espaço auxiliar; apenas altere os ponteiros. Dê duas soluções: uma iterativa e uma recursiva
Iterativa
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* proximo;
} Node;
void inverterListaIterativa(Node** cabeca) {
Node* anterior = NULL;
Node* atual = *cabeca;
Node* proximo = NULL;
while (atual != NULL) {
proximo = atual->proximo;
atual->proximo = anterior;
anterior = atual;
atual = proximo;
}
*cabeca = anterior;
}
void imprimirLista(Node* cabeca) {
Node* atual = cabeca;
while (atual != NULL) {
printf("%d ", atual->data);
atual = atual->proximo;
}
printf("\n");
}
void liberarLista(Node* cabeca) {
Node* atual = cabeca;
while (atual != NULL) {
Node* temp = atual;
atual = atual->proximo;
free(temp);
}
}
int main() {
Node* cabeca = (Node*)malloc(sizeof(Node));
cabeca->data = 1;
Node* no2 = (Node*)malloc(sizeof(Node));
no2->data = 2;
Node* no3 = (Node*)malloc(sizeof(Node));
no3->data = 3;
cabeca->proximo = no2;
no2->proximo = no3;
no3->proximo = NULL;
printf("Lista original: ");
imprimirLista(cabeca);
inverterListaIterativa(&cabeca);
printf("Lista invertida iterativamente: ");
imprimirLista(cabeca);
liberarLista(cabeca);
return 0;
}
Recursiva
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* proximo;
} Node;
void inverterListaRecursiva(Node** cabeca) {
Node* primeiro = *cabeca;
Node* resto = primeiro->proximo;
if (resto == NULL) {
return;
}
inverterListaRecursiva(&resto);
primeiro->proximo->proximo = primeiro;
primeiro->proximo = NULL;
*cabeca = resto;
}
void imprimirLista(Node* cabeca) {
Node* atual = cabeca;
while (atual != NULL) {
printf("%d ", atual->data);
atual = atual->proximo;
}
printf("\n");
}
void liberarLista(Node* cabeca) {
if (cabeca == NULL) {
return;
}
liberarLista(cabeca->proximo);
free(cabeca);
}
int main() {
Node* cabeca = (Node*)malloc(sizeof(Node));
cabeca->data = 1;
Node* no2 = (Node*)malloc(sizeof(Node));
no2->data = 2;
Node* no3 = (Node*)malloc(sizeof(Node));
no3->data = 3;
cabeca->proximo = no2;
no2->proximo = no3;
no3->proximo = NULL;
printf("Lista original: ");
imprimirLista(cabeca);
inverterListaRecursiva(&cabeca);
printf("Lista invertida recursivamente: ");
imprimirLista(cabeca);
liberarLista(cabeca);
return 0;
}
Digamos que um texto é um vetor de caracteres contendo apenas letras, espaços e sinais de pontuação. Digamos que uma palavra é um segmento maximal de texto que consiste apenas de letras. Escreva uma função que recebe um texto e imprime uma relação de todas as palavras que ocorrem no texto juntamente com o número de ocorrências de cada palavra
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_LENGTH 100
typedef struct {
char palavra[MAX_LENGTH];
int ocorrencias;
} Palavra;
void imprimirPalavras(const Palavra* palavras, int numPalavras) {
printf("Palavras encontradas:\n");
for (int i = 0; i < numPalavras; i++) {
printf("%s: %d ocorrência(s)\n", palavras[i].palavra, palavras[i].ocorrencias);
}
}
int compararPalavras(const void* a, const void* b) {
Palavra* palavraA = (Palavra*)a;
Palavra* palavraB = (Palavra*)b;
return strcmp(palavraA->palavra, palavraB->palavra);
}
void contarPalavras(const char* texto) {
Palavra palavras[MAX_LENGTH];
int numPalavras = 0;
const char* delimiters = " .,;?!"; // delimitadores de palavras
char copiaTexto[MAX_LENGTH];
strcpy(copiaTexto, texto);
char* token = strtok(copiaTexto, delimiters);
while (token != NULL) {
// Verificar se a palavra contém apenas letras
int palavraValida = 1;
for (int i = 0; i < strlen(token); i++) {
if (!isalpha(token[i])) {
palavraValida = 0;
break;
}
}
// Se a palavra for válida, atualizar a contagem
if (palavraValida) {
int palavraEncontrada = 0;
for (int i = 0; i < numPalavras; i++) {
if (strcmp(token, palavras[i].palavra) == 0) {
palavras[i].ocorrencias++;
palavraEncontrada = 1;
break;
}
}
if (!palavraEncontrada) {
strcpy(palavras[numPalavras].palavra, token);
palavras[numPalavras].ocorrencias = 1;
numPalavras++;
}
}
token = strtok(NULL, delimiters);
}
// Ordenar as palavras em ordem alfabética
qsort(palavras, numPalavras, sizeof(Palavra), compararPalavras);
// Imprimir a relação de palavras e ocorrências
imprimirPalavras(palavras, numPalavras);
}
int main() {
const char* texto = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris malesuada consectetur turpis ut gravida. Integer at lobortis nisl, ac tristique erat. Aliquam erat volutpat. Sed id pellentesque est, et consectetur urna. Vivamus gravida dapibus felis a malesuada.";
contarPalavras(texto);
return 0;
}