Estrutura de Dados Sônia Virginia Alves França 2007 Estrutura de Dados Índice 1. Estrutura de Dados .............................................................................................................................. 4 2. Tipos de Estruturas de Dados .............................................................................................................. 5 2.1 Listas Lineares ..............................................................................................................................................5 2.2 Filas ................................................................................................................................................................6 2.3 Pilhas ..............................................................................................................................................................6 2.4 Árvores...........................................................................................................................................................7 3. Implementação das Estruturas Estáticas .......................................................................................... 12 3.1 Lista Estática Desordenada........................................................................................................................12 3.1.1 Operações Básicas.................................................................................................................................................12 3.1.2 Algoritmo...............................................................................................................................................................15 3.1.3 Programa em C .....................................................................................................................................................17 3.2 Lista Estática Ordenada.............................................................................................................................21 3.2.1 Operações Básicas.................................................................................................................................................21 3.2.2 Algoritmo...............................................................................................................................................................24 3.2.3 Programa em C .....................................................................................................................................................27 3.3 Fila Estática .................................................................................................................................................32 3.3.1 Operações Básicas.................................................................................................................................................32 3.3.2 Algoritmo...............................................................................................................................................................33 3.3.3 Programa em C .....................................................................................................................................................35 3.4 Pilha Estática...............................................................................................................................................38 3.4.1 Operações Básicas.................................................................................................................................................38 3.4.2 Algoritmo...............................................................................................................................................................39 3.4.3 Programa em C .....................................................................................................................................................41 4. Implementação das Estruturas Dinâmicas ....................................................................................... 44 4.1 Alocação Dinâmica......................................................................................................................................44 4.2 Lista Dinâmica Desordenada .....................................................................................................................46 4.2.1 Operações Básicas.................................................................................................................................................47 4.2.2 Programa em C .....................................................................................................................................................49 4.3 Lista Dinâmica Ordenada ..........................................................................................................................53 4.3.1 Operações Básicas.................................................................................................................................................53 4.3.2 Programa em C .....................................................................................................................................................56 2 Estrutura de Dados 4.4 Lista Duplamente Encadeada Ordenada..................................................................................................60 4.4.1 Operações Básicas.................................................................................................................................................60 4.4.2 Programa em C .....................................................................................................................................................61 4.5 Fila Dinâmica ..............................................................................................................................................66 4.5.1 Operações Básicas.................................................................................................................................................66 4.5.2 Programa em C .....................................................................................................................................................68 4.6 Pilha Dinâmica ............................................................................................................................................71 4.6.1 Operações Básicas.................................................................................................................................................71 4.6.1 Programa em C .....................................................................................................................................................72 5. Ordenação e Pesquisa ........................................................................................................................ 76 5.1 Ordenação....................................................................................................................................................76 5.1.1 Método da Ordenação por Troca ........................................................................................................................76 5.1.2 Método da Ordenação por Seleção......................................................................................................................77 5.1.3 Método da Ordenação por Inserção....................................................................................................................79 5.2 Pesquisa........................................................................................................................................................80 3 Estrutura de Dados 1. Estrutura de Dados Estruturas de dados e algoritmos são temas fundamentais da ciência da computação, sendo que são utilizados nas mais diversas áreas e com os mais diferentes propósitos. Algoritmos manipulam dados. Quando estes dados estão organizados de forma coerente caracterizam uma estrutura de dados. São a organização e os métodos que manipulam determinada estrutura que lhe conferem singularidade. A escolha de uma estrutura de dados apropriada pode tornar um problema complicado em uma solução trivial. O estudo das estruturas de dados está em constante desenvolvimento, apesar disso, existem estruturas clássicas que têm se mostrado padrão de facto. As estruturas têm as suas características básicas e tem finalidades diferentes. Podem ser implementadas usando vetores (estática) ou ponteiros (dinâmica) Conceito de Estrutura de Dados Para definir o que é uma estrutura de dados devemos definir o que é dado e tipo de dado. Podemos definir dado como um elemento sobre o qual serão efetuadas operações e tipo de dado é o conjunto de valores ao qual pertence um dado. Exemplos de tipos de dados são inteiro, real, lógico, etc. Uma primeira classificação para os tipos de dados é: primitivos ou derivados. Os tipos de dados primitivos são aqueles que não podem ser decompostos, por exemplo: inteiro, real, lógico e caracter. Os tipos de dados derivados são aqueles definidos a partir dos tipos primitivos, por exemplo: vetores, matrizes, registros, etc. Os tipos de dados derivados podem ser homogêneos ou heterogêneos. Os tipos de dados homogêneos agrupam dados primitivos do mesmo tipo, por exemplo: vetores, cadeias e matrizes. Os tipos de dados heterogêneos agrupam dados primitivos de tipos diferentes, por exemplo: registros. Os tipos de dados também podem ser estáticos ou dinâmicos. Os tipos de dados estáticos têm tamanho sempre finito, por exemplo: tipos primitivos, registros vetores e matrizes. Os tipos de dados dinâmicos têm um tamanho que pode variar durante o seu tempo de vida, por exemplo: pilhas, filas, listas encadeadas e árvores. Visto isso, definimos estrutura de dados como um tipo derivado de dado concebido com o objetivo de ser manipulado de maneira sistemática por algoritmos e, conseqüentemente, por programas de computador. 4 Estrutura de Dados 2. Tipos de Estruturas de Dados 2.1 Listas Lineares Uma das formas mais comumente usadas para se manter dados agrupados é a lista. Afinal, quem nunca organizou uma lista de compras antes de ir ao mercado, ou então uma lista dos amigos que participarão da festa? As listas têm-se mostrado um recurso bastante útil e eficiente no dia-a-dia das pessoas. Em computação, não tem sido diferente: a lista é uma das estruturas de dados mais empregadas no desenvolvimento de programas. Ao desenvolver uma implementação para listas lineares, o primeiro problema que surge é: como podemos armazenar os elementos da lista, dentro do computador? Sabemos que antes de executar um programa, o computador precisa carregar seu código executável para a memória. Da área de memória que é reservada para o programa, uma parte é usada para armazenar as instruções a serem executadas e a outra é destinada ao armazenamento dos dados. Quem determina quanto de memória será usado para as instruções é o compilador. Alocar área para armazenamento de dados entretanto, é responsabilidade do programador. Uma lista linear pode ser implementada usando vetores ou ponteiros. Se for implementada usando vetores, deve estipular qual a quantidade de elementos que a lista pode armazenar. A memória para armazenamento dos dados é alocada em tempo de compilação. Quando implementada usando ponteiros, a memória é alocada conforme novos elementos são colocados na lista e desalocada quando elementos são retirados. Ou seja, vai alocando memória dinamicamente, em tempo de execução. Tipos de Listas Lineares: 1. Lista estática desordenada 2. Lista estática ordenada 3. Lista dinâmica desordenada 4. Lista dinâmica ordenada 5. Lista dinâmica duplamente encadeada Na lista desordenada os elementos são colocados na primeira posição vazia da lista (normalmente, no final). Na lista ordenada, é escolhido um dado que será o campo de ordenação da lista. Quando se 5 Estrutura de Dados deseja inserir um novo elemento na lista, primeiro tem que ser verificado em que local ele dever ser colocado para que seja mantida a ordem da lista. Operações básicas das listas: inserir elemento, remover elemento, consultar elemento, alterar elemento, listagem dos elementos da lista. 2.2 Filas Uma fila é um tipo especial de lista linear em que as inserções são realizadas em um extremo, ficando as remoções restritas ao outro. O extremo onde os elementos são inseridos é denominado final da fila, e aquele de onde são removidos é denominado começo da fila. Cada vez que uma operação de inserção é executada, um novo elemento é colocado no final da fila. Na remoção, é sempre retornado o elemento que aguarda há mais tempo na fila, ou seja, aquele posicionado no começo. A ordem de saída corresponde diretamente à ordem de entrada dos elementos na fila, de modo que os primeiros elementos que entram são sempre os primeiros a sair. Por este motivo, as filas são denominadas listas FIFO (First-In/First-Out) ou PEPS (Primeiro que Entra/Primeiro que Sai). Um exemplo bastante comum de filas verifica-se num balcão de atendimento, onde pessoas formam uma fila para aguardar até serem atendidas. Naturalmente, devemos desconsiderar os casos de pessoas que “furam” a fila ou que desistem de aguardar! Diferentemente das filas no mundo real, o tipo abstrato de dados não suporta inserção nem remoção no meio da lista. Um exemplo de utilização em computação é a implementação de uma fila de impressão. Se uma impressora é compartilhada por várias máquinas, deve-se adotar uma estratégia para determinar qual documento será impresso primeiro. A estratégia mais simples é tratar todas as requisições com a mesma prioridade e imprimir os documentos na ordem em que foram submetidos – o primeiro submetido é o primeiro a ser impresso. 2.3 Pilhas Uma das estruturas de dados mais simples é a pilha. Possivelmente por essa razão, é a estrutura de dados mais utilizada em programação, sendo inclusive implementada diretamente pelo hardware da maioria das máquinas modernas. A idéia fundamental da pilha é que todo o acesso a seus elementos é feito através do seu topo. Assim, quando um elemento novo é introduzido na pilha, passa a ser o elemento do topo, e o único elemento que pode ser removido da pilha é o do topo. Isto faz com que os elementos da pilha sejam retirados na ordem inversa à ordem em que foram introduzidos: o primeiro que sai é o último que entrou 6 Estrutura de Dados (a sigla LIFO – last in, first out – é usada para descrever esta estratégia ou UEPS em português - Último que Entra/Primeiro que Sai). Para entendermos o funcionamento de uma estrutura de pilha, podemos fazer uma analogia com uma pilha de pratos. Se quisermos adicionar um prato na pilha, o colocamos no topo. Para pegar um prato da pilha, retiramos o do topo. Assim, temos que retirar o prato do topo para ter acesso ao próximo prato. A estrutura de pilha funciona de maneira análoga. Cada novo elemento é inserido no topo e só temos acesso ao elemento do topo da pilha. Existem três operações básicas que devem ser implementadas numa estrutura de pilha: a operação para empilhar um novo elemento, inserindo-o no topo, a operação para desempilhar um elemento, removendo-o do topo e a operação para consultar qual elemento está no topo da pilha. É comum nos referirmos a essas operações pelos termos em inglês push (empilhar) e pop (desempilhar). 2.4 Árvores Nos tópicos anteriores examinamos as estruturas de dados que podem ser chamadas de unidimensionais ou lineares, como as listas. A importância dessas estruturas é inegável, mas elas não são adequadas para representarmos dados que devem ser dispostos de maneira hierárquica. Por exemplo, os arquivos (documentos) que criamos num computador são armazenados dentro de uma estrutura hierárquica de diretórios (pastas). Existe um diretório base dentro do qual podemos armazenar diversos subdiretórios e arquivos. Por sua vez, dentro dos sub-diretórios podemos armazenar outros sub-diretórios e arquivos, e assim por diante, recursivamente. Arvore são estruturas de dados adequadas para a representação de hierarquias. A forma mais natural para definirmos uma estrutura de árvore é usando recursividade. Uma árvore é composta por um conjunto de nós. Existe um nó r, denominado raiz, que contém zero ou mais sub-árvores, cujas raízes são ligadas diretamente a r. Esses nós raízes das sub-árvores são ditos filhos do nó pai, r. Nós com filhos são comumente chamados de nós internos e nós que não têm filhos são chamados de folhas, ou nós externos. Existem três formas de representação gráfica são: Representação por parênteses aninhados ( A (B) ( C (D (G) (H)) (E) (F (I)) ) ) 7 Estrutura de Dados Diagrama de inclusão Representação hierárquica Motivação • diversas aplicações necessitam de estruturas mais complexas que as estruturas básicas(listas, filas e pilhas); • inúmeros problemas podem ser modelados através de árvores • árvores admitem tratamento computacional eficiente quando comparadas às estruturas mais genéricas como os grafos (os quais, por sua vez são mais flexíveis e complexos) Definição Uma árvore enraizada T, ou simplesmente uma árvore, é um conjunto finito de elementos denominados nós ou vértices tais que: • T = 0 é a árvore dita vazia ou • existe um nó especial r, chamado raiz de T; os restantes constituem um único conjunto vazio ou são divididos em m (deve ser maior ou igual a 1) conjuntos distintos não vazios que são as subárvores de r, cada subárvore a qual é, por sua vez, uma árvore. Subárvore Seja a árvore acima T = {A, B, ...} 8 Estrutura de Dados A árvore T possui duas subárvores: Tb e Tc onde Tb = { B } e Tc = {C, D, ...} A subárvore Tc possui 3 subárvores: Td, Tf e Te onde Td = {D, G, H} Tf = {F, I} Te = {E} As subárvores Tb, Te, Tg, Th, Ti possuem apenas o nó raiz e nenhuma subárvore. Nós filhos, pais, tios, irmãos e avô Seja v o nó raiz da subárvore Tv de T. Os nós raízes w1, w2, ... wj das subárvores de Tv são chamados filhos de v. v é chamado pai de w1, w2, ... wj. Os nós w1, w2, ...wj são irmãos. Se z é filho de w1 então w2 é tio de z e v é avô de z. Grau de saída, descendente e ancestral Número de filhos de um nó é chamado grau de saída desse nó. Se x pertence à subárvore Tv, então, x é descendente de v e v é ancestral, ou antecessor, de x. Se neste caso x é diferente de v então x é descendente próprio de v e v é ancestral próprio de x. Nó folha e nó interior Um nó que não possui descendentes próprios é chamado de nó folha, ou seja, um nó folha é aquele com grau de saída nulo. Um nó que não é folha (isto é, possui grau de saída diferente de zero) é chamado nó interior ou nó interno. Grau de uma árvore Grau de uma árvore é o máximo entre os graus de seus nós. Floresta Uma floresta é um conjunto de zero ou mais árvores. 9 Estrutura de Dados Caminho, comprimento do caminho Uma seqüência de nós distintos v1, v2, ..., vk, tal que existe sempre entre nós consecutivos ( isto é, entre v1 e v2, entre v2 e v3, ... , v(k-1) e vk) a relação "é filho de"ou "é pai de" é denominada um caminho na árvore. Diz-se que v1 alcança vk e que vk é alcançado por v1. Um caminho de vk vértices é obtido pela sequência de k-1 pares. O valor k-1 é o comprimento do caminho. Nível (ou profundidade) e altura de um nó Nível ou profundidade, de um nó é o número de nós do caminho da raiz até o nó. O nível da raiz, é portanto, 1. A altura de um nó v é o número de nós no maior caminho de v até um de seus descendentes. As folhas têm altura 1. Nível da raiz (profundidade) e altura de uma árvore O nível da raiz é 1 (acima). A altura de uma árvore T é igual ao máximo nível de seus nós. Representa-se a altura de T por h(T) e a altura da subárvore de raiz v por h(v). Árvore Ordenada Uma árvore ordenada é aquela na qual os filhos de cada nó estão ordenados. Assume-se ordenação da esquerda para a direita. Desse modo, a árvore do primeiro exemplo é ordenada, mas, a árvore abaixo não. Árvores Isomorfas Duas árvores não ordenadas são isomorfas quando puderem se tornar coincidentes através de uma permutação na ordem das subárvores de seus nós. Duas árvores ordenadas são isomorfas quando forem coincidentes segundo a ordenação existente entre seus nós. Árvore Cheia Uma árvore de grau d é uma árvore cheia se possui o número máximo de nós, isto é, todos os nós têm número máximo de filhos exceto as folhas, e todas as folhas estão na mesma altura. 10 Estrutura de Dados Árvore cheia de grau 2: implementação seqüencial. Árvore Binária Uma Árvore Binária T é um conjunto finito de elementos denominados nós ou vértices, tal que: • T = 0 e a árvore é dita vazia ou • existe um nó especial r, chamado raiz de T, os restantes podem ser divididos em dois subconjuntos disjuntos, Tre e Trd, que são as subárvores esquerda e direita de r, respectivamente e as quais, por sua vez, também são árvores binárias. Árvore Binária de Busca Uma Árvore Binária de Busca T (ABB) ou Árvore Binária de Pesquisa é tal que ou T = 0 e a árvore é dita vazia ou seu nó raiz contém uma chave e: • Todas as chaves da subárvore esquerda são menores que a chave da raiz. • Todas as chaves da subárvore direita são maiores que a chave raiz. • As subárvores direita e esquerda são também Árvores Binárias de Busca. 11 Estrutura de Dados 3. Implementação das Estruturas Estáticas A seguir, faremos a implementação de todas as operações básicas das estruturas de dados vistas na seção anterior. Primeiramente, serão implementadas as estruturas estáticas, usando vetores. Para estas, também serão feitos os algoritmos, com o objetivo de facilitar o aprendizado. As estruturas dinâmicas serão implementadas diretamente na linguagem C, na seção 4. 3.1 Lista Estática Desordenada Esta estrutura é implementada usando vetores e não se preocupa com ordenação. Os elementos são colocados na estrutura por ordem de chegada. Nas próximas seções será descrita cada uma das operações feitas nesta estrutura. Em seguida será apresentado o algoritmo de cada operação e o programa em C. No exemplo, teremos uma lista com os dados dos alunos de uma turma (para simplificar, cada aluno tem apenas a matrícula e o nome). 3.1.1 Operações Básicas Inserir Elemento A figura abaixo ilustra a inserção de três elementos em uma lista estática desordenada. Inicialmente o vetor está vazio. O primeiro elemento a chegar é o aluno José com matrícula 256. Este será colocado na primeira posição do vetor. 12 Estrutura de Dados Posteriormente, chegam mais dois alunos (Ana com matrícula 132 e Paulo com matrícula 429), que são colocados nas próximas posições disponíveis do vetor (posição 2 e posição 3). Quando uma inserção vai ser executada, é necessário verificar se o vetor tem posições disponíveis. Caso contrário, a inserção não pode ser efetuada. Consultar Elemento Depois que um elemento é inserido, a operação mais executada é a consulta. Para a consulta é necessário saber qual elemento deseja consultar. Neste caso faremos uma consulta por matrícula. Para isso, a matrícula do aluno a ser consultado deve ser lida. É feita uma “visita” ou “varredura” em todas as posições ocupadas do vetor, a procura do elemento. No vetor da figura acima temos seis elementos. Vamos consultar o elemento de matrícula 578. Para encontrá-lo, temos que varrer o vetor desde o seu início e paramos na posição 4 que é a posição onde ele se encontra. Caso quiséssemos consultar o elemento de matrícula 192, iríamos varrer todo o vetor, elemento a elemento e ao chegar na sexta posição (que é a ultima) ficaríamos sabendo que este elemento não se encontra no vetor. Quando um elemento é encontrado, seus dados são apresentados e quando ele não está no vetor, uma mensagem de erro deve ser dada ao usuário. Alterar Elemento A alteração é importante para o momento que se tenha cadastrado um dado incorretamente ou mesmo eles sofram uma alteração (exemplo: modificar o telefone do cliente). Para a alterar os dados de um elemento é necessário saber qual elemento deseja alterar. Neste caso faremos a busca por matrícula. Para isso, a matrícula do aluno a ser alterado deve ser lida. 13 Estrutura de Dados É feita a varredura em todas as posições ocupadas do vetor, a procura da matrícula. Assim que o elemento é encontrado, seus dados devem ser apresentados ao usuário (neste caso a matrícula e o nome). Dessa forma ele pode verificar se realmente é aquele o elemento a ser alterado, além de informar qual campo dever ser alterado e qual o novo valor para aquele campo. Quando o elemento não é encontrado, uma mensagem de erro deve ser dada ao usuário. Caso deseje, assim que os dados forem alterados, o registro do aluno é apresentado novamente para o usuário. Deve tomar cuidado quando a alteração de um campo, influencie em outro campo, fazendo-se necessário uma alteração indireta, por exemplo: o professor cadastrou a nota do aluno incorretamente. A alteração desta nota irá influenciar na média do aluno. Remover Elemento Caso um elemento não precise mais fazer parte da estrutura, ele pode ser removido. Para remover os dados de um elemento é necessário saber qual elemento deseja remover. Já que iremos Neste caso faremos a busca por matrícula. Para isso, a matrícula do aluno a ser removido deve ser lida. É feita uma varredura em todas as posições ocupadas do vetor, a procura da matrícula. Assim que o elemento é encontrado, seus dados devem ser apresentados ao usuário (neste caso a matrícula e o nome). Dessa forma ele pode verificar se realmente é aquele o elemento a ser removido. Quando o elemento não é encontrado, uma mensagem de erro deve ser dada ao usuário. Numa lista desordenada, para a remoção ser efetuada, o último elemento do vetor deve ser transferido para a posição do elemento removido. Listagem de Todos os Elementos A operação de listagem possibilita a visualização dos dados de todos os elementos cadastrados. É feita uma varredura no vetor e todos os dados de todos os elementos são apresentados ao usuário. Caso a lista esteja vazia, será apresentada uma mensagem. 14 Estrutura de Dados 3.1.2 Algoritmo INICIO tipo regaluno = registro caracter: nome; inteiro: mat; real: media; fimregistro; tipo vetorturma = vetor [1..50] de regaluno; vetorturma: turma; inteiro: op, qa; módulo inserir; se (qa = 50) então escreva(″não pode inserir″); senão inicio qa ← qa + 1; leia(turma[qa].mat, turma[qa].nome, turma[qa].med); escreva(″Inserido com sucesso″); fim; fimse; fimmódulo; módulo procura(inteiro: matprocurada); inteiro i, p; p ← 0; i ← 0; enquanto (i<qa) e (p=0) faça i ← i+1; se (turma[i].mat = matprocurada) então p ← i; fimse; fimenquanto; retorne(p); fimmódulo; módulo consultar; inteiro: posicao, matcon; leia(matcon); posicao ← procura(matcon); se (posicao <> 0) então escreva(turma[posicao].mat, turma[posicao].nome, turma[posicao].med); senão escreva(″Matricula não cadastrada″); fimse; fimmódulo; 15 Estrutura de Dados módulo remover; inteiro: posicao, matrem, confirma; leia(matrem); posicao ← procura(matrem); se (posicao <> 0) então inicio escreva(turma[posicao].mat, turma[posicao].nome, turma[posicao].med); escreva(″Confirma remoção(1-sim/2-não)?″); leia(confirma) se (confirma = 1) então inicio turma[posicao] ← turma[qa]; qa ← qa - 1; escreva(″Removido com Sucesso!″); fim; senão escreva(″Remocao Cancelada″); fimse; fim; senão escreva(″Matricula nao cadastrada″); fimse; fimmódulo; módulo alterar; inteiro: posicao, matalt,confirma; leia(matalt); posicao ← procura(matalt); se (posicao <> 0) então inicio escreva(turma[posicao].mat, turma[posicao].nome, turma[posicao].med); escreva(″Alterar Nome(1-sim/2-não)?″); leia(confirma) se (confirma = 1) então leia(turma[posicao].nome); fimse; escreva(″Alterar Media(1-sim/2-não)?″); leia(confirma) se (confirma = 1) então leia(turma[posicao].med); fimse; escreva(turma[posicao].mat, turma[posicao].nome, turma[posicao].med); escreva(″Alterado com Sucesso!″); fim; senão escreva(″Matricula não cadastrada″); fimse; fimmódulo; 16 Estrutura de Dados módulo listagem; inteiro: i; se (qa > 0) então inicio escreva(″Matricula Nome Media″); para i de 1 até qa faça escreva(turma[i].mat, turma[i].nome, turma[i].med); fimpara; fim; senão escreva(″Turma Vazia″); fimse; fimmódulo; qa ← 0; repita escreva(“Informe a opcao desejada(1-inserir/2remover/3-consultar /4-alterar/5-listagem/0-sair: “); leia(op); escolha op caso 1: inserir; caso 2: remover; caso 3: consultar; caso 4: alterar; caso 5: listagem; fimescolha; até op = 0; FIM. 3.1.3 Programa em C #include <stdio.h> #include <conio.h> #include <string.h> #include <stdlib.h> // Programa para executar funcoes de uma lista estatica desordenada typedef struct { int mat; char nome[31]; float media; }TAlunos; TAlunos turma[30]; const int maximo= 30; int qa, op; //*********************************************************************** void linha() { int i; for (i=1;i<=80;i++) printf("_"); printf("\n"); } 17 Estrutura de Dados void cabec() { system("cls"); printf("Faculdade Santa Maria - Lista Estatica Desordenada\n"); linha(); } // modulo que retorna a posicao do elemento procurado int procura(int procurado) { int j, posicao; posicao = -1; for(j = 0; j<qa; j++) { if (procurado==turma[j].mat) { posicao = j; break; } } return posicao; } // modulo para mostrar o elemento na posicao indice void mostre (int pos) { printf("\n\nMatricula Aluno Media"); printf("\n--------------------------------------------"); printf("\n%9d %-20s %5.2f", turma[pos].mat, turma[pos].nome, turma[pos].media); printf("\n--------------------------------------------\n\n"); } //Inserir novo aluno void inserir() { int cont; do{ cabec(); printf("\nInserir Novo Aluno\n\n"); if (qa < maximo) // verifica se o vetor pode receber novo aluno { printf("\nMatricula do Aluno: "); scanf("%d",&turma[qa].mat); printf("\nNome: "); fflush(stdin); gets(turma[qa].nome); printf("\nMedia: "); scanf("%f",&turma[qa].media); qa++; printf("\n\nAluno Inserido com Sucesso!!!\n\n"); } else // vetor cheio { printf("\n\n\aNao Pode Inserir - Turma Cheia!!!\n\n"); getche(); break; } printf("\n\nInserir outro(1-sim/2-nao)? "); scanf("%d",&cont); }while (cont == 1); } 18 Estrutura de Dados //Remover aluno cadastrado void remover() { int matrem, i, cont, achou, conrem; do{ cabec(); printf("\nRemover Aluno\n\n"); printf("\nMatricula do Aluno: "); scanf("%d",&matrem); achou = procura(matrem); if (achou != -1) { mostre(achou); printf("\nDeseja remover o aluno (1-sim/2-nao)? "); scanf("%d",&conrem); if (conrem==1) // verifica se quer remover { turma[i]= turma[qa-1]; qa--; printf("\n\nAluno removido com Sucesso!!!\n"); } else printf("\n\n\aO aluno nao foi removido!!!\n"); break; } else // aluno nao foi encontrado printf("\n\naNumero de Matricula Incorreto!!!!!!\n"); printf("\n\nRemover outro(1-sim/2-nao)? "); scanf("%d",&cont); }while (cont == 1); } //Consultar aluno cadastrado por matricula void consultarmat() { int i, matcon, achou, cont; do { cabec(); printf("\nConsultar Aluno por Matricula\n\n"); printf("\nMatricula do Aluno: "); scanf("%d",&matcon); achou = procura(matcon); if (achou != -1) mostre(achou); else // aluno nao foi encontrado printf("\n\n\aNumero de Matricula Incorreto!!!!!!\n"); printf("\n\nConsultar outro(1-sim/2-nao)? "); scanf("%d",&cont); } while (cont == 1); } //Alterar dados de aluno cadastrado void alterar() { int achou, i, matalt, conalt, cont; do { cabec(); printf("\nAlterar Dados do Aluno\n\n"); printf("\nMatricula do Aluno: "); 19 Estrutura de Dados scanf("%d",&matalt); achou = procura(matalt); if (achou != -1) { mostre(achou); printf("\nDeseja Alterar o nome do aluno (1-sim/2-nao)? "); scanf("%d",&conalt); if (conalt == 1) { printf("\n\tNome : "); fflush(stdin); gets(turma[achou].nome); } printf("\nDeseja Alterar a Media do aluno (1-sim/2-nao)? "); scanf("%d",&conalt); if (conalt == 1) { printf("\nMedia: "); scanf("%f",&turma[achou].media); } mostre(achou); printf("\n\nAluno Alterado com Sucesso!!!\n"); } else // aluno nao foi encontrado printf("\n\n\aNumero de Matricula Incorreto!!!!!!\n"); printf("\n\nContinuar alterando aluno (1-sim/2-nao)? "); scanf("%d",&cont); } while (cont == 1); } //Imprimir relatorio com as informaçoes de todos alunos void listagem() { int i; cabec(); printf("\nRelatorio Geral\n"); printf("\n\nMatricula Aluno Media"); printf("\n---------------------------------------------"); for(i = 0; i < qa; i++) printf("\n%9d %-20s %5.2f", turma[i].mat, turma[i].nome, turma[i].media); printf("\n---------------------------------------------"); printf("\n\nDigite qualquer tecla para sair... "); getche(); } //Programa principal main() { qa =0; do // tela com o menu do opcoes { cabec(); printf("Opcoes:\n\n"); printf(" 1- Inserir novo Aluno\n\n"); printf(" 2- Remover Aluno\n\n"); printf(" 3- Consultar Aluno por Matricula\n\n"); printf(" 4- Alterar Dados de Aluno\n\n"); printf(" 5- Listagem de Alunos\n\n"); printf(" 0- Sair do Programa\n"); 20 Estrutura de Dados linha(); printf("\n Informe a Opcao desejada: "); scanf("%d",&op); switch(op) { case 1: inserir(); break; case 2: remover(); break; case 3: consultarmat(); break; case 4: alterar(); break; case 5: listagem(); break; case 0: break; default : printf("\n\a Opcao Invalida! Tecle enter..."); getche(); break; } } while (op != 0); } 3.2 Lista Estática Ordenada Nesse tipo de lista, os elementos devem ser colocados na estrutura obedecendo a uma ordenação. Qualquer operação feita na estrutura, não pode afetar na ordenação da mesma. A vantagem dessa lista será notada principalmente nos momentos que necessite percorrer a lista a procura de algum elemento. Aqui o programa anterior é modificado, fazendo com que os alunos sejam armazenados no vetor por ordem de matrícula. 3.2.1 Operações Básicas Inserir Elemento Para inserir um elemento em uma lista ordenada podem ocorrer cinco possibilidades: 1. a lista está cheia:nesse caso a inserção é cancelada; 2. a lista está vazia: o elemento é colocado na primeira posição do vetor; 3. o elemento a ser inserido é menor do que o primeiro da lista; 4. o elemento a ser inserido é maior do que o ultimo da lista; 5. o elemento novo será inserido entre elementos da lista. A figura a seguir ilustra a inserção de quatro elementos em uma lista estática ordenada. Inicialmente o vetor está vazio. O primeiro elemento a chegar é o aluno José com matrícula 256. Este será colocado na primeira posição do vetor. Posteriormente, chega Ana com matrícula 132. Para que a lista fique ordenada, deve verificar em qual posição o elemento deve ser inserido. Nesse caso, a matrícula 132 é menor que 256 21 Estrutura de Dados (que é a primeira da lista). Assim, todos os elementos a partir da posição onde o elemento de matrícula 256 se encontra, devem se deslocar uma posição, abrindo espaço para o elemento ser inserido. Mais tarde chega o elemento de matrícula 429. Esta matrícula é maior do que todas as matrículas do vetor, portanto, ele é inserido no final do vetor, sem necessidade de deslocamentos. Por fim, chega o elemento de matrícula 197. Devemos descobrir onde se encontra o primeiro elemento maior do que o que será inserido, ou seja, seu sucessor imediato. Neste caso, ele deve entrar na posição do elemento de matrícula 256. O espaço deve ser liberado, fazendo-se necessário o deslocamento de todos os elementos a partir do elemento de matrícula 256. A principal questão da inserção ordenada é descobrir o local onde o elemento deve ser inserido e, se necessário, fazer os deslocamentos. 22 Estrutura de Dados Consultar Elemento A matrícula do aluno a ser consultado deve ser lida. É feita uma varredura em todas as posições ocupadas do vetor, a procura da matrícula. No caso de uma lista ordenada, se estivéssemos procurando um aluno de matrícula 120, assim que fizéssemos a leitura da primeira matrícula do vetor, já saberíamos que a matrícula 120 não está no vetor, evitando uma varredura até o final do vetor. Na estrutura ordenada, as consultas são mais eficientes. Alterar Elemento A diferença da alteração ordenada e desordenada é que, numa lista ordenada, se o campo que ordena a lista for alterado, deve verificar se a lista permanece ordenada. Por exemplo, se alterarmos a matrícula de um aluno, pode ser que a lista fique desordenada. Tem duas soluções - não permitir a alteração do campo que ordena a lista ou sempre que o campo for alterado é verificada se a lista continua ordenada, os demais passos para alterar são iguais à lista desordenada. Remover Elemento Começamos com a leitura da matrícula do aluno a ser removido. É feita uma varredura em todas as posições ocupadas do vetor, a procura da matrícula. Assim que o elemento é encontrado, seus dados devem ser apresentados ao usuário (neste caso a matrícula e o nome). Dessa forma ele pode verificar se realmente é aquele o elemento a ser removido. Quando o elemento não é encontrado, uma mensagem de erro deve ser dada ao usuário. No exemplo da figura a seguir, desejamos remover o elemento de matrícula 256. Para que a lista fique contínua e ordenada, todos os elementos que vem depois do elemento que será removido, devem ser trazidos uma posição a frente. 23 Estrutura de Dados Listagem de Todos os Elementos A operação de listagem possibilita a visualização dos dados de todos os elementos cadastrados. É feita uma varredura no vetor e todos os dados de todos os elementos são apresentados ao usuário. 3.2.2 Algoritmo INICIO tipo regaluno = registro caracter: nome; inteiro: mat; real: media; fimregistro; tipo vetorturma = vetor [1..50] de regaluno; vetorturma: turma; inteiro: op, qa; módulo verificalocal(inteiro: matins); inteiro i, local; local ← 0; se (qa = 0) então local ← 1; senão inicio se (matins > turma[qa].mat) então local ← qa + 1; senão inicio local ← 1; enquanto (turma[local].mat < matins) faça local ← local + 1; fimenquanto; 24 Estrutura de Dados para i de qa até local passo -1 faça turma[i+1]=turma[i]; fimpara; fim; fimse; fim; fimse; retorne (local); fimmódulo; módulo inserir; inteiro: l, matl; se (qa = 50) então escreva(″não pode inserir″); senão inicio leia(matl); l ← verificalocal(matl); turma[l].mat ← matl; leia(turma[l].nome, turma[l].med); qa ← qa + 1; escreva(″Inserido com sucesso″); fim; fimse; fimmódulo; módulo procura(inteiro: matprocurada); inteiro i, p; p ← 0; i ← 1; enquanto (i<=qa) e (p=0) e (turma[i].mat<=matprocurada) faça se (turma[i].mat = matprocurada) então p ← i; fimse; i ← i+1; fimenquanto; retorne(p); fimmódulo; módulo consultar; inteiro: posicao, matcon; leia(matcon); posicao ← procura(matcon); se (posicao <> 0) então escreva(turma[posicao].mat, turma[posicao].nome, turma[posicao].med); senão escreva(″Matricula não cadastrada″); fimse; fimmódulo; 25 Estrutura de Dados módulo remover; inteiro: posicao, matrem, confirma, i; leia(matrem); posicao ← procura(matrem); se (posição <> 0) então inicio escreva(turma[posicao].mat, turma[posicao].nome, turma[posicao].med); escreva(″Confirma remoção(1-sim/2-não)?″); leia(confirma) se (confirma = 1) entao inicio para i de posicao até qa-1 faça turma[i] ← turma[i+1]; fimpara; qa ← qa - 1; escreva(″Removido com Sucesso!″); fim senão escreva(″Remocao Cancelada″); fimse; fim; senão escreva(″Matricula não cadastrada″); fimse; fimmódulo; módulo alterar; inteiro: posicao, matalt,confirma; leia(matalt); posicao ← procura(matalt); se (posicao <> 0) então inicio escreva(turma[posicao].mat, turma[posicao].nome, turma[posicao].med); escreva(″Alterar Nome(1-sim/2-não)?″); leia(confirma) se (confirma = 1) então leia(turma[posicao].nome); fimse; escreva(″Alterar Media(1-sim/2-não)?″); leia(confirma) se (confirma = 1) então leia(turma[posicao].med); fimse; escreva(turma[posicao].mat, turma[posicao].nome, turma[posicao].med); escreva(″Alterado com Sucesso!″); fim; senão escreva(″Matricula não cadastrada″); fimse; fimmódulo; 26 Estrutura de Dados módulo listagem; inteiro: i; se (qa > 0) então inicio escreva(″Matricula Nome Media″); para i de 1 até qa faça escreva(turma[i].mat, turma[i].nome, turma[i].med); fimpara; fim; senão escreva(″Turma Vazia″); fimse; fimmódulo; qa ← 0; repita escreva(“Informe a opcao desejada(1-inserir/2remover/3-consultar /4-alterar/5-listagem/0-sair: “); leia(op) escolha op caso 1: inserir; caso 2: remover; caso 3: consultar; caso 4: alterar; caso 5: listagem; fimescolha ate op = 0; FIM. 3.2.3 Programa em C #include <stdio.h> #include <conio.h> #include <stdlib.h> // Programa para executar funcoes de uma lista estatica ordenada. typedef struct { int mat; char nome[31]; float media; }TAlunos; TAlunos turma[30]; TAlunos al; const int maximo= 30; int qa, op; void linha() { int i; for (i=1;i<=80;i++) printf("_"); printf("\n"); } 27 Estrutura de Dados void cabec() { system("cls"); printf("Faculdade Santa Maria - Lista Estatica Ordenada\n"); linha(); } // Verificar em que posicao deve ser colocado o novo aluno a ser inserido. void colocarordem() { int i, local; local = -1; if (qa==0) turma[0] = al; else { for (i=0;i<qa;i++) { if (al.mat<turma[i].mat) { local = i; break; } } if (local==-1) turma[qa] = al; else { for (i=qa;i>local;i--) turma[i]=turma[i-1]; turma[local]=al; } } } // modulo que retorna a posicao do elemento procurado int procura(int procurado) { int j, posicao; posicao = -1; for(j = 0; j<qa; j++) { if (procurado==turma[j].mat) { posicao = j; break; } else { if (procurado<turma[j].mat) break; } } return posicao; } // modulo para mostrar o elemento na posicao indice void mostre (int indice) { printf("\n\nMatricula Aluno Media"); printf("\n---------------------------------------------"); printf("\n%9d %-20s %5.2f", turma[indice].mat, turma[indice].nome, turma[indice].media); printf("\n----------------------------------------------\n\n"); } 28 Estrutura de Dados // Inserir um novo aluno na escola void inserir() { int cont; do{ cabec(); printf("\nInserir Novo Aluno\n"); if (qa < maximo) // verifica se o vetor pode receber novo aluno { printf("\nMatricula do Aluno: "); scanf("%d",&al.mat); printf("\nNome: "); fflush(stdin); gets(al.nome); printf("\nMedia: "); scanf("%f",&al.media); colocarordem(); qa++; printf("\n\nAluno Inserido com Sucesso!!!\n"); } else // vetor cheio { printf("\n\n\aNao Pode Inserir - Turma Cheia!!!\n"); getche(); break; } printf("\n\nContinuar inserindo aluno (1-sim/2-nao)? "); scanf("%d",&cont); }while (cont == 1); } // Remover um aluno da escola void remover() { int matrem, i, achou, continuar, conrem; do{ cabec(); printf("\nRemover Aluno\n\n"); printf("\nMatricula do Aluno: "); scanf("%d",&matrem); achou = procura(matrem); if (achou!=-1) { mostre(achou); printf("\nDeseja remover o aluno (1-sim/2-nao)? "); scanf("%d",&conrem); if (conrem == 1) { for (i=achou;i<qa;i++) turma[i]=turma[i+1]; qa--; printf("\n\nAluno removido com Sucesso!!!\n"); } else printf("\n\n\aO aluno nao foi removido!!!\n"); } else printf("\n\n\aNumero de Matricula Incorreto!!!!!!\n"); printf("\n\nContinuar removendo aluno (1-sim/2-nao)? "); scanf("%d",&continuar); }while (continuar == 1); } 29 Estrutura de Dados //Consultar um aluno da escola void consultar() { int matcon, achou, continuar; do{ cabec(); printf("\nConsultar Aluno\n\n"); printf("\nMatricula do Aluno: "); scanf("%d",&matcon); achou = procura(matcon); if (achou!=-1) mostre(achou); else printf("\n\n\aNumero de Matricula Incorreto!!!!!!\n"); printf("\n\nContinuar consultando aluno(1-sim/2-nao)? "); scanf("%d",&continuar); }while (continuar == 1); } //Fazer alteracao dos dados de um aluno void alterar() { int matalt, achou, conalt, continuar; do{ cabec(); printf("\nAlterar Dados do Aluno\n\n"); printf("\nMatricula do Aluno: "); scanf("%d",&matalt); achou = procura(matalt); if (achou!=-1) { mostre(achou); printf("\nDeseja Alterar o nome do aluno (1-sim/2-nao)? "); scanf("%d",&conalt); if (conalt == 1) { printf("\nNome : "); fflush(stdin); gets(turma[achou].nome); } printf("\nDeseja Alterar a media do aluno (1-sim/2-nao)? "); scanf("%d",&conalt); if (conalt == 1) { printf("\nMedia: "); scanf("%f",&turma[achou].media); } mostre(achou); printf("\n\nAluno Alterado com Sucesso!!!\n"); } else printf("\n\n\aNumero de Matricula Incorreto!!!!!!\n"); printf("\n\nContinuar alterando aluno(1-sim/2-nao)? "); scanf("%d",&continuar); }while (continuar == 1); } 30 Estrutura de Dados //Imprimir o relatorio contendo os dados de todos os alunos void listagem() { int i; float soma=0; cabec(); printf("\nRelatorio Geral\n"); printf("\nMatricula Aluno Media"); printf("\n--------------------------------------------"); for(i = 0; i<qa; i++) { printf("\n%9d %-20s %5.2f", turma[i].mat, turma[i].nome, turma[i].media); soma += turma[i].media; } printf("\n--------------------------------------------"); printf("\n\nMedia da turma = %.2f",soma/qa); printf("\n\nDigite qualquer tecla para sair"); getche(); } //Programa principal main() { qa=0; do { cabec(); printf("\n Opcoes: \n\n"); printf("\t1- Inserir novo Aluno\n\n"); printf("\t2- Remover Aluno\n\n"); printf("\t3- Consultar Aluno\n\n"); printf("\t4- Alterar dados de Aluno\n\n"); printf("\t5- Listagem de Alunos\n\n"); printf("\t0- Sair do Programa\n\n\n"); linha(); printf("Informe a Opcao desejada: "); scanf("%d",&op); switch(op) { case 1: inserir(); break; case 2: remover(); break; case 3: consultar(); break; case 4: alterar(); break; case 5: listagem(); break; case 0: break; default : printf("\nOpcao Invalida! Tecle enter.."); getche(); break; } }while(op!=0); } 31 Estrutura de Dados 3.3 Fila Estática Nesta seção iremos verificar as operações em uma fila implementada com vetores. As operações básicas em uma fila: inserir elemento no final da fila, remover o elemento do início da fila, consultar o primeiro da fila, listar todos oserá implementado simula a fila de atendimento de um banco. 3.3.1 Operações Básicas Inserir Elemento Todo elemento que vai ser inserido em uma fila é colocado no final da estrutura. A figura abaixo ilustra a chegada de três clientes na fila. Os clientes vão sendo inseridos por ordem de chegada. Consultar Primeiro da Fila Em uma fila, a consulta é feita apenas do primeiro elemento da fila. Assim, teremos a informação de qual será o próximo elemento a ser retirado. Na figura abaixo, o primeiro elemento da fila é o cliente João, com conta número 3456. Quando o vetor estiver vazio, é apresentada uma mensagem de fila vazia ao usuário. 32 Estrutura de Dados Remover Primeiro da Fila Em uma fila, o elemento removido é sempre o que chegou há mais tempo, ou seja, o elemento da primeira posição do vetor. Na figura abaixo iremos remover o primeiro elemento da fila (neste caso, João). Os elementos seguintes devem ser deslocados uma posição a frente. Com isso, o segundo elemento da fila passa a ser o primeiro, o terceiro passa a ser o segundo e assim por diante. Listagem de Todos os Elementos da Fila A operação de listagem possibilita a visualização dos dados de todos os elementos da fila. É feita uma varredura no vetor e todos os dados de todos os elementos são apresentados ao usuário. 3.3.2 Algoritmo INICIO tipo regfila = registro caracter: nome; inteiro: conta, agencia; fimregistro; tipo vetorfila = vetor [1..50] de regfila; vetorfila: fila; inteiro: op, qe; módulo inserir; se (qe = 50) então escreva(″Fila cheia - não pode inserir″); senão 33 Estrutura de Dados inicio qe ← qe + 1; leia(fila[qe].agencia, fila[qe].conta, fila[qe].nome); escreva(″Inserido com sucesso″); fim; fimse; fimmóodulo; módulo consultarprimeiro; se (qe <> 0) então escreva(fila[1].agencia, fila[1].conta, fila[1].nome); senão escreva(″Fila Vazia″); fimse; fimmódulo; módulo removerprimeiro; inteiro: confirma, i; se (qe <> 0) então inicio escreva(fila[1].agencia, fila[1].conta, fila[1].nome); escreva(″Confirma remoção(1-sim/2-não)?″); leia(confirma); se (confirma = 1) então inicio para i de 1 até qe-1 faça turma[i] ← turma[i+1]; fimpara; qe ← qe - 1; escreva(″Removido com Sucesso″); fim; senão escreva(″Remocao Cancelada″); fimse; fim; senão escreva(″Fila Vazia″); fimse; fimmódulo; módulo listagem; inteiro: i; se (qe > 0) então inicio escreva(″Agencia Conta Nome″); para i de 1 até qe faça escreva(fila[i].agencia, fila[i].conta, fila[i].nome); fimpara; fim; senão escreva(″Fila Vazia″); fimse; fimmódulo; 34 Estrutura de Dados qe ← 0; repita escreva(“Informe a opcao desejada(1-inserir/2-remover primeiro /3-consultar primeiro/4-listagem/0-sair: “); leia(op); escolha op caso 1: inserir; caso 2: removerprimeiro; caso 3: consultarprimeiro; caso 4: listagem; fimescolha; até op = 0; FIM. 3.3.3 Programa em C #include <stdio.h> #include <conio.h> #include <stdlib.h> // Implementação de fila usando vetor /* Estrutura que será usada para cada elemento da fila */ typedef struct tipo_cliente { int conta, agencia; char nome[15]; int tipo; } TCliente; TCliente cliente[30]; TCliente cl; int op, tamfila; /************************************************************************/ void linha() { int i; for (i=1;i<=80;i++) printf("_"); printf("\n"); } void cabec() { system("cls"); printf("Banco Poupe Muito - Fila Estatica\n"); linha(); } /* Funcao para inserir um novo cliente no final da fila */ void inserir () { int continuar; do{ // leitura dos dados do cliente 35 Estrutura de Dados cabec(); printf("\n Chegada de novo cliente na fila \n"); printf("\n Numero da conta: "); scanf("%d",&cl.conta); printf("\n Numero da agencia: "); scanf("%d",&cl.agencia); printf("\n Nome: "); fflush(stdin); gets(cl.nome); printf("\n Tipo de cliente(1- especial, 2-normal): "); scanf("%d",&cl.tipo); // Inserir cliente na fila if (tamfila <30) /* Se ainda tem vaga na fila */ { cliente[tamfila] = cl; tamfila++; printf("\n\nInserido com Sucesso!!!!\n\n"); } else /* Fila cheia*/ printf("\n\nFila cheia, cliente nao inserido!!!!\n\n"); printf("\n Continuar inserindo (1-sim/2-nao)? "); scanf("%d",&continuar); }while (continuar == 1); // verifica se quer continuar inserindo } /* Consultar um primeiro cliente da fila */ void consultarprimeiro() { cabec(); printf("\nConsulta primeiro cliente da fila\n"); if (tamfila != 0) { printf("\n\nAgencia Conta Nome Tipo\n"); printf("--------------------------------------------------------\n"); printf("%4d %4d %-15s %2d\n", cliente[0].agencia,cliente[0].conta, cliente[0].nome, cliente[0].tipo); printf("--------------------------------------------------------\n"); } else printf("\n\nA fila está vazia!!\n\n"); printf("\n\nTecle enter para voltar para o menu\n"); getche(); } /* remover um cliente da fila */ void retirafila() { int i, confrem, continuar; do{ cabec(); printf("\nRetira primeiro cliente da fila \n"); if (tamfila != 0) // verifica se tem elementos na fila { printf("\n\nAgencia Conta Nome Tipo\n"); printf("---------------------------------------------------\n"); printf("%4d %4d %-15s %2d\n", cliente[0].agencia, cliente[0].conta, cliente[0].nome, cliente[0].tipo); printf("---------------------------------------------------\n"); 36 Estrutura de Dados printf("\n\nconfirma retirada do cliente (1-sim, 2-nao)? "); scanf("%d",&confrem); if (confrem ==1) // confirma que quer remover { for (i=0; i<tamfila; i++) cliente[i] = cliente[i+1]; tamfila--; printf("\n\n Retirado da fila com sucesso!!!!\n\n"); } else // cancelou a remocao printf("\n\n Retirada cancelada\n\n"); } else // fila vazia printf("\n\nFila vazia!!\n\n"); printf("\n\nDeseja retirar outro cliente(1-sim, 2-nao)? "); scanf("%d",&continuar); }while (continuar ==1); // continuar retirando cliente da fila } /* Lista todos os clientes da fila */ void listar () { int i; cabec(); printf("\nListagem de clientes da fila\n"); if (tamfila != 0) { printf("\n\nAgencia Conta Nome Tipo\n"); printf("-------------------------------------------------------\n"); for (i=0;i<tamfila;i++) printf("%4d %4d %-15s %2d\n", cliente[i].agencia,cliente[i].conta, cliente[i].nome, cliente[i].tipo); printf("-------------------------------------------------------\n"); printf("\n\nQuantidade de clientes na fila = %d\n",tamfila); } else printf("\n\n Nao tem nenhum cliente na fila"); printf("\n\n\nTecle enter para voltar para o menu\n"); getche(); } // Programa principal main() { tamfila= 0; do { cabec(); printf("\nOpcoes: "); printf("\n\n 1 - Inserir cliente na fila"); printf("\n\n 2 - Consultar primeiro da fila"); printf("\n\n 3 - Retirar primeiro cliente da fila"); printf("\n\n 4 - Listar todos os clientes da fila"); printf("\n\n 0 - para sair \n"); linha(); printf("\nEntre com a sua opcao: "); scanf("%d", &op); /* Le a opcao do usuario */ switch(op) { case 1: inserir(); break; 37 Estrutura de Dados case 2: consultarprimeiro();break; case 3: retirafila(); break; case 4: listar(); break; case 0: break; default: printf("\nOpcao nao valida"); } } while (op != 0); } 3.4 Pilha Estática A seguir vamos analisar a implementação de pilha estática. Neste exemplo será implementada uma pilha de livros. 3.4.1 Operações Básicas Inserir Elemento Todo elemento que vai ser inserido em uma pilha é colocado no final da estrutura. A figura abaixo ilustra a chegada de três livros colocados na pilha. Os livros vão sendo inseridos por ordem de chegada. Consultar Topo da Pilha Em uma pilha, a consulta é feita apenas do elemento do topo, ou seja o último elemento a ser inserido. Assim, teremos a informação de qual será o próximo elemento a ser retirado. Na figura abaixo, o elemento do topo da pilha é o livro de código 4 e título Física, armazenado na posição 3 do vetor. Quando o vetor estiver vazio, é apresentada uma mensagem de pilha vazia ao usuário. 38 Estrutura de Dados Remover Topo da Pilha Em uma pilha, o elemento removido é sempre o que chegou há menos tempo, ou seja, o elemento da última posição do vetor. Na figura abaixo iremos remover o elemento do topo da pilha (neste caso, o elemento da posição 3). Não há necessidade de deslocamentos. Listagem de Todos os Elementos da Pilha A operação de listagem possibilita a visualização dos dados de todos os elementos da pilha. É feita uma varredura no vetor e todos os dados de todos os elementos são apresentados ao usuário. 3.4.2 Algoritmo INICIO tipo regpilha = registro caracter: titulo; inteiro: codigo, editora; fimregistro; tipo vetorpilha = vetor [1..50] de regpilha; vetorpilha: pilha; inteiro: op, qe; módulo inserir; se (qe = 50) então escreva(″Pilha cheia - não pode inserir″); senão inicio qe ← qe + 1; 39 Estrutura de Dados leia(pilha[qe].codigo, pilha[qe].editora, pilha[qe].titulo); escreva(″Inserido com sucesso″); fim; fimse; fimmódulo; módulo consultartopo; se (qe <> 0) então escreva(pilha[qe].codigo, pilha[qe].editora, pilha[qe].titulo); senão escreva(″Pilha Vazia″); fimse; fimmódulo; módulo removertopo; inteiro: confirma; se (qe <> 0) então inicio escreva(pilha[qe].codigo, pilha[qe].editora, pilha[qe].titulo); escreva(″Confirma remoção(1-sim/2-não)?″); leia(confirma); se (confirma = 1) então inicio qe ← qe - 1; escreva(″Removido com Sucesso″); fim senão escreva(″Remocao Cancelada″); fimse; fim senão escreva(″Pilha Vazia″); fimse; fimmódulo; módulo listagem; inteiro: i; se (qe > 0) então inicio escreva(″Codigo Editora Titulo″); para i de 1 até qe faça escreva(pilha[i].codigo, pilha[i].editora, pilha[i].titulo); fimpara; fim; senão escreva(″Pilha Vazia″); fimse; fimmódulo; qe ← 0; repita escreva(“Informe a opcao desejada(1-inserir/2-remover topo /3-consultar topo/4-listagem/0-sair: “); 40 Estrutura de Dados leia(op); escolha op caso 1: inserir; caso 2: removertopo; caso 3: consultartopo; caso 4: listagem; fimescolha; até op = 0; FIM. 3.4.3 Programa em C #include <stdio.h> #include <conio.h> #include <stdlib.h> // Implementação de pilha usando vetor /* Estrutura que será usada para cada elemento da pilha */ typedef struct tipo_livro { int codigo, editora; char titulo[30]; } TLivro; TLivro livro[30]; TLivro ll; int op, tampilha; /***********************************************************************/ void linha() { int i; for (i=1;i<=80;i++) printf("_"); printf("\n"); } void cabec() { system("cls"); printf("Pilha de Livros - Estatica\n"); linha(); } /* Funcao para inserir um novo livro na pilha */ void inserir () { int continuar; do{ cabec(); printf("\nColocar livro no topo da pilha \n"); printf("\nCodigo do livro: "); scanf("%d",&ll.codigo); printf("\nTitulo do Livro: "); fflush(stdin); gets(ll.titulo); printf("\nEditora(1- Campus, 2-Makron Books, 3-Moderna): "); scanf("%d",&ll.editora); 41 Estrutura de Dados // Inserir livro na pilha if (tampilha <30) /* Se ainda tem vaga na pilha */ { livro[tampilha] = ll; tampilha++; printf("\n\nInserido com Sucesso!!!!\n\n"); } else /* Pilha cheia*/ printf("\n\nPilha cheia, Livro nao inserido!!!!\n\n"); printf("\n Continuar inserindo (1-sim/2-nao)? "); scanf("%d",&continuar); }while (continuar == 1); // verifica se quer continuar inserindo livros } /* Consultar topo da pilha*/ void consultatopo() { cabec(); printf("\nConsulta topo da pilha\n"); if (tampilha != 0) { printf("\n\nCod Titulo Editora\n"); printf("-----------------------------------------------------\n"); printf("%2d %-20s %7d\n", livro[tampilha-1].codigo, livro[tampilha-1].titulo, livro[tampilha-1].editora); printf("-----------------------------------------------------\n"); } else printf("\n\nA pilha esta vazia!!\n\n"); printf("\n\nTecle enter para voltar para o menu\n"); getche(); } /* remover um livro da pilha */ void retirapilha() { int i, confrem, continuar; do{ cabec(); printf("\nRetira livro do topo da pilha \n"); if (tampilha != 0) // verifica se tem elementos na pilha { printf("\n\nCodigo Titulo Editora\n"); printf("---------------------------------------------------\n"); printf("%6d %-20s %7d\n", livro[tampilha-1].codigo, livro[tampilha-1].titulo, livro[tampilha-1].editora); printf("---------------------------------------------------\n"); printf("\n\nconfirma retirada do livro (1-sim, 2-nao)? "); scanf("%d",&confrem); if (confrem ==1) // confirma que quer remover { tampilha--; printf("\n\n Retirado da Pilha com sucesso!!!!\n\n"); } else // cancelou a remocao printf("\n\n Retirada cancelada\n\n"); } else // pilha vazia printf("\n\nPilha vazia!!\n\n"); printf("\n\nDeseja retirar outro livro(1-sim, 2-nao)? "); scanf("%d",&continuar); 42 Estrutura de Dados }while (continuar ==1); // continuar retirando livro da pilha } /* Lista todos os livros da pilha */ void listar () { int i; cabec(); printf("\nListagem dos livros da pilha\n"); if (tampilha != 0) { printf("\n\nCodigo Titulo Editora\n"); printf("-----------------------------------------------------\n"); for (i=tampilha-1;i>=0;i--) printf("%6d %-20s %7d\n", livro[i].codigo, livro[i].titulo, livro[i].editora); printf("-----------------------------------------------------\n"); printf("\n\nQuantidade de livros na pilha = %d\n",tampilha); } else printf("\n\n Nao tem nenhum livro na pilha"); printf("\n\n\nTecle enter para voltar para o menu\n"); getche(); } // Programa principal main() { tampilha= 0; do { cabec(); printf("\nOpcoes: \n"); printf("\n 1 - Inserir livro na pilha"); printf("\n 2 - Consultar topo da pilha"); printf("\n 3 - Retirar livro do topo"); printf("\n 4 - Listar todos os livros da pilha"); printf("\n 0 - Sair \n"); linha(); printf("\nEntre com a sua opcao: "); scanf("%d", &op); /* Le a opcao do usuario */ switch(op) { case 1: inserir(); break; case 2: consultatopo();break; case 3: retirapilha(); break; case 4: listar(); break; case 0: break; default: printf("\n\n Opcao invalida"); getche(); break; } } while (op != 0); } 43 Estrutura de Dados 4. Implementação das Estruturas Dinâmicas A seguir, todos os programas das estruturas de dados feitos na seção anterior serão implementados utilizando alocação dinâmica (ponteiros). Quando alocamos espaço de memória de forma dinâmica, temos as seguintes vantagens: programas mais rápidos e uso eficiente da memória. No caso das estruturas dinâmicas, a implementação será mostrada diretamente na linguagem C. 4.1 Alocação Dinâmica Ponteiros Ponteiros são variáveis que armazenam um endereço de memória. Se uma variável contém o endereço de outra, então a primeira (o ponteiro) aponta para a segunda. int a,*x; x = &a; O ‘*’significa que esta sendo declarado o ponteiro x. O ponteiro "x" aponta para o "inteiro" a, ou seja, ele armazena o endereço de memória da variável a. Operadores • & (E comercial) fornece o endereço de determinada variável. Atribui o endereço de uma variável para um ponteiro. • * (Asterístico) que acessa o conteúdo de uma variável, cujo endereço é o valor do ponteiro. Não confundir com o operador aritmético de multiplicação de mesmo símbolo. Devolve o valor endereçado pelo ponteiro. main() { int *pont, cont, valor; cont = 100; pont = &cont; valor = *pont; printf("%d",valor); /* 100 */ } main() { int x,y,*px,*py; x = 100; px = &x; // px tem o endereco de x 44 Estrutura de Dados py = px; // py tem o endereco de x y = *py; // y = 100, pois recebe o valor de x através de py printf("%d %d",x,y); } Simule a execução dos programas abaixo: #include <stdio.h> main() { int i,k,*pi,*pk; i = 2; k = 0; pk = &k; pi = &i; *pk = i; // variável apontada por pk recebe o valor de i printf("para *pk = i, temos k= %d\n",k); k = *pi; printf("para k = *pi, temos k= %d\n",k); scanf("%c",&a); } #include <stdio.h> main() { int x,y,*px,*py; printf("Digite um valor: "); scanf("%d",&x); px = &x; y = *px; printf("digitou= %d e y= %d\n",x,y); *px = 8; printf("valor mudou para %d\n",x); } Funções malloc e free As funções malloc() e free() permitem que utilizemos a área de memória livre para criar nossas variáveis. As variáveis serão criadas em tempo de execução. A função malloc() aloca memória e tem esse protótipo: ponteiro = malloc(numero_de_bytes); – O numero_de_bytes é a quantidade de memória que deseja alocar; – A função malloc() retorna um ponteiro para a primeira área livre; – A função malloc faz parte a biblioteca stdlib.h int *p; p = malloc(10000); 45 Estrutura de Dados A função free() desaloca memória e tem esse protótipo: free(ponteiro); Ponteiro para registros typedef struct { int mat; char nome[15]; }TAluno; Declaração do ponteiro para registro TAluno *pa1 = NULL, *pa2 = NULL; Alocação de memória para um registro pa2 = (TAluno *)malloc(sizeof(TAluno)); Atribuição a um campo do registro pa2->mat = 3; for (i=0;i<=14;i++) pa2->nome[i] =nomel[i]; Liberar memória de endereço pa2 free(pa2); 4.2 Lista Dinâmica Desordenada Esta lista é implementada usando ponteiros. A memória para armazenar os dados é alocada em tempo de execução. Na próxima seção será descrito o funcionamento de cada uma das operações e na seção 4.2.2 temos o código de um programa completo que faz o cadastro dos alunos de uma turma em uma lista usando ponteiros. Esta lista possui dois ponteiros, um que guarda o endereço do primeiro elemento da lista (início) e outro que guarda o endereço do último elemento da lista (fim). 46 Estrutura de Dados 4.2.1 Operações Básicas Inserir Elemento A figura abaixo ilustra a inserção de três elementos em uma lista dinâmica desordenada. Inicialmente a lista está vazia, portanto o valor do ponteiro início e fim é NULL (passo 1). Quando um elemento vai ser inserido, a memória é alocada e os dados são armazenados (passo 2). Todo nó criado em uma lista dinâmica desordenada, não tem vizinho seguinte, por isso ele aponta para NULL. Na inserção do primeiro elemento, os ponteiros início e fim apontam para este elemento (no exemplo, endereço 1010). No passo 3 temos a chegada de um outro elemento. A memória é alocada e o novo nó tem os dados preenchidos e tem que ser anexado aos outros nós da lista. Todo nó que chega aponta para NULL e o ponteiro fim passa a ter o endereço do nó que acabou de chegar. O nó que anteriormente era o último da lista(1010) passará a ter como vizinho o nó que acabou de chegar (ou seja, aponta para 1040). O passo 4 mostra uma outra inserção de nó. Veja que a cada novo elemento, apenas o endereço do ponteiro fim é modificado. O ponteiro início permanece com o mesmo valor. 47 Estrutura de Dados Consultar Elemento Para fazer uma consulta em uma lista dinâmica é necessário saber qual elemento deseja consultar. Neste caso faremos uma consulta por matrícula. Um ponteiro auxiliar será usado para percorrer a lista, visitando cada nó a procura do elemento. Na figura acima temos uma lista com três elementos. Caso quiséssemos consultar o elemento de matrícula 25, iríamos percorrer a lista até chegar no último nó, cujo endereço do vizinho é NULL (nó de endereço 1080) e ficaríamos sabendo que este elemento não se encontra na lista. Quando um elemento é encontrado, seus dados são apresentados e quando ele não está na lista, uma mensagem de erro deve ser dada ao usuário. Remover Elemento Para a remover um elemento é necessário saber qual elemento deseja remover. Para isso, a matrícula do aluno a ser removido deve ser lida. É feita uma varredura em todos os nós da lista. Assim que o elemento é encontrado, seus dados devem ser apresentados ao usuário (neste caso a matrícula e o nome). Dessa forma ele pode verificar se realmente é aquele o elemento a ser removido. Quando o elemento não é encontrado, uma mensagem de erro deve ser dada ao usuário. Na figura a seguir são ilustrados os três casos de remoção: remover primeiro da lista, último da lista, elemento no meio da lista. No passo 1 temos a lista com cinco elementos. Primeiramente será feita a remoção do aluno com matrícula 10. Este é o primeiro nó da lista. Esta remoção é feita modificando o valor do nó início para o endereço do vizinho do nó que está sendo removido, neste caso, endereço 1040 (Passo 2). Em seguida será removido a aluno de matrícula 17. Este aluno é o ultimo nó da lista, a sua remoção irá ter que atualizar o ponteiro fim. Além disso o elemento que tinha como vizinho seguinte o nó de matrícula 17, terá agora NULL como vizinho. Portanto, dois ponteiros são atualizados (Passo 3). No passo 4 será feita a última remoção, aluno com matrícula 14 (endereço 1050), que está armazenado em um nó no meio da lista. Nesta remoção, os ponteiros início e fim não são alterados. No entanto, o elemento que vem antes do removido (1040), terá agora como vizinho o elemento que era vizinho do que será removido (1070). 48 Estrutura de Dados Listagem de Todos os Elementos A operação de listagem possibilita a visualização dos dados de todos os elementos cadastrados. É feita uma varredura na lista partindo do endereço início até o último nó, todos os dados de todos os elementos são apresentados ao usuário. 4.2.2 Programa em C #include #include #include // Lista <stdio.h> <conio.h> <stdlib.h> desordenada usando ponteiro - alocacao dinamica typedef struct tipo_aluno { int mat; char nome[20]; struct tipo_aluno *prox; } TAluno; 49 Estrutura de Dados TAluno *inicio = NULL; TAluno *fim = NULL; TAluno *noatual; int op, qa; /*****************************************************************/ void linha() { int i; for (i=1;i<=80;i++) printf("_"); printf("\n"); } void cabec() { system("cls"); printf("Faculdade Santa Maria - Lista Dinamica Desordenada\n"); linha(); } /* Funcao para inserir um novo no, ao final da lista */ void inserir () { TAluno *novono; int i, matl, continuar; char nomel[20]; do{ cabec(); printf("\n Inserir novo aluno \n"); printf("\n Matricula: "); scanf("%d",&matl); printf("\n Nome: "); fflush(stdin); gets(nomel); fflush(stdin); qa++; //Aloca memoria para o novo aluno e coloca os dados novono = (TAluno *)malloc(sizeof(TAluno)); novono->mat = matl; for (i=0;i<=19;i++) novono->nome[i] =nomel[i]; novono->prox = NULL; // Inserir novono na lista de alunos if (inicio == NULL) { inicio = novono; fim = novono; } else { fim->prox = novono; fim = novono; } printf("\n\nInserido com Sucesso!!!!\n"); printf("\nContinuar inserindo (1-sim/2-nao)? "); scanf("%d",&continuar); }while (continuar == 1); } 50 Estrutura de Dados /* Consultar um aluno na lista */ void consultar() { int matc, continuar, achou=0; do{ cabec(); printf("\nConsulta aluno pelo numero de matricula\n\n"); printf("\nMatricula: "); scanf("%d",&matc); noatual = inicio; while(noatual != NULL) { if (noatual->mat == matc) { achou = 1; printf("\n\nMatricula Nome\n"); printf("---------------------------------------\n"); printf("%9d %-20s\n",noatual->mat, noatual->nome); printf("---------------------------------------\n"); break; } else noatual = noatual->prox; } if (achou == 0) printf("\n\nAluno nao encontrado!!\n"); printf("\nContinuar consultando (1-sim/2-nao)? "); scanf("%d",&continuar); }while (continuar == 1); } /* remover um aluno da lista */ void remover() { TAluno *noantrem; int matr, confrem, continuar, achou; do{ achou = 0; cabec(); printf("\nRemove aluno \n\n"); printf("\nMatricula: "); scanf("%d",&matr); noatual = inicio; while(noatual != NULL) { if (noatual->mat == matr) { achou = 1; printf("\n\nMatricula Nome\n"); printf("---------------------------------------\n"); printf("%9d %-20s\n",noatual->mat, noatual->nome); printf("---------------------------------------\n"); printf("\n\nDeseja remover o aluno (1-sim, 2-nao)? "); scanf("%d",&confrem); if (confrem ==1) { if (noatual == inicio) inicio = inicio->prox; else { noantrem->prox=noatual->prox; if (noatual == fim) fim=noantrem; 51 Estrutura de Dados } qa--; free(noatual); printf("\n\nRemovido com sucesso!!!!\n"); } else printf("\n\nRemocao cancelada\n"); break; } else { noantrem = noatual; noatual = noatual->prox; } } if (achou == 0) printf("\n\nAluno nao encontrado!!\n"); printf("\n\nDeseja remover outro (1-sim, 2-nao)? "); scanf("%d",&continuar); }while (continuar ==1); } /* Lista todos os alunos presentes na lista */ void listar () { noatual = inicio; cabec(); printf("\nListagem de Alunos\n\n"); if (qa != 0) { printf("\n\nMatricula Nome\n"); printf("---------------------------------------\n"); while( noatual != NULL) { printf("%9d %-20s\n",noatual->mat, noatual->nome); noatual = noatual->prox; } printf("---------------------------------------\n"); printf("\n\nQuantidade de Alunos = %d\n",qa); } else printf("\n\n Nao tem nenhum aluno cadastrado"); printf("\n\n\nTecle enter para voltar para o menu\n"); getche(); } //Programa Principal main() { qa = 0; do { cabec(); printf("\n Opcoes: \n\n"); printf("\t1- Inserir novo Aluno\n\n"); printf("\t2- Remover Aluno\n\n"); printf("\t3- Consultar Aluno\n\n"); printf("\t4- Listagem de Alunos\n\n"); printf("\t0- Sair do Programa\n\n\n"); linha(); 52 Estrutura de Dados printf("Informe a Opcao desejada: "); scanf("%d",&op); switch(op) { case 1: inserir(); break; case 2: remover(); break; case 3: consultar(); break; case 4: listar(); break; case 0: break; default : printf("\nOpcao Invalida! break; } }while(op!=0); noatual = inicio; while (noatual != NULL) { inicio = noatual->prox; free(noatual); noatual = inicio; } } Tecle enter..."); getche(); 4.3 Lista Dinâmica Ordenada Esta lista é implementada usando ponteiros, no entanto, quando for feito o caminhamento pelos nós da lista, ela deve estar ordenada por algum campo, neste exemplo o campo de ordenação é a matrícula. Esta lista possui apenas o ponteiro início, que guarda o endereço do primeiro elemento da lista. 4.3.1 Operações Básicas Inserir Elemento Na figura é ilustrada a inserção de quatro elementos em uma lista dinâmica ordenada. No passo 1 a lista está vazia, com o ponteiro início apontando para NULL. No passo 2 temos a inserção do elemento de matrícula 17. Como a lista está vazia, o ponteiro início vai apontar para este elemento (endereço 1080). No passo 3 temos a chegada de um outro elemento, matrícula 10. É verificado que ele tem a matrícula menor do que o primeiro elemento da lista, então este novo elemento terá que ser inserido no início da lista. Assim, o elemento novo vai apontar para o primeiro da lista e o ponteiro início irá apontar para o novo nó. Em seguida, teremos a inserção de um aluno com matrícula 14, que será inserido no meio da lista. Para isso, teremos que descobrir entre quais elementos ele irá ser inserido, para manter a lista ordenada e fazer as ligações dos ponteiros corretamente. 53 Estrutura de Dados Finalmente, no passo 5 teremos a inserção do aluno com matrícula 22. Esse será inserido no final da lista. Consultar Elemento Para fazer uma consulta é necessário primeiro saber qual elemento deseja consultar. Um ponteiro auxiliar será usado para percorrer a lista, visitando cada nó a procura do elemento. Na figura acima temos uma lista com quatro elementos. Caso quiséssemos consultar o elemento de matrícula 25, iríamos percorrer a lista até chegar no último nó, cujo endereço do vizinho é NULL (nó de endereço 1040) e ficaríamos sabendo que este elemento não se encontra na lista. Se procurássemos a matrícula 8, assim que fosse feita a comparação com o primeiro elemento da lista, já saberíamos que a matricula 8 não se encontra na lista e a consulta é finalizada. A busca é executada enquanto não encontra o elemento procurado ou enquanto não encontra um elemento cuja matrícula é maior do que a matrícula que está sendo procurada. 54 Estrutura de Dados Remover Elemento A remoção em uma lista dinâmica ordenada segue a mesma regra de uma lista desordenada. A única diferença é que não teremos o ponteiro fim para atualizar. Para remover um elemento é necessário saber qual elemento deseja remover. Para isso, a matrícula do aluno a ser removido deve ser lida. É feita uma varredura em todos os nós da lista. Assim que o elemento é encontrado, seus dados devem ser apresentados ao usuário (neste caso a matrícula e o nome). Quando o elemento não é encontrado, uma mensagem de erro deve ser dada ao usuário. Na figura a seguir são ilustrados os dois casos de remoção: primeiro da lista e meio ou fim da lista. Quando o primeiro elemento da lista é removido, passo 2, o endereço do início precisa ser atualizado. No passo 3 o elemento a ser removido é o último da lista. Neste caso, o elemento que apontava para o elemento removido (1080), terá que apontar para o elemento que o elemento removido aponta (NULL). Listagem de Todos os Elementos A operação de listagem possibilita a visualização dos dados de todos os elementos cadastrados. É feita uma varredura na lista partindo do endereço início até o último nó, todos os dados de todos os elementos são apresentados ao usuário. 55 Estrutura de Dados 4.3.2 Programa em C #include #include #include // Lista <stdio.h> <conio.h> <stdlib.h> ordenada usando ponteiro - alocacao dinamica /* Estrutura que será usada para criar os nós da lista */ typedef struct tipo_aluno { int mat; char nome[15]; struct tipo_aluno *prox; } TAluno; TAluno *inicio = NULL; /* Ponteiro para a inicio da lista */ TAluno *noatual; /* Ponteiro a ser usado para percorrer a lista*/ int op, qa; void linha() { int i; for (i=1;i<=80;i++) printf("_"); printf("\n"); } void cabec() { system("cls"); printf("Faculdade Santa Maria - Lista Dinamica Ordenada\n"); linha(); } /* Funcao para inserir um novo no, ao final da lista */ void inserir () { TAluno *novono, *antinserido; int i, matl,continuar; char nomel[15]; do{ cabec(); printf("\nInserir novo aluno \n"); printf("\nMatricula: "); scanf("%d",&matl); fflush(stdin); printf("\nNome: "); gets(nomel); qa++; //Aloca memoria para o novo aluno e coloca os dados novono = (TAluno *) malloc(sizeof(TAluno)); novono->mat = matl; for (i=0;i<=14;i++) novono->nome[i] =nomel[i]; antinserido = NULL; // Inserir novono na lista de alunos if (inicio == NULL) /* Ainda nao existe nenhum aluno na lista */ { inicio = novono; novono->prox = NULL; } 56 Estrutura de Dados else { noatual = inicio; if (noatual->mat > matl) // aluno inserido no inicio da lista { novono->prox = inicio; inicio = novono; } else // aluno sera inserido no meio ou final da lista { while(noatual != NULL) { if (noatual->mat < matl) // procura o local da insercao { antinserido = noatual; noatual = noatual->prox; } else // encontrou o local onde sera inserido noatual = NULL; } novono->prox = antinserido->prox; antinserido->prox = novono; } } printf("\n\nInserido com Sucesso!!!!\n"); printf("\nContinuar inserindo (1-sim/2-nao)? "); scanf("%d",&continuar); }while (continuar == 1); // verifica se quer continuar removendo } /* Consultar um aluno na lista */ void consultar() { int matc, continuar, achou=0; do{ cabec(); printf("\nConsulta aluno pelo numero de matricula\n\n"); printf("Matricula: "); scanf("%d",&matc); noatual = inicio; // coloca ponteiro no inicio da lista while(noatual != NULL) // percorre a lista procurando o aluno { if (noatual->mat == matc) // aluno encontrado { achou = 1; printf("\n\nMat Nome \n"); printf("----------------------------\n"); printf("%2d %-15s\n", noatual->mat, noatual->nome); printf("----------------------------\n"); break; } else // procura no proximo aluno { noatual = noatual->prox; if (noatual != NULL) { if (noatual->mat > matc) break; } } } if (achou == 0) // aluno nao esta na lista printf("\n\nAluno nao encontrado!!\n\n"); printf("\nContinuar consultando (1-sim/2-nao)? "); scanf("%d",&continuar); 57 Estrutura de Dados }while (continuar == 1); } /* remover um aluno da lista */ void remover() { TAluno *noantrem; int matr, confrem, continuar, achou; do{ achou = 0; cabec(); printf("\nRemove aluno \n\n"); printf("Matricula: "); scanf("%d",&matr); noatual = inicio; //ponteiro que ira percorrer a lista while(noatual != NULL) // percorre a lista a procura do aluno { if (noatual->mat == matr) // verifica se é o aluno { achou = 1; // impressao dos dados do aluno para conferencia printf("\n\nMatricula Nome\n"); printf("----------------------------------------\n"); printf("%9d %-15s\n", noatual->mat, noatual->nome); printf("----------------------------------------\n"); printf("\n\nDeseja remover o aluno (1-sim, 2-nao)? "); scanf("%d",&confrem); if (confrem ==1) // confirma que quer remover { if (noatual == inicio) // verifica se é o primeiro da lista inicio = inicio->prox; else // removido esta no meio ou final da lista noantrem->prox=noatual->prox; // atualiza a quatidade de alunos e reprovados ou aprovados qa--; free(noatual); // libera memoria do no removido printf("\n\n Removido com sucesso!!!!\n"); } else // cancelou a remocao printf("\n\n Remocao cancelada\n"); break; } else // passa para o proximo no para continuar a busca { noantrem = noatual; noatual = noatual->prox; if (noatual !=NULL) { if (noatual->mat > matr) break; } } } if (achou == 0) // o elemento nao foi encontrado na lista printf("\n\nAluno nao encontrado!!\n\n"); printf("\n\nDeseja remover outro (1-sim, 2-nao)? "); scanf("%d",&continuar); }while (continuar ==1); // continuar removendo aluno } 58 Estrutura de Dados /* Lista todos os alunos presentes na lista */ void listar () { noatual = inicio; // no auxiliar marca o inicio da lista cabec(); printf("\nListagem de Alunos\n\n"); if (qa != 0) // verifica se tem aluno cadastrado { printf("\n\nMatricula Nome\n"); printf("----------------------------------------\n"); while( noatual != NULL) // percorre toda a lista ate chegar no final { printf("%9d %-15s\n", noatual->mat, noatual->nome); noatual = noatual->prox; // Faz noatual apontar para o proximo no } printf("----------------------------------------\n"); printf("\n\nQuantidade de Alunos: %d\n",qa); } else printf("\n\nNao tem nenhum aluno cadastrado"); printf("\n\nTecle enter para voltar para o menu..."); getche(); } // Programa principal main() { qa = 0; do { cabec(); printf("\nOpcoes: \n\n"); printf(" 1 - Inserir novo aluno\n"); printf(" 2 - Consultar aluno\n"); printf(" 3 - Remover aluno\n"); printf(" 4 - Listar todos os alunos\n"); printf(" 0 - para sair \n\n"); printf("Entre com a sua opcao: "); scanf("%d", &op); /* Le a opcao do usuario */ switch(op) { case 1: inserir(); break; case 2: consultar();break; case 3: remover(); break; case 4: listar(); break; case 0: break; default: printf("\n\n Opcao invalida"); getche(); break; } fflush(stdin); /* Limpa o buffer de entrada */ } while (op != 0); /* Desaloca a memoria alocada para os elementos da lista */ noatual = inicio; while (noatual != NULL) { inicio = noatual->prox; free(noatual); noatual = inicio; } } 59 Estrutura de Dados 4.4 Lista Duplamente Encadeada Ordenada Nessa lista teremos dois ponteiros em cada nó. Um que irá armazenar o endereço do nó anterior e o outro pra armazenar o endereço do nó posterior. Dessa forma, as consultas serão melhoradas e podemos percorrer a lista da esquerda para direita e da direita para esquerda. 4.4.1 Operações Básicas Inserir Elemento Na figura é ilustrada a inserção de três elementos em uma lista duplamente encadeada ordenada. No passo 1 a lista está vazia, com o ponteiro início apontando para NULL. No passo 2 temos a inserção do elemento de matrícula 17. Como a lista está vazia, o ponteiro início vai apontar para este elemento (endereço 1080). Este nó não tem vizinhos, por isso os seus ponteiros apontam para NULL. No passo 3 temos a chegada de um outro elemento, matrícula 10. É verificado que ele tem a matrícula menor do que o primeiro elemento da lista, então este novo elemento terá que ser inserido no início da lista. Assim, o elemento novo vai apontar para o primeiro da lista e o ponteiro início irá apontar para o novo nó e o elemento que era o primeiro da lista, terá o elemento novo como vizinho anterior. Em seguida, teremos a inserção de um aluno com matrícula 14, que será inserido no meio da lista. Para isso, teremos que descobrir entre quais elementos ele irá ser inserido, para manter a lista ordenada e fazer as ligações dos ponteiros corretamente. 60 Estrutura de Dados Consultar Elemento Para fazer uma consulta é necessário primeiro saber qual elemento deseja consultar. Um ponteiro auxiliar será usado para percorrer a lista, visitando cada nó a procura do elemento. A consulta é similar a consulta em uma lista de encadeamento simples. Remover Elemento Para remover um elemento é necessário saber qual elemento deseja remover. Para isso, a matrícula do aluno a ser removido deve ser lida. É feita uma varredura em todos os nós da lista. Assim que o elemento é encontrado, seus dados devem ser apresentados ao usuário (neste caso a matrícula e o nome). Quando o elemento não é encontrado, uma mensagem de erro deve ser dada ao usuário. Na figura a seguir será ilustrada a remoção do primeiro elemento da lista (matrícula 10). Quando o primeiro elemento da lista é removido, passo 2, o endereço do início precisa ser atualizado. Além disso, o segundo elemento da lista (matrícula 14), passará a ser o primeiro e por isso, não terá mais vizinho anterior. Listagem de Todos os Elementos A operação de listagem possibilita a visualização dos dados de todos os elementos cadastrados. É feita uma varredura na lista partindo do endereço início até o último nó, todos os dados de todos os elementos são apresentados ao usuário. 4.4.2 Programa em C #include #include #include // Lista <stdio.h> <conio.h> <stdlib.h> duplamente encadeada - alocacao dinamica typedef struct tipo_aluno { int mat; char nome[15]; float m; 61 Estrutura de Dados struct tipo_aluno *ant, *prox; } TAluno; TAluno *inicio = NULL; /* Ponteiro para a inicio da lista */ TAluno *noatual; /* Ponteiro a ser usado para percorrer a lista*/ int op, qa; /*************************************************************************/ void linha() { int i; for (i=1;i<=80;i++) printf("_"); printf("\n"); } void cabec() { system("cls"); printf("Faculdade Santa Maria - Lista Duplamente Encadeada Ordenada\n"); linha(); } /* Funcao para inserir um novo no, ao final da lista */ void inserir () { TAluno *novono, *antinserido; int i, matl, continuar; float ml; char st, nomel[15]; do{ cabec(); printf("\n Inserir novo aluno \n"); printf("\n Matricula: "); scanf("%d",&matl); printf("\n Nome: "); fflush(stdin); gets(nomel); printf("\n media: "); scanf("%f",&ml); qa++; //Aloca memoria para o novo aluno e coloca os dados novono = (TAluno *) malloc(sizeof(TAluno)); novono->mat = matl; for (i=0;i<=14;i++) novono->nome[i] =nomel[i]; novono->m = ml; antinserido = NULL; // Inserir novono na lista de alunos if (inicio == NULL) /* Ainda nao existe nenhum aluno na lista */ { inicio = novono; novono->prox = NULL; novono->ant = NULL; } else // ja existem alunos na lista { noatual = inicio; if (noatual->mat > matl) // aluno sera inserido no inicio 62 Estrutura de Dados { novono->prox = inicio; novono->ant = NULL; inicio->ant = novono; inicio = novono; } else // aluno sera inserido no meio ou final da lista { while(noatual != NULL) { if (noatual->mat < matl) // procura o local da insercao { antinserido = noatual; noatual = noatual->prox; } else // encontrou o local onde sera inserido break; } novono->prox = antinserido->prox; novono->ant = antinserido; antinserido->prox = novono; if (noatual != NULL) noatual->ant = novono; } } printf("\n\nInserido com Sucesso!!!!\n\n"); printf("\n Continuar inserindo (1-sim/2-nao)? "); scanf("%d",&continuar); }while (continuar == 1); // verifica se quer continuar removendo } /* Consultar um aluno na lista */ void consultar() { int matc, continuar, achou=0; do{ cabec(); printf("\nConsulta aluno pelo numero de matricula\n\n"); printf("\nMatricula: "); scanf("%d",&matc); noatual = inicio; // coloca ponteiro no inicio da lista while(noatual != NULL) // percorre a lista procurando o aluno { if (noatual->mat == matc) // aluno encontrado { achou = 1; printf("\n\nMat Nome Media\n"); printf("-----------------------------------------\n"); printf("%2d %-15s %5.2f\n", noatual->mat, noatual->nome,noatual->m); printf("-----------------------------------------\n"); break; } else // procura no proximo aluno { noatual = noatual->prox; if (noatual != NULL) { if (noatual->mat > matc) break; } } } 63 Estrutura de Dados } if (achou == 0) // aluno nao esta na lista printf("\n\nAluno nao encontrado!!\n\n"); printf("\nContinuar consultando (1-sim/2-nao)? "); scanf("%d",&continuar); }while (continuar == 1); /* remover um aluno da lista */ void remover() { TAluno *noantrem, *noposrem; int matr, confrem, continuar, achou; do{ achou = 0; cabec(); printf("\nRemove aluno \n\n"); printf("\nMatricula: "); scanf("%d",&matr); noatual = inicio; //ponteiro que ira percorrer a lista while(noatual != NULL) // percorre a lista a procura do aluno { if (noatual->mat == matr) // verifica se é o que deseja remover { achou = 1; // impressao dos dados do aluno para conferencia printf("\n\nMat Nome Media\n"); printf("---------------------------------------\n"); printf("%2d %-15s %5.2f\n", noatual->mat, noatual->nome,noatual->m); printf("---------------------------------------\n"); printf("\n\nDeseja remover o aluno (1-sim, 2-nao)? "); scanf("%d",&confrem); if (confrem ==1) // confirma que quer remover { if (noatual == inicio) // verifica se é o primeiro da lista { inicio = inicio->prox; inicio->ant = NULL; } else // removido esta no meio ou final da lista { noantrem->prox=noatual->prox; noposrem= noatual->prox; if (noposrem != NULL) noposrem->ant = noantrem; } // atualiza a quatidade de alunos e reprovados ou aprovados qa--; free(noatual); // libera memoria do no removido printf("\n\n Removido com sucesso!!!!\n\n"); } else // cancelou a remocao { printf("\n\n Remocao cancelada\n\n"); } break; } 64 Estrutura de Dados else // passa para o proximo no para continuar a busca { noantrem = noatual; noatual = noatual->prox; if (noatual !=NULL) if (noatual->mat > matr) break; } } if (achou == 0) // o elemento nao foi encontrado na lista printf("\n\nAluno nao encontrado!!\n\n"); printf("\n\nDeseja remover outro (1-sim, 2-nao)? "); scanf("%d",&continuar); }while (continuar ==1); // continuar removendo aluno } /* Lista todos os alunos presentes na lista */ void listar () { noatual = inicio; // no auxiliar marca o inicio da lista cabec(); printf("\nListagem de Alunos\n\n"); if (qa != 0) // verifica se tem aluno cadastrado { printf("\n\nMat Nome Media\n"); printf("-----------------------------------------\n"); while( noatual != NULL) { printf("%2d %-15s %5.2f\n", noatual->mat, noatual->nome,noatual->m); noatual = noatual->prox; // Faz noatual apontar para o proximo no } printf("-----------------------------------------\n"); printf("\n\nQuantidade de Alunos = %d\n",qa); } else printf("\n\n Nao tem nenhum aluno cadastrado"); printf("\n\n\nTecle enter para voltar para o menu\n"); getche(); } //Programa principal main() { qa = 0; do { cabec(); printf("\n Opcoes: \n\n"); printf("\t1- Inserir novo Aluno\n\n"); printf("\t2- Remover Aluno\n\n"); printf("\t3- Consultar Aluno\n\n"); printf("\t4- Listagem de Alunos\n\n"); printf("\t0- Sair do Programa\n\n\n"); linha(); printf("Informe a Opcao desejada: "); scanf("%d",&op); switch(op) { case 1: inserir(); break; case 2: remover(); break; case 3: consultar(); break; 65 Estrutura de Dados case 4: listar(); break; case 0: break; default : printf("\nOpcao Invalida! Tecle enter..."); getche(); break; } } }while(op!=0); noatual = inicio; while (noatual != NULL) { inicio = noatual->prox; free(noatual); noatual = inicio; } 4.5 Fila Dinâmica Nesta seção iremos analisar as operações básicas em uma fila implementada com ponteiros e posteriormente o seu código em C. 4.5.1 Operações Básicas Inserir Elemento Todo elemento que vai ser inserido em uma fila é colocado no final da estrutura. 66 Estrutura de Dados A figura ilustra a chegada de dois clientes na fila. Inicialmente a fila está vazia, portanto o valor do ponteiro início e fim é NULL (passo 1). Quando um elemento vai ser inserido, a memória é alocada e os dados são armazenados (passo 2). Todo nó criado em uma fila dinâmica, não tem vizinho seguinte, por isso ele aponta para NULL. Na inserção do primeiro elemento, os ponteiros início e fim apontam para este elemento (no exemplo, endereço 1010). No passo 3 temos a chegada do cliente 12, que será armazenado no final da estrutura, o último elemento da fila o terá (endereço 1070) como vizinho e o ponteiro fim irá apontar para o novo elemento. Consultar Primeiro da Fila Em uma fila, a consulta é feita apenas do primeiro elemento da fila. Assim teremos a informação de qual será o próximo elemento a ser retirado. O primeiro elemento da fila é o elemento do endereço início. Quando início estiver apontando para NULL, significa que a fila está vazia. Remover Primeiro da Fila Em uma fila, o elemento removido é sempre o que chegou há mais tempo, ou seja, o elemento apontado por início. Quando um elemento é removido, o endereço do ponteiro início deve apontar para o vizinho do primeiro da fila. Listagem de Todos os Elementos da Fila A operação de listagem possibilita a visualização dos dados de todos os elementos da fila. É feita uma varredura na fila e todos os dados de todos os elementos são apresentados ao usuário. 67 Estrutura de Dados 4.5.2 Programa em C #include <stdio.h> #include <conio.h> #include <stdlib.h> // Implementação de fila usando ponteiro /* Estrutura que será usada para criar os nós da fila */ typedef struct tipo_cliente { int conta, agencia; char nome[15]; int tipo; struct tipo_cliente *prox; } TCliente; TCliente *inicio = NULL; /* Ponteiro para o inicio da fila */ TCliente *fim = NULL; /* Ponteiro para o fim da fila */ TCliente *noatual; /* Ponteiro a ser usado para percorrer a fila*/ int op, tamfila; /*************************************************************************/ void linha() { int i; for (i=1;i<=80;i++) printf("_"); printf("\n"); } void cabec() { system("cls"); printf("Banco Poupe Muito - Fila Dinamica\n"); linha(); } /* Funcao para inserir um novo no, ao final da fila */ void inserir () { TCliente *novono; int i, contal, agencial, tipol, continuar; char nomel[15]; do{ // leitura dos dados do cliente cabec(); printf("\n Chegada de novo cliente na fila \n"); printf("\n Numero da conta: "); scanf("%d",&contal); printf("\n Numero da agencia: "); scanf("%d",&agencial); printf("\n Nome: "); fflush(stdin); gets(nomel); printf("\n Tipo de cliente(1- especial, 2-normal): "); scanf("%d",&tipol); tamfila++; //Aloca memoria para o novo cliente 68 Estrutura de Dados novono = (TCliente *) malloc(sizeof(TCliente)); novono->conta = contal; novono->agencia = agencial; for (i=0;i<=14;i++) novono->nome[i] =nomel[i]; novono->tipo = tipol; novono->prox = NULL; // Inserir novono na fila de cliente if (inicio == NULL) /* Se ainda nao existe nenhum cliente na fila */ { inicio = novono; fim = novono; } else /* Se ja existem clientes na fila*/ { fim->prox = novono; /* Faz o ultimo no apontar para o novo no */ fim = novono; /* final da fila é atualizado */ } printf("\n\nInserido com Sucesso!!!!\n\n"); printf("\n Continuar inserindo (1-sim/2-nao)? "); scanf("%d",&continuar); }while (continuar == 1); // verifica se quer continuar inserindo } /* Consultar um primeiro cliente da fila */ void consultarprimeiro() { cabec(); printf("\nConsulta primeiro cliente da fila\n\n"); noatual = inicio; // coloca ponteiro no inicio da lista if (noatual != NULL) { printf("\n\nAgencia Conta Nome Tipo\n"); printf("-------------------------------------------------------\n"); printf("%4d %4d %-15s %2d\n", noatual->agencia, noatual->conta, noatual->nome, noatual->tipo); printf("-------------------------------------------------------\n"); } else printf("\nA fila está vazia!!\n\n"); printf("\n\nTecle enter para voltar para o menu\n"); getche(); } /* remover um cliente da fila */ void retirafila() { int confrem, continuar; do{ cabec(); printf("\nRetira primeiro cliente da fila \n\n"); noatual = inicio; //ponteiro que ira apontar para o primeiro no if (noatual != NULL) // verifica se tem elementos na fila { printf("\n\nAgencia Conta Nome Tipo\n"); printf("---------------------------------------------------\n"); printf("%4d %4d %-15s %2d\n", noatual->agencia, noatual->conta, noatual->nome, noatual->tipo); printf("---------------------------------------------------\n"); 69 Estrutura de Dados printf("\n\nconfirma retirada do cliente (1-sim, 2-nao)? "); scanf("%d",&confrem); if (confrem ==1) // confirma que quer remover { inicio = inicio->prox; free(noatual); // libera memoria do no removido tamfila--; printf("\n\n Retirado da fila com sucesso!!!!\n\n"); } else // cancelou a remocao printf("\n\n Retirada cancelada\n\n"); } else // fila vazia printf("\n\nFila vazia!!\n\n"); printf("\n\nDeseja retirar outro cliente(1-sim, 2-nao)? "); scanf("%d",&continuar); }while (continuar ==1); // continuar retirando cliente da fila } /* Lista todos os clientes da fila */ void listar () { noatual = inicio; // no auxiliar marca o inicio da lista cabec(); printf("\nListagem de clientes da fila\n\n"); if (tamfila != 0) { printf("\n\nAgencia Conta Nome Tipo\n"); printf("-------------------------------------------------------\n"); while( noatual != NULL) // percorre toda a fila ate chegar no final { printf("%4d %4d %-15s %2d\n", noatual->agencia, noatual->conta, noatual->nome, noatual->tipo); noatual = noatual->prox; // Faz noatual apontar para o proximo no } printf("-------------------------------------------------------\n"); printf("\n\nQuantidade de clientes na fila = %d\n",tamfila); } else printf("\n\n Nao tem nenhum cliente na fila"); printf("\n\n\nTecle enter para voltar para o menu\n"); getche(); } // Programa principal main() { tamfila= 0; do { cabec(); printf("\nOpcoes: "); printf("\n\n 1 - Inserir cliente na fila"); printf("\n\n 2 - Consultar primeiro da fila"); printf("\n\n 3 - Retirar primeiro cliente da fila"); printf("\n\n 4 - Listar todos os clientes da fila"); printf("\n\n 0 - para sair \n"); linha(); printf("\nEntre com a sua opcao: "); scanf("%d", &op); /* Le a opcao do usuario */ 70 Estrutura de Dados } switch(op) { case 1: inserir(); break; case 2: consultarprimeiro();break; case 3: retirafila(); break; case 4: listar(); break; case 0: break; default: printf("\nOpcao nao valida"); } } while (op != 0); noatual = inicio; while (noatual != NULL) { inicio = noatual->prox; free(noatual); noatual = inicio; } 4.6 Pilha Dinâmica Nesta seção iremos analisar as operações básicas em uma pilha implementada com ponteiros e posteriormente o seu código em C. 4.6.1 Operações Básicas Inserir Elemento Todo elemento que vai ser inserido em uma pilha é colocado no final da estrutura. A figura abaixo ilustra a chegada de três livros colocados na pilha. 71 Estrutura de Dados Cada elemento que chega, será inserido no início da estrutura. Portando, o ponteiro início é sempre modificado a cada inserção. Na Figura a pilha inicia vazia, com o ponteiro início apontando para NULL (Passo 1). No passo 2 um elemento é inserido na pilha, por ser o primeiro, ele não tem vizinho e o ponteiro início passa a apontar para o novo nó (endereço 1080). No passo 3 um novo elemento é inserido, o ponteiro início deve ser atualizado e o novo nó deve apontar para o elemento que estava no início da pilha (endereço 1080). No passo 4, um novo elemento é inserido e as atualizações dos ponteiros devem ser feitas. Consultar Topo da Pilha Em uma pilha, a consulta é feita apenas do elemento do topo, ou seja o último elemento a ser inserido, que neste caso é o elemento apontado pelo ponteiro início. Se o ponteiro início aponta para NULL significa que a pilha está vazia. Remover Topo da Pilha Em uma pilha, o elemento removido é sempre o que chegou há menos tempo, ou seja, o elemento da apontado pelo ponteiro início. Na figura abaixo iremos remover o elemento do topo da pilha. O ponteiro início deve ser atualizado, apontando para o elemento que era vizinho do elemento removido. Listagem de Todos os Elementos da Pilha A operação de listagem possibilita a visualização dos dados de todos os elementos da pilha. É feita uma varredura na pilha e todos os dados de todos os elementos são apresentados ao usuário. 4.6.1 Programa em C #include <stdio.h> #include <conio.h> #include <stdlib.h> // Implementação de pilha usando ponteiro 72 Estrutura de Dados /* Estrutura que será usada para criar os nós da pilha */ typedef struct tipo_livro { int codigo, editora; char titulo[30]; struct tipo_livro *prox; } TLivro; TLivro *inicio = NULL; /* Ponteiro para o inicio da pilha */ TLivro *noatual; /* Ponteiro a ser usado para percorrer a pilha*/ int op, tampilha; /*************************************************************************/ void linha() { int i; for (i=1;i<=80;i++) printf("_"); printf("\n"); } void cabec() { system("cls"); printf("Pilha de Livros - Dinamica\n"); linha(); } /* Funcao para inserir um novo no, no inicio da pilha */ void inserir () { TLivro *novono; int i, codl, edl, continuar; char titl[30]; do{ cabec(); printf("\nColocar livro no topo da pilha \n"); printf("\nCodigo do livro: "); scanf("%d",&codl); printf("\nTitulo do Livro: "); fflush(stdin); gets(titl); printf("\nEditora(1- Campus, 2-Makron Books, 3-Moderna): "); scanf("%d",&edl); // Inserir livro na pilha tampilha++; //Aloca memoria para o novo livro novono = (TLivro *) malloc(sizeof(TLivro)); novono->codigo = codl; novono->editora = edl; for (i=0;i<=29;i++) novono->titulo[i] =titl[i]; novono->prox = inicio; inicio = novono; printf("\n\nInserido com Sucesso!!!!\n\n"); printf("\nContinuar inserindo (1-sim/2-nao)? "); scanf("%d",&continuar); }while (continuar == 1); // verifica se quer continuar inserindo livros } 73 Estrutura de Dados /* Consultar livro do topo da pilha */ void consultatopo() { cabec(); printf("\nConsulta topo da pilha\n\n"); if (inicio != NULL) { printf("\n\nCodigo Titulo Editora\n"); printf("-----------------------------------------------------\n"); printf("%6d %-20s %7d\n", inicio->codigo, inicio->titulo,inicio->editora); printf("-----------------------------------------------------\n"); } else printf("\nA pilha está vazia!!\n\n"); printf("\n\nTecle enter para voltar para o menu\n"); getche(); } /* remover livro do topo da pilha */ void retirapilha() { int confrem, continuar; do{ cabec(); printf("\nRetira livro do topo da pilha \n"); noatual = inicio; //ponteiro que ira apontar para o primeiro no if (inicio != NULL) // verifica se tem elementos na pilha { printf("\n\nCodigo Titulo Editora\n"); printf("---------------------------------------------------\n"); printf("%6d %-20s %7d\n", inicio->codigo, inicio->titulo,inicio->editora); printf("---------------------------------------------------\n"); printf("\n\nconfirma retirada do livro (1-sim, 2-nao)? "); scanf("%d",&confrem); if (confrem ==1) // confirma que quer remover { inicio = inicio->prox; free(noatual); // libera memoria do no removido tampilha; printf("\n\n Retirado da Pilha com sucesso!!!!\n\n"); } else // cancelou a remocao printf("\n\n Retirada cancelada\n\n"); } else // pilha vazia printf("\n\nPilha vazia!!\n\n"); printf("\n\nDeseja retirar outro livro(1-sim, 2-nao)? "); scanf("%d",&continuar); }while (continuar ==1); // continuar retirando livro da pilha } /* Lista todos os livros da pilha */ void listar () { noatual = inicio; // no auxiliar marca o inicio da lista cabec(); printf("\nListagem dos livros da pilha\n\n"); 74 Estrutura de Dados } if (inicio != NULL) { printf("\n\nCodigo Titulo Editora\n"); printf("-----------------------------------------------------\n"); while( noatual != NULL) // percorre toda a pilha { printf("%6d %-20s %7d\n", noatual->codigo, noatual->titulo, noatual->editora); noatual = noatual->prox; // Faz noatual apontar para proximo no } printf("-----------------------------------------------------\n"); printf("\n\nQuantidade de livros na pilha = %d\n",tampilha); } else printf("\n\n Nao tem nenhum livro na pilha"); printf("\n\n\nTecle enter para voltar para o menu\n"); getche(); //Programa principal main() { tampilha= 0; do { cabec(); printf("\nOpcoes: \n"); printf("\n 1 - Inserir livro na pilha"); printf("\n 2 - Consultar topo da pilha"); printf("\n 3 - Retirar livro do topo"); printf("\n 4 - Listar todos os livros da pilha"); printf("\n 0 - Sair \n"); linha(); printf("\nEntre com a sua opcao: "); scanf("%d", &op); /* Le a opcao do usuario */ switch(op) { case 1: inserir(); break; case 2: consultatopo();break; case 3: retirapilha(); break; case 4: listar(); break; case 0: break; default: printf("\n\n Opcao invalida"); getche(); break; } } while (op != 0); noatual = inicio; while (noatual != NULL) { inicio = noatual->prox; free(noatual); noatual = inicio; } } 75 Estrutura de Dados 5. Ordenação e Pesquisa A ordenação facilita o acesso aos dados. Quando recebemos um conjunto de dados desordenados, devemos realizar sobre eles um pré-processamento de forma a classificá-los. Muitas vezes necessitamos organizar uma estrutura de dados para facilitar a pesquisa. Para alcançarmos um dado armazenado na estrutura, também temos que usar métodos de pesquisa (busca) eficientes. Neste tópico iremos tratar métodos clássicos de ordenar uma lista desordenada implementada com vetores e métodos de pesquisa para buscas em uma lista estática ordenada. 5.1 Ordenação Os métodos de ordenação de dados realizam classificações segundo uma chave de ordenação. Nesta chave, especifica-se o tipo de ordem que queremos dar aos dados (crescente, decrescente, etc.) e o campo da estrutura que será afetado (campo nome, campo matrícula, etc.). Tipos de métodos de ordenação: • Por troca: são baseados na troca de posição dos dados, de forma a ordená-los. • Por seleção:parte do princípio de realizar o isolamento de elementos para posições ordenadas. • Por inserção: baseiam-se no deslocamento de elementos da estrutura frente a um elemento de busca. Imagine as cartas de um baralho: • Para ordenar as cartas utilizando troca, espalhe-as voltadas para cima e então troque as cartas fora de ordem até que todo baralho esteja ordenado; • Utilizando seleção, espalhe as cartas na mesa, selecione a carta de menor valor, retire-a do baralho e coloque-a na mão. O processo continua e termina quando todas as cartas estiverem na sua mão; • Para ordenar as cartas por inserção, segure todas as cartas na mão. Ponha uma carta por vez na mesa, sempre a inserindo na posição correta. 5.1.1 Método da Ordenação por Troca Método da Bolha(bubble sort): esse metodo é muito simples de implementar, no entando é um dos piores métodos de ordenção quando se fala de desempenho. Ela envolve repetidas comparações e, se necessário, a troca de dois elementos adjacentes. A figura a seguir mostra o que acontece com o vetor no decorrer da execução do método da bolha. 76 Estrutura de Dados 5.1.2 Método da Ordenação por Seleção Este método procura o menor elemento do vetor e coloca na primeira posição. A seguir, procura o menor elemento do vetor a partir do segundo elemento e coloca na segunda posição do vetor. Continua o processo até que existam apenas os dois últimos elementos do vetor para serem comparados. 77 Estrutura de Dados A figura a seguir mostra o que acontece com o vetor no decorrer da execução do método de ordenação por seleção. 78 Estrutura de Dados 5.1.3 Método da Ordenação por Inserção Inserção Direta: Neste método, considera-se o segmento já ordenado como sendo formado pelo primeiro elemento do vetor de chaves. Os demais elementos, ou seja do 2º ao último, pertencem ao segmento não ordenado. A partir desta situação inicial, toma-se um a um dos elementos não ordenados, a partir do primeiro e, por busca seqüencial realizada no segmento já ordenado, localiza-se a sua posição relativa correta. Após a inserção, a fronteira entre os dois segmentos é deslocada uma posição para a direita, indicando, com isto, que o segmento ordenado ganhou um elemento e o não ordenado perdeu um. O processo prossegue até que todos os elementos do segundo segmento tenham sido inseridos no primeiro. A figura a seguir mostra o que acontece com o vetor no decorrer da execução deste método. 79 Estrutura de Dados 5.2 Pesquisa Busca de dados dentro de um conjunto. A Busca seqüencial procura do primeiro ao último elemento do vetor até encontrar o elemento. Método mais simples, já utilizado nos nossos programas. A Busca Binária é o método aplicado para conjunto de dados ordenados. Muito parecido com o método que usamos quando desejamos procurar um número numa lista telefônica. Programa que implementa os métodos de ordenação e pesquisa #include <stdio.h> #include <conio.h> #include <stdlib.h> // Programa para executar metodos de ordenação numa lista desordenada // estatica typedef struct { int mat; char nome[31], sit; float nota1, nota2, media; }alunos; alunos turma[30]; float soma; int qa, ap,rp,op; void linha() { int i; for (i=1;i<=80;i++) printf("_"); printf("\n"); } void cabec() { system("cls"); printf("Faculdade Santa Maria - Ordenacao e Pesquisa\n"); linha(); } //Inserir novo aluno void inserir() { int cont; do{ cabec(); printf("\n\nInserir Novo Aluno\n\n"); printf("\n\tNumero de Matricula do Aluno: "); scanf("%d",&turma[qa].mat); printf("\n\tNome: "); fflush(stdin); gets(turma[qa].nome); printf("\n\tNota 1: "); scanf("%f",&turma[qa].nota1); printf("\n\tNota 2: "); scanf("%f",&turma[qa].nota2); 80 Estrutura de Dados } turma[qa].media= (turma[qa].nota1+turma[qa].nota2)/2; soma += turma[qa].media; if (turma[qa].media>=6) { turma[qa].sit= 'A'; ap++; } else { turma[qa].sit= 'R'; rp++; } qa++; printf("\n\n\tAluno Inserido com Sucesso!!!\n\n"); printf("\n\n\tContinuar inserindo aluno (1-sim/2-nao)? "); scanf("%d",&cont); }while (cont == 1); //Metodo de ordenação da Bolha void bolha() { int i, fim, troquei; alunos aux; fim = qa-1; do { troquei = 0; for (i=0; i<=fim-1; i++) { if (turma[i].mat > turma[i+1].mat) { aux = turma[i]; turma[i] = turma[i+1]; turma[i+1] = aux; troquei = 1; } } fim--; } while (troquei ==1); printf("\n\n Ordenacao pelo metodo da Bolha\n\n"); printf("\n\n Vetor Ordenado com Sucesso!!!\n\n"); getche(); } //Metodo de ordenação por Inserção void insercao() { int i, k; alunos aux; for (i=1; i<=qa-1; i++) { k=i; aux = turma[i]; while ((k>0)&&(aux.mat<turma[k-1].mat)) { turma[k] = turma[k-1]; k--; } turma[k]=aux; } printf("\n\n Ordenacao pelo metodo da Insercao\n\n"); 81 Estrutura de Dados } printf("\n\n Vetor Ordenado com Sucesso!!!\n\n"); getche(); //Metodo de ordenação por Seleção void selecao() { int i,k,pmenor; alunos aux; for (i=0; i<=qa-2; i++) { pmenor = i; for (k=i+1; k<=qa-1; k++) { if (turma[k].mat < turma[pmenor].mat) pmenor = k; } if (i!=pmenor) { aux = turma[i]; turma[i] = turma[pmenor]; turma[pmenor] = aux; } } printf("\n\n Ordenacao pelo metodo da Selecao\n\n"); printf("\n\n Vetor Ordenado com Sucesso!!!\n\n"); getche(); } // Metodos de Busca com para listas ordenadas //Metodo de busca binaria void binaria() { int matcon, achou, continuar, inicio, fim, meio; alunos aux; do{ cabec(); printf("\n\nConsultar Aluno - Busca Sequencial\n\n"); printf("\n\tNumero de Matricula do Aluno: "); scanf("%d",&matcon); achou = 0; inicio = 0; fim = qa-1; while (inicio<=fim) { meio = (inicio + fim)/2; printf("\nmeio = %d\n\n",meio); if (turma[meio].mat == matcon) { printf("\nMat Aluno Nota1 Nota2 Media Sit"); printf("\n--------------------------------------------------"); printf("\n%2d %-20s %5.2f %5.2f %5.2f %c", turma[meio].mat, turma[meio].nome, turma[meio].nota1, turma[meio].nota2, turma[meio].media, turma[meio].sit); printf("\n--------------------------------------------------"); achou = 1; break; } 82 Estrutura de Dados if (matcon >turma[meio].mat) inicio = meio +1; else fim = meio -1; } if (achou == 0) printf("\n\n\tNumero de Matricula Incorreto!!!!!!\n\n"); printf("\n\n\tContinuar consultando aluno(1-sim/2-nao)? "); scanf("%d",&continuar); }while (continuar == 1); } //Metodo de busca sequencial void sequencial() { int i, matcon, achou, continuar; do{ cabec(); printf("\n\nConsultar Aluno - Busca Sequencial\n\n"); printf("\n\tNumero de Matricula do Aluno: "); scanf("%d",&matcon); achou = -1; for(i = 0; i<qa; i++) { if (matcon==turma[i].mat) { achou = i; break; } else { if (matcon<turma[i].mat) break; } } if (achou!=-1) { printf("\nMat Aluno Nota1 Nota2 Media Sit"); printf("\n--------------------------------------------------"); printf("\n%2d %-20s %5.2f %5.2f %5.2f %c", turma[achou].mat,turma[achou].nome, turma[achou].nota1, turma[achou].nota2,turma[achou].media,turma[achou].sit); printf("\n--------------------------------------------------"); } else printf("\n\n\tNumero de Matricula Incorreto!!!!!!\n\n"); printf("\n\n\tContinuar consultando aluno(1-sim/2-nao)? "); scanf("%d",&continuar); }while (continuar == 1); } //Imprimir relatorio com as informaçoes de todos alunos void listagem() { int i; cabec(); printf("\n\nRelatorio Geral\n"); printf("\nMat Aluno Nota1 Nota2 Media Sit"); printf("\n------------------------------------------------------------"); for(i = 0; i < qa; i++) printf("\n%2d %-20s %5.2f %5.2f %5.2f %c",turma[i].mat, 83 Estrutura de Dados turma[i].nome, turma[i].nota1, turma[i].nota2, turma[i].media, turma[i].sit); printf("\n------------------------------------------------------------"); printf("\n\nMedia da turma = %.2f",soma/qa); printf("\n\nQuantidade de aprovados = %d",ap); printf("\n\nQuantidade de reprovados = %d",rp); printf("\n\n\tDigite qualquer tecla para sair\n\n\n "); getche(); } //Programa principal main() { op = 1; soma = 0; ap = rp = qa =0; while (op != 0) { cabec(); printf("Opcoes: \n\n"); printf(" 1- Inserir Aluno\n\n"); printf(" 2- Ordenacao Bolha\n\n"); printf(" 3- Ordenacao por Selecao\n\n"); printf(" 4- Ordenacao por Insercao\n\n"); printf(" 5- Busca Sequencial\n\n"); printf(" 6- Busca Binaria\n\n"); printf(" 7- Listagem\n\n"); printf(" 0- Sair do Programa\n"); linha(); printf(" Informe a Opcao desejada: "); scanf("%d",&op); switch(op) { case 1: inserir(); break; case 2: bolha(); break; case 3: selecao(); break; case 4: insercao(); break; case 5: sequencial(); break; case 6: binaria(); break; case 7: listagem(); break; case 0: break; default: printf("\nOpcao Invalida!!!!"); getche();break; } } } 84