Docsity
Docsity

Prepare-se para as provas
Prepare-se para as provas

Estude fácil! Tem muito documento disponível na Docsity


Ganhe pontos para baixar
Ganhe pontos para baixar

Ganhe pontos ajudando outros esrudantes ou compre um plano Premium


Guias e Dicas
Guias e Dicas

LISTA DE EXERCICIOS LINGUAGEM C, Exercícios de Programação em C

SEGUE LISTA DE EXERCIO EM LINGUAGEM DE PROGRAMAÇÃO C.

Tipologia: Exercícios

2022

Compartilhado em 30/03/2022

otimize-engenharia
otimize-engenharia 🇧🇷

5 documentos

1 / 13

Toggle sidebar

Esta página não é visível na pré-visualização

Não perca as partes importantes!

bg1
Universidade Federal de Minas Gerais
Departamento de Ciência da Computação
Algoritmos e Estruturas de Dados II (Turmas M, N, W, F)
1º Semestre de 2012
Profs. Camilo Oliveira, Gisele Pappa, Ítalo Cunha, Loïc Cerf, William Schwartz
2ª Lista de Exercícios
1. Utilizando a implementação de listas com alocação sequencial (arranjos), implemente um procedimento
para inserir um item em uma determinada posição da lista. Qual é a ordem de complexidade do seu
procedimento?
#define MaxTam 1000
typedef int Apontador;
typedef struct {
/* dados */
} TipoItem;
typedef struct {
TipoItem Item[MaxTam];
Apontador Primeiro, Ultimo;
} TipoLista;
void Insere(TipoLista *lista, TipoItem dado, int posicao) {
int i;
if (lista->Ultimo >= MaxTam) {
printf(“Lista está cheia\n”);
}
else {
for (i = lista->Ultimo; i >= posicao; i--)
lista->Item[i] = lista->Item[i-1];
lista->Item[posição] = dado;
}
}
A complexidade é O(MaxTam).
2. Um problema que surge com frequência na manipulação de listas lineares implementadas através de
apontadores é “andar para trás” na lista, ou seja, percorrê-la no sentido inverso dos apontadores. Uma
solução para isso é implementar uma lista duplamente encadeada, em que cada célula também possui um
apontador para a sua antecessora, como mostrado na figura abaixo:
pf3
pf4
pf5
pf8
pf9
pfa
pfd

Pré-visualização parcial do texto

Baixe LISTA DE EXERCICIOS LINGUAGEM C e outras Exercícios em PDF para Programação em C, somente na Docsity!

Universidade Federal de Minas Gerais Departamento de Ciência da Computação Algoritmos e Estruturas de Dados II (Turmas M, N, W, F) 1º Semestre de 2012 Profs. Camilo Oliveira, Gisele Pappa, Ítalo Cunha, Loïc Cerf, William Schwartz

2ª Lista de Exercícios

1. Utilizando a implementação de listas com alocação sequencial (arranjos), implemente um procedimento

para inserir um item em uma determinada posição da lista. Qual é a ordem de complexidade do seu

procedimento?

#define MaxTam 1000

typedef int Apontador;

typedef struct {

/* dados */

} TipoItem;

typedef struct {

TipoItem Item[MaxTam];

Apontador Primeiro, Ultimo;

} TipoLista;

void Insere (TipoLista *lista, TipoItem dado, int posicao) {

int i;

if (lista->Ultimo >= MaxTam) {

printf(“Lista está cheia\n”);

else {

for (i = lista->Ultimo; i >= posicao; i--)

lista->Item[i] = lista->Item[i-1];

lista->Item[posição] = dado;

A complexidade é O(MaxTam).

2. Um problema que surge com frequência na manipulação de listas lineares implementadas através de

apontadores é “andar para trás” na lista, ou seja, percorrê-la no sentido inverso dos apontadores. Uma

solução para isso é implementar uma lista duplamente encadeada, em que cada célula também possui um

apontador para a sua antecessora, como mostrado na figura abaixo:

a) Declare os tipos necessários para a implementação dessa lista

b) Escreva um procedimento para retirar uma célula apontada por um apontador p

c) Escreva um procedimento para inserir um elemento na primeira posição da lista (logo após a célula

cabeça).

struct lista {

struct no *cabeca;

struct no *ultimo;

struct no {

struct no *ante;

struct no *prox;

int dado;

int remove_elemento(struct lista *L, struct no *P)

struct no *ante = P->ante;

struct no *prox = P->prox;

ante->prox = prox; /* ante != NULL por causa do cabeca */

if(prox != NULL) { prox->ante = ante; }

if(L->ultimo == P) { L->ultimo = ante; }

int dado = P->dado;

free(P);

return dado;

void insere_inicio(struct lista *L, int i)

struct no *primeiro = L->cabeca->prox;

struct no *novo = malloc(sizeof(struct no));

if(novo == NULL) { perror(NULL); exit(EXIT_FAILURE); }

L->cabeca->prox = novo;

if(primeiro != NULL) { primeiro->ante = novo; }

novo->ante = L->cabeca;

novo->prox = primeiro;

novo->dado = i;

if(L->ultimo == L->cabeca) { L->ultimo = novo; }

3. Considere uma pilha P vazia e uma fila F não vazia. Utilizando apenas os testes de fila e pilha vazias, as

operações Enfileira , Desenfileira , Empilha , Desempilha , e uma variável aux do TipoItem , escreva um

programa que inverte a ordem dos elementos da fila.

/* void Troca(struct lista *L, struct no *P) ou */ void Troca(TipoLista *L, Apondador *P) { struct no *ante; struct no prox = P->prox; if(prox == NULL) { return; } / impossível trocar posições. / ante = L->cabeca; while(ante->prox != P) { ante = ante->prox; } / ante é o nó anterior ao nó P */ ante->prox = prox; P->prox = prox->prox; prox->prox = P; if(L->ultimo == prox) { L->ultimo = ante; } }

5. Utilizando as operações de manipulação de pilhas vistas em sala, uma pilha auxiliar e uma variável do tipo

TipoItem, escreva um procedimento que remove um item com chave c de uma posição qualquer de uma

pilha. Note que você não tem acesso à estrutura interna da pilha (topo, item, etc), apenas às operações de

manipulação.

typedef struct {

TipoChave chave;

/* dados */

} TipoItem;

void RemoveChaveC (TipoPilha *pilha, TipoChave c) {

TipoPilha *pilha2;

TipoItem aux;

pilha2 = (TipoPilha *) malloc(sizeof(TipoPilha));

FPVazia(pilha2);

while (Vazia(pilha) == 0) {

aux = Desempilha(pilha);

if (aux.chave != c)

Empilha(aux, pilha2);

else

break;

while (Vazia(pilha2) == 0)

Empilha(Desempilha(pilha2), pilha);

6. Escreva dois procedimentos (um usando a implementação por arranjos (alocação sequencial) e outro

usando a implementação por apontadores) para remover de uma lista encadeada um elemento com uma

chave específica (passada como parâmetro): Remove(TipoLista *Lista, TipoChave c). Qual é a ordem de

complexidade dos seus procedimentos?

Implementação para lista de inteiros:

#define MAX_ELEMENTOS 65535 struct lista_arranjo { int dados[MAX_ELEMENTOS]; int ultimo; }; int remove_elemento_arranjo(struct lista_arranjo L, int dado) { int i; int j; for(i = 0; i < L->ultimo && L->dados[i] != chave; i++); / se o dado está na lista, i contém o índice do elemento a

  • remover. se o dado não está na lista, i == L->ultimo. / if(i == L->ultimo) { return 0; } else { / o dado está no elemento no índice i, que vamos remover: */ while(i < L->ultimo - 1) { L->dados[i] = L->dados[i+1]; i++; } return 1; } }

Esta função possui complexidade O(N) no melhor e no pior caso, onde N é o número de elementos na lista.

struct lista_encadeada { struct no *cabeca; struct no *ultimo; }; struct no { struct no *ante; struct no *prox; int dado; }

int remove_elemento_arranjo(struct lista_arranjo *L, int chave) { int i; int j; for(i = 0; i < L->ultimo && L->dados[i] .chave != chave; i++); if(i == L->ultimo) { return 0; } else { while(i < L->ultimo - 1) { L->dados[i] = L->dados[i+1]; i++; } return 1; } }

Esta função possui complexidade O(N) no melhor e no pior caso, onde N é o número de elementos na lista.

struct lista_encadeada { struct no *cabeca; struct no *ultimo; }; struct no { struct no *ante; struct no prox; / prox e ante são ponteiros, acessamos com seta (->) / struct item dado; / note que dado não é ponteiro, então acessamos com ponto (.) */ } int remove_elemento_encadeado(struct lista_encadeada *L, int chave) { struct no *ante; ante = L->cabeca; while(ante->prox && ante->prox->dado .chave != chave) { ante = ante->prox; } if(ante->prox == NULL) { return 0; } else { struct no *prox = ante->prox; if(L->ultimo == prox) { L->ultimo = ante; } ante->prox = prox->prox; free(prox); return 1; } }

Esta função possui complexidade O(1) no melhor caso (dado está no primeiro elemento da lista) e O(N) no pior caso

(dado está no último elemento da lista), onde N é o número de elementos na lista.

Implementação para listas de itens que contém estruturas que armazenam chaves e dados usando typedef :

A implementação a seguir é similar à anterior, porém definimos um tipo para a chave e outro tipo para os items. Isto

torna mais fácil mudar o tipo da chave que identifica os itens na lista.

#define MAX_ELEMENTOS 65535 typedef int TipoChave; struct item { TipoChave chave; /* campos de dados. por exemplo: char nome[80]; int telefone; etc */ };

typedef struct item TipoItem; struct lista_arranjo { TipoItem dados[MAX_ELEMENTOS]; int ultimo; }; int remove_elemento_arranjo(struct lista_arranjo *L, TipoChave chave) { int i; int j; for(i = 0; i < L->ultimo && L->dados[i].chave != chave; i++); if(i == L->ultimo) { return 0; } else { while(i < L->ultimo - 1) { L->dados[i] = L->dados[i+1]; i++; } return 1; } }

Esta função possui complexidade O(N) no melhor e no pior caso, onde N é o número de elementos na lista.

struct lista_encadeada { struct no *cabeca; struct no *ultimo; }; struct no { struct no *ante; struct no *prox; TipoItem dado; } int remove_elemento_encadeado(struct lista_encadeada *L, TipoChave chave) { struct no *ante; ante = L->cabeca; while(ante->prox && ante->prox->dado.chave != chave) { ante = ante->prox; } if(ante->prox == NULL) { return 0; } else { struct no *prox = ante->prox; if(L->ultimo == prox) { L->ultimo = ante; } ante->prox = prox->prox; free(prox); return 1; } }

Esta função possui complexidade O(1) no melhor caso (dado está no primeiro elemento da lista) e O(N) no pior caso

(dado está no último elemento da lista), onde N é o número de elementos na lista.

Implementação genérica usando ponteiro para void :

A implementação genérica usando ponteiro para void é similar às anteriores.

A diferença é que o compilador não sabe comparar elementos do tipo void, então precisamos informar ao compilador

como comprar nossos elementos. Fazemos isso passando para a função de remover elementos uma outra função para

int remove_elemento_encadeado(struct lista_encadeada *L, *void ** chave, *int (compara_items)(void i1, void i2) ) { struct no *ante; ante = L->cabeca; while(ante->prox && compara_items(ante->prox->chave, chave) ) { ante = ante->prox; } if(ante->prox == NULL) { return 0; } else { struct no *prox = ante->prox; if(L->ultimo == prox) { L->ultimo = ante; } ante->prox = prox->prox; free(prox); return 1; } }

Esta função possui complexidade O(1) no melhor caso (dado está no primeiro elemento da lista) e O(N) no pior caso

(dado está no último elemento da lista), onde N é o número de elementos na lista.

7. Considere a implementação de filas usando arranjos “circulares” (alocação sequencial). Escreva um

procedimento FuraFila(TipoFila *fila, TipoItem x) que insere um item na primeira posição da fila. O detalhe

é que seu procedimento deve ser O(1) , ou seja, não pode movimentar os outros itens da fila.

#define MaxTam 1000

typedef int Apontador;

typedef struct {

TipoItem Item[MaxTam];

Apontador Frente, Tras;

} TipoFila;

void FuraFila (TipoFila *fila, TipoItem x) {

fila->Frente--;

if (fila->Frente < 0)

fila->Frente = MaxTam-1;

fila->Item[fila->Frente] = x;

8. Expresse as seguintes equações usando árvores. Cada operador deve ser nó interno que terá os operadores

como filhos. Por exemplo, a equação 2(a-b/c) é representada pela seguinte árvore:

a) a + b + 5c

b) 7a/c - c

c)

Note que os operadores de subtração, divisão e exponenciação (seta para cima) não são associativos. Nesses

operadores, a ordem dos filhos é relevante.

struct arvore {

struct arvore *pai;

struct arvore *esquerda;

struct arvore *direita;

int dado;

void insere (struct arvore *raiz, int *dado) {

if(*dado < raiz->dado) {

if (raiz->esq) {

insere_elemento(raiz->esq, dado);

else { /* achou local de inserção */

struct arvore *novo = cria_arvore();

novo->dado = *dado;

raiz->esq = novo;

novo->pai = raiz;

} else if(*dado > raiz->dado) {

if(raiz->dir) {

insere_elemento(raiz->dir, dado);

else {

struct arvore *novo = cria_arvore();

novo->dado = *dado;

raiz->dir = novo;

novo->pai = raiz;

} else {

printf(“elemento já existe na árvore\n”);

struct arvore *cria_arvore(void) {

struct arvore *novo;

novo = malloc(sizeof(struct arvore));

novo->esq = NULL;

novo->dir = NULL;

novo->pai = NULL;

novo->dado = 0;