










Estude fácil! Tem muito documento disponível na Docsity
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
Prepare-se para as provas
Estude fácil! Tem muito documento disponível na Docsity
Prepare-se para as provas com trabalhos de outros alunos como você, aqui na Docsity
Encontra documentos específicos para os exames da tua universidade
Prepare-se com as videoaulas e exercícios resolvidos criados a partir da grade da sua Universidade
Responda perguntas de provas passadas e avalie sua preparação.
Ganhe pontos para baixar
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
Estrutura de Dados
Tipologia: Notas de estudo
1 / 18
Esta página não é visível na pré-visualização
Não perca as partes importantes!











O que é uma Estrutura de Dados (ED)?
? Tipos de Dados ? Estruturas de Dados e ? Tipos Abstratos de Dados
Embora estes termos sejam parecidos, eles têm significados diferentes. Em linguagens de programação, o tipo de dados de uma variável define o conjunto de valores que a variável pode assumir. Por exemplo, uma variável do tipo lógico pode assumir o valor verdadeiro ou falso.
Uma declaração de variável em uma linguagem como C ou Pascal especifica:
Então, tipos de dados podem ser vistos como métodos para interpretar o conteúdo da memória do computador.
Mas podemos ver o conceito de Tipo de Dados de uma outra perspectiva: não em termos do que um computador pode fazer (interpretar os bits...) mas em termos do que os usuários desejam fazer (somar dois inteiros...)
Este conceito de Tipo de Dado divorciado do hardware é chamado Tipo Abstrato de Dado - TAD.
Es trutura de Dados é um método particular de se implementar um TAD.
A implementação de um TAD escolhe uma ED para representá-lo. Cada ED é construída dos tipos primitivos (inteiro, real, char,...) ou dos tipos compostos (array, registro,...) de uma linguagem de programação.
Não importa que tipo de dados estaremos trabalhando, a primeira operação a ser efetuada em um TAD é a criação. Depois, podemos realizar inclusões e remoções de dados. A operação que varre todos os dados armazenados num TAD é o percurso , podendo também ser realizada uma busca por algum valor dentro da estrutura.
Exemplos de TAD:
Lineares:
Não Lineares:
LISTAS
São estruturas formadas por um conjunto de dados de forma a preservar a relação de ordem linear entre eles. Uma lista é composta por nós, os quais podem conter, cada um deles, um dado primitivo ou composto.
Representação:
L 1 L 2 L 3... Ln-1 Ln
Sendo:
L 1? 1º elemento da lista L 2? Sucessor de L 1 Ln-1? Antecessor de Ln- Ln? Último elemento da lista.
Exemplos de Lista:
? Lista Telefônica ? Lista de clientes de uma agência bancária ? Lista de setores de disco a serem acessados por um sistema operacional ? Lista de pacotes a serem transmitidos em um nó de uma rede de computação de pacotes.
Operações Realizadas com Listas:
? Criar uma lista vazia ? Verificar se uma lista está vazia ? Obter o tamanho da uma lista ? Obter/modificar o valor do elemento de uma determinada posição na lista ? Obter a posição de elemento cujo valor é dado ? Inserir um novo elemento após (ou antes) de uma determinada posição na lista ? Remover um elemento de uma determinada posição na lista ? Exibir os elementos de uma lista ? Concatenar duas listas
a) Seqüencial:
Explora a sequencialidade da memória do computador, de tal forma que os nós de uma lista sejam armazenados em endereços sequenciais, ou igualmente distanciados um do outro. Pode ser representado por um vetor na memória principal ou um arquivo seqüencial em disco.
L pato cabra rato anta macaco... 1 2 3 4 5 6 7 MAX
b) Encadeada:
Esta estrutura é tida como uma seqüência de elementos encadeados por ponteiros, ou seja, cada elemento deve conter, além do dado propriamente dito, uma referência para o próximo elemento da lista.
Ex: L = pato, cabra, rato, anta, macaco
pato cabra rato anta macaco
A seguir, apresentaremos a estrutura de dados e as operações básicas sobre listas, implementadas na linguagem C.
Definição da ED:
#define MAX ________ /* tamanho máximo da lista */
typedef ______ telem; /* tipo base dos elementos da lista / typedef struct { telem v[MAX]; / vetor que contém a lista / int n; / posição do último elemento da lista / } tlista; / tipo lista */
n 5 v Pato^ cabra^ rato^ anta^ macaco^... 0 1 2 3 4 5 6 MAX-
Operações simples utilizando lista seqüencial:
1) Criar uma lista vazia
void criar (tlista *L) { L->n = 0; }
2) Verificar se uma lista está vazia
int vazia (tlista L) { return (L.n == 0); }
3) Verificar se uma lista está cheia
int cheia (tlista L) { return (L.n == MAX); }
4) Obter o tamanho de uma lista
int tamanho (tlista L) { return (L.n); }
5) Obter o i-ésimo elemento de uma lista
int elemento (tlista L, int pos, telem *dado) {
/* O parâmetro dado irá receber o elemento encontrado / / Retorna 0 se a posição for inválida. Caso contrário, retorna 1 */
if ( (pos > L.n) || (pos <= 0) ) return (0);
*dado = L.v[pos-1]; return (1); }
6) Pesquisar um dado elemento, retornando a sua posição
int posicao (tlista L, telem dado) {
/* Retorna a posição do elemento ou 0 caso não seja encontrado */
int i;
for (i=1; i<=L.n; i++) if (L.v[i-1] == dado) return (i);
return (0); }
7) Inserção de um elemento em uma determinada posição
Requer o deslocamento à dire ita dos elementos v(i+1)...v(n)
int inserir (tlista *L, int pos, telem dado) {
/* Retorna 0 se a posição for inválida ou se a lista estiver cheia / / Caso contrário, retorna 1 */
int i;
if ( (L->n == MAX)) || (pos > L->n + 1) ) return (0);
for (i=L->n; i>=pos; i--) L->v[i] = L->v[i-1];
L->v[pos-1] = dado; (L->n)++; return (1); }
8) Remoção do elemento de uma determinada posição
Requer o deslocamento à esquerda dos elementos v(p+1)...v(n)
int remover (tlista *L, int pos, telem *dado) {
/* O parâmetro dado irá receber o elemento encontrado / / Retorna 0 se a posição for inválida. Caso contrário, retorna 1 */
int i;
if ( (pos > L->n) || (pos <= 0) ) return (0);
*dado = L->v[pos-1];
for (i=pos; i<=(L->n)-1; i++) L->v[i-1] = L->v[i];
(L->n)--; return (1); }
São listas lineares onde os elementos estão ordenados segundo um critério pré-estabelecido. Na realidade, as listas ordenadas diferem das listas genéricas pelo fato de que cada novo elemento a ser inserido ocupará uma posição específica, obedecendo à ordenação dos valores já existentes.
#define MAX _______ /* tamanho máximo da lista */
typedef _____ telem; /* tipo base dos elementos da lista */
typedef struct { telem v[MAX]; /* vetor que contém a lista / int n; / posição do último elemento da lista / } tlistaord; / tipo lista ordenada */
1) Criar uma lista vazia
void criar (tlistaord *L) { L->n = 0; }
2) Verificar se uma lista está vazia
int vazia (tlistaord L) { return (L.n == 0); }
3) Verificar se uma lista está cheia
int cheia (tlistaord L) { return (L.n == MAX); }
4) Obter o tamanho de uma lista
int tamanho (tlistaord L) { return (L.n); }
5) Obter o i-ésimo elemento de uma lista
int elemento (tlistaord L, int pos, telem dado) { / O parâmetro dado irá receber o elemento encontrado / / Retorna 0 se a posição for inválida. Caso contrário, retorna 1 */
if ( (pos > L.n) || (pos <= 0) ) return (0); *dado = L.v[pos-1]; return (1); }
6) Pesquisar um dado elemento, retornando a sua posição
int posicao (tlistaord L, telem dado) { /* Retorna a posição do elemento ou 0 caso não seja encontrado */
int i;
for (i=1; i<=L.n; i++) if (L.v[i-1] == dado) return (i);
return (0); }
7) Inserção de um elemento dado
int inserir (tlistaord L, telem dado) { / Retorna 0 se a posição for inválida ou se a lista estiver cheia / / Caso contrário, retorna 1 */
int i, pos;
if (L->n == MAX) return (0); /* erro: lista cheia */
for (i=0; i<L->n; i++) { if (L->v[i] == dado) return (0); /* erro: dado já existente */ if (L->v[i] > dado) break; }
pos = i;
for (i=L->n; i>pos; i--) L->v[i] = L->v[i-1];
L->v[i] = dado; (L->n)++;
return (1); }
8) Remoção do elemento de uma determinada posição
int remover (tlistaord *L, int pos, telem dado) { / O parâmetro dado irá receber o elemento encontrado / / Retorna 0 se a posição for inválida. Caso contrário, retorna 1 */
int i;
if ( (pos > L->n)) || (pos <= 0) ) return (0); /* erro: posição inválida */
*dado = L->v[pos-1];
for (i=pos; i<=(L->n)-1; i++) L->v[i-1] = L->v[i];
(L->n)--;
return (1); }
Pilhas são listas onde a inserção de um novo item ou a remoção de um item já existente se dá em uma única extremidade, no topo.
Pilha vazia
Insere (A)
Insere (B)
Retira (B)
Insere (C)
Retira (C)
Retira (A)
Definição:
Dada uma pilha P = ( a(1), a(2), ..., a(n) ), dizemos que a(1) é o elemento da base da pilha; a(n) é o elemento topo da pilha; e a(i+1) está acima de a(i).
Pilhas são também conhecidas como listas LIFO (last in first out).
Operações Associadas:
1. Criar uma pilha P vazia 2. Testar se P está vazia 3. Obter o elemento do topo da pilha (sem eliminar) 4. Inserir um novo elemento no topo de P (empilhar) 5. Remover o elemento do topo de P (desempilhar)
Implementação de Pilhas
Como lista Seqüencial ou Encadeada?
No caso geral de listas ordenadas, a maior vantagem da alocação encadeada sobre a seqüencial - se a memória não for problema - é a eliminação de deslocamentos na inserção ou eliminação dos elementos. No caso das pilhas, essas operações de deslocamento não ocorrem.
Portanto, podemos dizer que a alocação sequencial é mais vantajosa na maioria das vezes.
Exemplo do Uso de Pilhas
Chamadas de procedimentos
Suponha a seguinte situação:
Quando o procedimento A1 é executado, ele efetua uma chamada a A2, que deve carregar consigo o endereço de retorno e1. Ao término de A2, o processamento deve retornar ao A1, no devido endereço. Situação idêntica ocorre em A2 e A3.
Assim, quando um procedimento termina, é o seu endereço de retorno que deve ser consultado. Portanto, há uma lista implícita de endereços (e0, e1, e2, e3) que deve ser manipulada como uma pilha pelo sistema, onde e0 é o endereço de retorno de A1.
No caso de processamento recursivo - por exemplo uma chamada a A2 dentro de A4 - o gerenciamento da lista como uma pilha resolve automaticamente a obtenção dos endereços de retorno na ordem apropriada (e0, e1, e2, e3, e4).
Definição da Estrutura de Dados:
#define MAX 10
typedef int telem;
typedef struct { telem v[MAX]; int topo; } tpilha;
a) crie uma pilha P; b) exiba o seguinte menu de opções:
c) leia a opção do usuário; d) execute a opção escolhida pelo usuário; e) após a execução de cada opção, o programa deve retornar ao menu para nova opção do usuário ou o encerramento do programa (através da tecla ESC).
É uma lista linear em que a inserção é feita numa extremidade e a eliminação na outra. Conhecida com estrutura FIFO ( First In , First Out ).
( a1, a2 , ... , an ) eliminações inserções no início no final
Exemplos:
? Escalonamento de "Jobs": fila de processos aguardando os recursos do sistema operacional. ? Fila de pacotes a serem transmitidos numa rede de comutação de pacotes. ? Simulação: fila de caixa em banco.
Operações associadas:
Implementação de Filas
Como lista Seqüencial ou Encadeada?
Pelas suas características, as filas têm as eliminações feitas no seu início e as inserções feitas no seu final. A implementação encadeada dinâmica torna mais simples as operações (usando uma lista de duas cabeças). Já a implementação seqüencial é um pouco mais complexa (teremos que usar o conceito de fila circular), mas pode ser usada quando há previsão do tamanho máximo da fila.
Definição da Estrutura de Dados:
Devido a sua estrutura, será necessária a utilização de dois campos que armazenarão os índices do início e do final da fila e um vetor de elementos (onde serão armazenados os dados) com tamanho pré-estabelecido.
#define MAX ______ /* tamanho máximo da fila */
typedef _____ telem; /* tipo base dos elementos da fila */
typedef struct{
telem v[MAX]; int inicio; /* posição do primeiro elemento / int final; / posição do último elemento */
} tfila;
Problema na implementação seqüencial
O que acontece com a fila considerando a seguinte seqüência de operações sobre um fila:
(I - inserção e E - eliminação)
Note que a fila vai se deslocando da esquerda para a direita do vetor. Chegará a condição de "overflow" (cheia), porém estando vazia, ou seja, sem nenhum elemento.
Alternativa:
No algoritmo de remoção, após a atualização de inicio , verificar se a fila ficou vazia. Se este for o caso, reinicializar inicio = 0 e final = -
Portanto, ficaria:
int remover (tfila *F, telem *valor) {
if (vazia(F)) return 0; / Erro: fila vazia */
primeiro(*F,valor); (F->inicio)++;
if (vazia(*F)) { F->inicio = 0; F->final = -1; }
return(1); }
O que aconteceria se a seqüência fosse:
A lista estaria com no máximo dois elementos, mas ainda ocorreria overflow com a lista quase vazia.
Alternativa:
Forçar final a usar o espaço liberado por inicio ( Fila Circular )
Para permitir a reutilização das posições já ocupadas, usa-se o conceito de "Fila Circular". Precisamos de um novo componente para indicar quantos elementos existem na fila, no momento.
A estrutura de dados com o novo componente ficaria assim representada:
#define MAX ______ /* tamanho máximo da fila */
typedef _____ telem; /* tipo base dos elementos da fila */
typedef struct{ telem v[MAX]; int inicio; /* posição do primeiro elemento / int final; / posição do último elemento / int tam; / número de elementos da fila */ } tfila;
As operações são agora executadas assim:
1. Criar - cria uma fila vazia
void criar (tfila *F) { F->inicio = 0; F->final = -1; F->tam = 0; }
2. Vazia - testa se uma fila está vazia
int vazia (tfila F) { return (F.tam == 0); }
3. Primeiro - obtém o elemento do início da fila
int primeiro (tfila F, telem dado) { if (vazia(F)) return 0; / Erro: fila vazia */
*dado = F.v[F.inicio];
return (1); }
4. Inserir - insere um elemento no fim de uma fila
int inserir (tfila *F, telem valor) { if (F->tam == MAX) return 0;
(F->tam)++; F->final = (F->final + 1) % MAX; F->v[F->final] = valor;
return(1); }
5. Remover - remove o elemento do início de uma fila, retornando o elemento removido
int remover (tfila F, telem valor) { if (vazia(F)) return 0; / Erro: fila vazia */
primeiro(*F,valor); (F->tam)--; F->inicio = (F->inicio + 1) % MAX;
return(1); }