Buscar

apostila estruturas parte1

Prévia do material em texto

Ponteiros
Ponteiro é uma variável que guarda (aponta para) um endereço de memória onde é 
possível o armazenamento de um valor de acordo com o tipo especificado na sua 
declaração.
A memória de um computador é identificada por células que são regiões onde 
valores podem ser armazenados.
Células de memória – Porções da memória principal do computador. Estas células são 
endereçadas.
OBS: Os endereços representados são apenas exemplos, não refletem uma situação real.
Com o software DDD você pode ver o endereço real de uma variável utilizada em seu 
programa, basta colocar o cursor do mouse sobre a variável e observar seu endereço no 
rodapé da ferramenta.
Operadores utilizados em ponteiros
A linguagem C++ utiliza dois operadores básicos para manipulação de ponteiros, * 
e &.
* É utilizado para declaração de variável ponteiro e também para acesso ao conteúdo de 
um endereço de memória apontado por um ponteiro.
& É utilizado para representar um endereço de memória de uma variável
OBS..: Em C++, o operador * (asterisco) é também utilizado como operador aritmético de 
multiplicação, portanto tenha muito cuidado ao utilizá-lo.
A forma correta de declaração de variável ponteiro é:
<tipo-de-dado> * <nome-da-variável>
int * a;
float * b;
char * str;
Veja que é necessário informar de qual o tipo será o ponteiro. 
De acordo com esta informação é possível declarar um ponteiro a partir de qualquer 
tipo pré-definido da linguagem e de qualquer tipo de dados criado pelo programador.
Quando ocorre a declaração destas duas variáveis, elas apontam para endereços de 
memória.
Exemplo:
#include<iostream>
using namespace std;
int main(void)
{ 
 int * a, *b;
 a = new int;
 b = new int;
 *a = 10;
 *b = 50;
 return(0);
}
Observe:
- As instruções a = new int; e b = new int; reference a alocação de memória para os 
ponteiros a e b antes que eles recebam valores.
- As instruções *a = 10 e *b = 50, significam que no endereço apontado pelo ponteiro a o 
valor 10 será inserido e no endereço apontado por b o valor 50. 
*a=10; - Conteúdo de a é 10 (posição de memória apontada por a recebe o valor 10)
*b=50; - Conteúdo de b é 50 (posição de memória apontada por b recebe o valor 50)
Exemplo:
#include<iostream>
using namespace std;
int main(void)
{ 
 int * a, b;
 a = new int;
 *a = 10;
 b = *a; 
 return(0);
}
A variável a é um ponteiro que aponta para um endereço de memória qualquer e b 
não aponta por não se tratar de um ponteiro, e sim uma variável comum.
A linha de instrução *a =10, diz que o conteúdo do endereço apontado por a recebe 
o valor 10.
A linha b = * 10, diz que o conteúdo do endereço apontado por a (valor 10) será 
copiado para a variável b, que não é ponteiro.
#include<iostream>
using namespace std;
int main(void)
{ 
 int * a, *b;
 a = new int;
 b = new int;
 *a = 10;
 *b = *a; 
 return(0);
}
Neste exemplo, o conteúdo do endereço apontado por a (valor 10), é copiado para o 
endereço apontado pelo ponteiro b. Neste caso, as duas também permanecem com o mesmo 
valor.
#include<iostream>
using namespace std;
int main(void)
{ 
 int * a, *b;
 a = new int;
 b = new int;
 *a = 10;
 b = a; 
 *b = 50;
 return(0);
}
Para entender melhor o que ocorre com este programa, vamos analisá-lo passo a 
passo:
1)
int *a, *b; - Declaração de dois ponteiro tipo inteiro. Ambos apontam para endereços de 
memória.
2) 
a = new int;
b = new int;
Alocação de memória para os ponteiros a e b
3)
*a = 10; - O endereço apontado pelo ponteiro a será preenchido com um valor inteiro 10.
4)
 b = a; - O ponteiro b deixa de apontar para seu endereço especificado na figura acima e 
passa a apontar para o endereço de a.
5) *b = 50; - O endereço apontado pelo ponteiro b recebe o valor 50. Observe que o valor 
10 que existe no endereço apontado por a foi substituído por 50. Isso ocorreu porque o 
ponteiro b está apontando para o mesmo endereço que o ponteiro a.
#include<iostream>
using namespace std;
int main(void)
{ 
 int * a, b;
 b = 10;
 a = &b;
 *a = 50;
return(0);
}
OBS: Observe que neste caso não foi necessário alocar memória para o ponteiro a, pois ele 
foi utilizado para apontar para a variável b.
O ponteiro a não recebeu diretamente um valor, por isso não foi necessário a alocação de 
memória para ele.
1) int * a, b; - Declaração de uma variável ponteiro a e uma variável (não ponteiro) b;
Observe que a variável b não é ponteiro, portanto não aponta para nenhum endereço na 
memória. Mesmo não apontando, toda variável é representada por um endereço.
2) b = 10; - A variável b recebe um valor inteiro 10.
3) a = &b; - O ponteiro a aponta para o endereço da variável b
O & é utilizado para passar ao ponteiro a o endereço da variável b. Ele é necessário porque 
b não é ponteiro. A partir desta linha de código, tudo que for feito através do ponteiro a, 
afetará a variável b.
4) *a = 50; - Endereço apontado pelo ponteiro a receberá o valor 50.
#include<iostream>
using namespace std;
struct dados
{
 char nome[30];
 int idade;
};
int main(void)
{
 dados * pessoa; //Declaração do ponteiro pessoa do tipo dados
 pessoa = new dados; //Alocação de memória para o ponteiro pessoa
return(0);
}
A variável pessoa é um ponteiro do tipo dados (struct).
Observe como fica a representação na memória:
É possível também a utilização de ponteiros a partir de tipos de dados que não são 
primitivos (int, float, char, double e void). Utilizamos neste exemplo um tipo de dado 
criado pelo programador com o nome “dado”. Para fazer isso foi utilizado o struct.
Passagem de parâmetros para função por valor e por ponteiro
Passagem de parâmetros por valor
#include<iostream>
using namespace std;
void soma(int, int);
int main(void)
{
 int a = 10, b = 20;
 soma(a,b);
return(0);
}
void soma(int x, int y)
{
 cout<<“\nSoma = “<< x+y;
}
1) int a=10, b= 20; - Declaração e inicialização de duas variáveis inteiras: a e b
As variáveis a e b são locais, ou seja, só são válidas apenas dentro do escopo do programa 
principal, onde foram declaradas.
2) soma(a,b); - Chamada da função soma, passando como parâmetro dois valores inteiros
através das variáveis a e b.
 
As variáveis x e y recebem os valores de a e b. Qualquer alteração realizada com as 
variáveis x e y não afetarão as variáveis a e b.
Cópias dos valores de a e b são passadas para as variáveis x e y.
#include<iostream>
using namespace std;
void dados(int , int );
int main(void)
{
 int a = 10, b = 20;
 dados(a,b);
 return(0);
}
void dados(int x, int y)
{
 x = 50;
 y = 70;
 }
1) int a=10, b=20;
Declaração de duas variáveis no programa principal e também inicialização com 
valores inteiros 10 e 20. Estas variáveis são válidas dentro desta função, caso seja 
necessário utilizar seus valores dentro de uma outra função, é preciso passá-las como 
parâmetro.
3) dados(a,b); - Chamada da função dados, passando os valores de a e b por valor.
Os valores de a e b são passados para x e y. Qualquer alteração em x e y não 
afetarão a e b.
4)
 void dados(int x, int y)
{
 x = 50;
 y = 70;
 }
Corpo da função dados e alteração dos valores 10 e 20 existentes em x e y, 
conforme figura do item 3.
Quando a execução dos códigos da função terminar e retornar ao programa 
principal, os valores de a e b permanecerão os mesmos, ou seja, 10 e 20. Isto acontecedevido a passagem de parâmetro ser por valor.
Passagem de parâmetros por ponteiro
#include<iostream>
using namespace std;
void dados(int *, int *);
int main(void)
{
 int a = 10, b = 20;
 dados(&a,&b);
}
void dados(int * x, int * y)
{
 *x = 50;
 *y = 70;
 }
1) int a = 10, b = 20; - Declaração de duas variáveis inteiras e atribuição dos valores 10 e 
20
2) dados(&a, &b); - Chamada da função dados passando o endereço de a e b
 (&a, &b). Isto ocorre porque a função foi construída utilizando ponteiros em seus 
argumentos:
dados(int *x, int *y)
Os endereços de a e b (&a , &b) foram passados para os ponteiros x e y que a partir 
deste momento apontam eles.
3)
 void dados(int * x, int * y)
{
 *x = 50;
 *y = 70;
 }
Observe que ao se tratar do conteúdo dos ponteiros x e y, na verdade as variáveis a e 
b são afetadas, pois x e y apontam para elas. 
Ao término da função dados e retorno ao programa principal os valores de a e b 
estarão modificados.
Programação modular
A modularização de programas é um método utilizado para facilitar a construção de 
grandes programas, através de sua divisão em pequenas partes, ou seja, módulos. 
Modularizar um programa significa dividi-lo em partes, ou seja, em arquivos 
distintos. Cada arquivo conterá parte do código que será compilado e ligado, formando um 
único código executável.
Se todos os módulos serão ligados novamente, então surge a pergunta:
- Por que dividi-los???
A resposta para isso é simples:
São várias as razões para dividir um código fonte em partes:
1ª – Organização: Cada módulo de programa tem como conteúdo códigos referentes 
a um conjunto de ações ou atividades;
2ª – Clareza na implementação: A escrita e a leitura de códigos em módulos é muito 
mais fácil, principalmente no processo de correção de defeitos;
3ª – Facilidade na manutenção dos programas: Com módulos, encontrar erros em 
programas torna-se um processo menos trabalhoso;
4ª – Tempo de compilação: O processo de compilação pode ser algo que demande 
muito tempo em programas grandes. Quando erros são encontrados e arrumados, 
apenas os módulos alterados sofrerão nova compilação, diminuindo bastante o 
tempo gasto na compilação. No caso de um programa que não é dividido em 
módulos, qualquer alteração realizada no código fonte exigirá toda a compilação do 
sistema, ocasionando esperas desnecessárias.
Ex:
Arquivo: DADOS.H
struct dados
{
 char nome[50];
 char endereco[50];
 float salario;
};
void cadastrar(void);
void imprimir(void);
Observe que neste arquivo encontram-se apenas as definições de um tipo de dado chamado 
dados e dois protótipos de funções que serão utilizadas para manipular os dados.
NÃO HÁ IMPLEMENTAÇÃO DE CÓDIGO NO ARQUIVO DADOS.H, APENAS 
DEFINIÇÕES
Arquivo: DADOS.CPP
#include”dados.h”
#include<iostream>
using namespace std;
extern dados pessoa;
void cadastrar(void)
{
 cout<<”\nInforme o nome:”;
 cin>>pessoa.nome;
 cout<<”\nInforme o endereco:”;
 cin>>pessoa.endereco;
 cout<<”\nInforme o salario:”;
 cin>>pessoa.salario;
}
void imprimir(void)
{
 cout<<”\nNome :”<<pessoa.nome;
 cout<<”\nEndereco:”<<pessoa.endereco;
 cout<<”\nSalario:”<<pessoa.salario;
}
Observe que neste arquivo encontram-se os códigos das funções definidas no arquivo 
DADOS.H.
ESTE ARQUIVO É UTILIZADO PARA O DESENVOLVIMENTO DAS FUNÇÕES 
DEFINIDAS NO ARQUIVO DADOS.H E UTILIZAÇÃO DO STRUC
Arquivo: PRINCIPAL.CPP
#include”dados.h”
#include<iostream>
using namespace std;
dados pessoa;
int main(void)
{
 cadastrar();
 imprimir();
 return(0);
}
Neste arquivo desenvolvemos o programa principal que será utilizado para a chamada das 
funções definidas no arquivo DADOS.H e implementadas no arquivo DADOS.CPP.
Para compilar:
g++ -g –o executável dados.cpp principal.cpp
OBS: -g : Opção utilizada na compilação para geração do binário com opção de depuração
 -o : Opção utilizada para geração dos códigos objetos e executável
 Executável: Nome dado ao código executável que será gerado
 dados.cpp: Arquivo fonte
 principal.cpp: Arquivo fonte
Estruturas de dados
Introdução
Quando um software é desenvolvido, duas coisas importantes devem ser levadas em 
consideração, os dados e os procedimentos utilizados para manipulá-los.
- Dados: Informações que o software utilizará para resolver um determinado problema
- Procedimentos: Como estes dados serão manipulados.
Quanto mais um projeto de software evolui, maior será a preocupação com estes 
dois itens.
Tipos de dados
Para que o computador possa trabalhar com dados, ele deve ser informado desse 
fato. Isso que dizer que antes de qualquer participação do usuário na iteratividade homem-
máquina, ela deve ser preparada para isso.
As declarações de variáveis dentro de um programa, são utilizadas com o intuito de 
preparar a memória da máquina para o armazenamento de informações. O tipo de valor a 
ser inserido na memória equivale ao tipo de dado permitido. Portanto, tipo de dado é o 
formato da informação a ser inserida na memória do computador.
Exemplo:
int a; - Declaração de uma variável do tipo inteiro. A memória está sendo informada que 
uma variável será utilizada para armazenamento de valores inteiros.
Valores inteiros..: 1, 10, -100, -65, 1100, etc...
float a; - Declaração de uma variável do tipo real. A memória está sendo informada que 
uma variável será utilizada para armazenamento de valores reais.
Valores reais..: -12.34, 12.00, 34.00, 89.68, 100.00, -234.56, etc....
char c; - Declaração de uma variável do tipo caractere. A memória está sendo informada 
que uma variável será utilizada para armazenamento de caracteres.
Caracteres..: a, A, b, 1, 3, #, +, -, /, etc....
Tipos de dados primitivos
São tipos de dados já existentes em uma linguagem de programação, como int, float, 
char, dentre outros. 
A partir dos tipos primitivos podemos criar outros tipos de dados.
São considerados tipos primitivos:
- números inteiros
- números reais
- caracteres
A cada um destes tipos primitivos, um conjunto de valores pode ser atribuído e 
operações realizadas.
Exemplos de valores já foram apresentados anteriormente, observe agora as 
operações que podem ser realizadas com os tipos primitivos:
- Inteiros: soma, subtração, multiplicação, divisão e resto.
- Real: soma, subtração, multiplicação, divisão.
- Caractere: Igualdade, diferença e concatenação.
- Ponteiro: Representação de endereços de memória
Tipos de dados abstratos
Conforme apresentado anteriormente, os dados manipulados em um programa são 
informações processadas com o propósito de apresentar a solução de um problema, o que 
vai depender de como o software foi projetado. Os tipos de dados primitivos dizem como 
os dados serão armazenados e não como serão manipulados. Para fazer isso, é necessário 
que o programador crie tipos de dados novos (abstratos), baseando-se nos tipos já existente 
e que ofereça funções para sua utilização.
Portanto, um TAD possui duas partes:
- Especificação
- Implementação
Exemplo de um TAD:
struct dados
{
 char nome[30];
 int idade;
}pessoa;
void cadastrar(void)
{
 cout<<“\nDigite nome..:”; 
 cin>>pessoa.nome;
 cout<<“\nDigite idade..:”;
 cin>>pessoa.idade;
}
void imprime(void)
{
 cout<<“\nNome..:”<<pessoa.nome;
 cout<<“\nDigite idade..:”<<pessoa.idade;
}
Todo este código representa um TAD. Você pode observar que foi criado um 
registro contendo informações relacionadas,com o propósito de guardar dados de uma 
pessoa. Em seguida foram implementadas funções para manipulação dos dados abstraídos 
do problema e inseridos no registro (struct dados).
Estrutura de dados
O computador é uma máquina que foi projetada para processamento de 
informações, com o propósito de facilitar a vida das pessoas. 
Com a necessidade de todos pela computação, os programas existentes são os mais 
diversos e também os mais complexos. Já imaginou se no desenvolvimento destes 
programas não existissem técnicas de organização, manipulação e utilização dos dados? 
Teríamos grandes problemas, pois os programas não seriam eficientes e tudo seria um caos.
Portanto:
Estruturas de dados são conceitos e técnicas desenvolvidas para organização e 
manipulação de dados.
Pilha utilizando vetores
Apesar de ser uma forma bastante simples de organização e manipulação de dados, 
esta estrutura tem papel fundamental em diversas áreas da computação, como a construção 
de linguagens de programação, compiladores, sistemas operacionais, etc.
O processo de ordenação e acesso aos dados utilizado em pilha segue o princípio 
onde o caminho de entrada de dados na estrutura é o mesmo utilizado para retirada, ou seja, 
LIFO – Last In First Out – Último que entra é o primeiro a sair.
Para entender melhor pense em uma pilha de pratos ou de livros.
Eles foram colocados uns sobre os outros, seguindo sempre o mesmo procedimento, 
de baixo para cima, formando uma pilha. A retirada deve ser feita pelo mesmo caminho, 
você sempre deve retirar o último elemento (topo). Caso a retirada seja feita com um 
elemento aleatório, a pilha de pratos pode cair e você terá um prejuízo.
Baseando-se neste princípio, pense em um conjunto de valores inteiros sendo 
inseridos e removidos da memória. Devemos utilizar um vetor para fazer esta simulação e 
também outras duas variáveis para representar a base da pilha (início) e o topo da pilha 
(fim), local onde os dados serão inseridos e removidos.
Observe que à medida que os dados são inseridos, o a variável topo deve ser 
incrementada para que o próximo elemento a ser inserido fique após o último que existia, 
assim ele passa a ser o último elemento da estrutura. O mesmo deve acontecer até que o 
topo represente o valor final do vetor, caracterizando pilha cheia.
Antes que qualquer elemento seja inserido na estrutura pilha indicará que a pilha 
está vazia, portanto as variáveis topo e base estarão armazenando o mesmo valor de índice 
para acesso ao vetor de dados, ou seja, valor 0 (zero).
Programa Pilha
// Arquivo PILHA.H - Descrição da estrutura pilha 
#include<iostream>
using namespace std;
#define MAX 5
extern pilha p;
struct pilha
{
 int dados[MAX];
 int base;
 int topo;
};
void empilha(int);
void desempilha(void);
void inicializa(void);
void imprime(void);
Este trecho de código representa um TAD pilha. 
Utilizamos para representação da pilha uma estrutura que contém um vetor que será 
utilizado para armazenamento dos valores e duas variáveis inteiras que representarão o topo 
e a base da pilha. As funções definidas serão utilizadas para realização das atividades de 
inicialização, inserção, remoção e impressão da pilha
void inicializa(void)
{
 int i;
 p.topo=p.base=0;
 for(i=0;i<MAX;i++)
 {
 p.dados[i]=0;
 }
}
Função utilizada para inicialização da pilha.
Após a execução da função inicializa, o vetor que representa os dados da pilha será 
preenchido com 0 (zero) e também as variáveis topo e base receberão zero para indicar que 
a pilha está vazia e pronta para entrada de dados.
void empilha(int x)
{
 if(p.topo == MAX )
 {
cout<<“\nPilha cheia...”;
 }
 else
 {
p.dados[p.topo]=x;
p.topo++;
 }
}
Esta função quando chamada receberá um valor (através de x) que indica o valor a 
ser inserido na pilha. 
Observe que o vetor de dados receberá o valor de x e em seguida o topo se desloca 
para a próxima posição, indicando onde poderá ser inserido o próximo valor.
Para visualizar melhor siga os passos:
1) Imagine que a função receba o valor inteiro 10 através da variável x.
int a=10;
empilha(a);
Neste momento, o valor da variável a será passado para a variável x da função 
insere. O valor de x será inserido na pilha através dos comandos existentes na 
função:
p.dados[p.topo]=x;
Após a inserção, o topo da pilha deverá ser deslocado para a próxima posição do 
vetor, onde deverá ser inserido o próximo valor. 
O comando que executa o deslocamento do topo é:
p.topo++;
Neste momento o topo passa a armazenar o valor 1.
Para melhor fixação vamos chamar novamente a função insere, passando outro 
valor para ser inserido na pilha:
a = 8;
empilha(a);
Neste momento o valor 8 é passado para x que será inserido na pilha, onde o topo 
estiver:
p.dados[p.topo]=x;
Veja que o topo andou novamente.
Esses procedimentos irão ocorrer até que o topo chegue à quantidade máxima 
permitida pelo vetor de dados. 
Por essa razão é necessário o teste de verificação se a pilha está cheia:
 if(p.topo == MAX )
 {
cout<<“\nPilha cheia...”;
 }
Exercícios
1 – Implemente o programa pilha apresentado como exemplo nesta apostila
2 – Utilizando o programa pilha proposto no exercício 1, escreva um programa que simule 
o funcionamento de uma calculadora onde os valores são inseridos na pilha e quando for 
solicitado uma operação, dois valores sejam removidos retornando a ela o resultado desta 
operação. Este processo deve acontecer até que a pilha fique com apenas um valor
3 – Faça um programa utilizando pilha para solução do seguinte problema:
10 + ( ( x * ( y *z ) / (a * b) ) – 50 )
Fila utilizando vetores
Esta estrutura de dados é bem parecida com a estrutura pilha, pelo fato de apresentar 
atividades formais de inserção e remoção de dados, ou seja, a inserção é realizada 
utilizando-se um caminho e a saída outro, sempre desta maneira. 
O nome FILA, dado a esta estrutura, segue o princípio das filas que conhecemos 
como fila de banco, fila de carros, dentre outros, onde o primeiro elemento que entra na 
fila é o primeiro a sair – FIFO – Fist In First Out.
O primeiro carro da fila será o primeiro a entrar na garagem. Se outro veículo 
chegar ele ficará por último.
Baseando-se neste princípio, pense em um conjunto de valores inteiros sendo 
inseridos e removidos da memória. Devemos utilizar um vetor para fazer esta simulação e 
também outras duas variáveis para representar o início e o fim da fila.
A entrada de dados acontece sempre no fim da fila e a remoção do início.
A estrutura básica da fila pode ser representada da seguinte maneira em 
programação:
struct fila
{
 int dados[4];
 int inicio, fim;
};
Logicamente, quando utilizamos vetor, a possibilidade de inserir mais elementos do 
que foi determinado pelo tamanho (4 neste caso), é impossível. Para resolver esse problema 
é necessário verificar no processo de inserção de um novo elemento se o limite máximo 
suportado não foi atingido.
Na tentativa de inserir novo elemento o programa deve informar que a fila está 
cheia, sendo impossível a inserção.
void enfila(int x)
{
 if(p.fim == 4 )
 {
cout<<“\nFila cheia...”;
 }
 else
 {
p.dados[p.fim]=x;
p.fim++;
 }
}
Se o fim atingir o limite máximo de elementos do vetor, o programa informará que a 
fila está cheia, caso contrário o elemento será inserido.
Observe a figura e veja o que poderia acontecer no uso de fila com vetor.
A) Neste caso,a fila está vazia sendo possível a inserção de elementos.
B) Neste item ocorre a entrada de 3 elementos, observe que no final ainda existe a 
possibilidade de inserção de mais um elemento.
C) Como a teoria de fila diz que a remoção deve ser feita no início, dois elementos 
foram removidos, portanto o início deixou de ser a posição que guarda os 
elementos 10 e 20 e passou a ser a posição que guarda o valor 30.
D) Este item representa a inserção de mais um elemento, que foi possível por existir 
uma posição ainda vazia.
Imagine agora se for necessário inserir outro elemento?
 Qual seria a resposta do programa? FILA CHEIA!!!!!! 
 Isso não é verdade, pois, ainda existem duas posições vazias onde poderia ser 
inserido novo elemento.
Uma solução para este problema seria a reorganização do vetor, trazendo para o 
início todos os elementos logo atrás daquele que sair da fila.
A) Neste momento seria impossível a inserção de um novo elemento porque a fila 
está cheia.
B) Com a remoção de um elemento, a posição vaga passaria a ser a última com a 
chegada de todos os elementos uma posição à frente.
C) Se um novo elemento chegar para ser inserido será possível por existir uma 
posição vaga.
for(i=0;i<p.fim;i++)
{ 
 p.dados[i] = p.dados[i+1];
}
Este laço de repetição reorganiza o vetor trazendo todos os números uma 
posição à frente.
Portanto, a função desenfila ficará assim:
void desenfila(void)
{ 
 if(p.fim == p.inicio)
 {
 cout<<“\nFila vazia!!!”;
 }
 else
 {
 for(i=0;i<p.fim;i++)
 { 
 p.dados[i] = p.dados[i+1];
 }
 }
}
Esta solução resolverá o problema, mas pode não ser tão eficiente pelo tempo gasto 
para realizar a reorganização. Imagine uma fila com 10000 elementos e a cada elemento 
removido este processo deve ocorrer, o tempo gasto seria muito grande.
Outra solução que existe é a criação de uma fila circular.
Neste caso o vetor é tratado como se fosse um círculo, ao invés de um conjunto em 
linha reta. O primeiro elemento (posição 0 do vetor) segue imediatamente o último, isto 
indica que mesmo se o último elemento do vetor possuir algum valor não que dizer a fila 
está vazia e um novo elemento poderá ser inserido no início.
Para entender melhor, observe a figura:
A) Como demonstrado anteriormente, não seria possível inserir um novo elemento, 
já que a última posição está sendo utilizada pelo valor 30. 
B) Utilizando esta técnica de fila circular, o primeiro elemento que segue o último 
passa a ser a posição que receberá um novo elemento se esta também não estiver 
ocupada. 
Referências Bibliográficas
TENENBAUM, A. M., LANGSAM Y. & AUGENSTEIN M. J. Estruturas de dados 
usando C. Ed. Makron Books, São Paulo 1995.
SCHILDT H. C Completo e Total, 3ª edição. Editora Makron Books, São Paulo, 
1996.
SCHILDT H. C++ Guia para iniciantes. Ed. Ciência Moderna, Rio de Janeiro, 2002.
DEITEL H.M. C++ como programar, 3ª edição. Editora Bookman, Porto Alegre, 
2001.
DROZDEK A. Estrutura de dados e Algoritmos em C++, Editora Cengage Learning, 2008

Continue navegando