A estrutura de dados uma disciplina que trabalha com mtodos de
organizao lgica dos dados, dando-lhes atributos mais funcionais do que se estivessem sem qualquer tipo de estruturao. Dentre as vrias atividades da estrutura de dados, esto o desenvolvimento de estruturas clssicas, como pilhas, filas, listas, deques, rvores! mtodos de pesquisa "pesquisa linear, pesquisa binria#, mtodos de ordenao, ou classificao, "$ooble %ort, &uic' %ort, (eap %ort, etc#, entre outras. Atualmente, uma grande fatia da performance dos grandes programas dependente da efici)ncia das estruturas de dados utilizadas na sua implementao. Tipos Abstratos de Dados *ipos abstratos de dados so tipos criados arbitrariamente pelo programador, sem que este+am definidos na linguagem de programao como tipos de dados primitivos. ,a realidade, os tipos abstratos de dados so uni-es de tipos de dados primitivos e, at mesmo, outros tipos abstratos de dados, formando uma .nica estrutura, semelhante a uma ficha com vrios campos, sendo que a ficha corresponde ao registro "ou struct, como chamada em /# e os campos correspondem 0s variveis internas da struct. 1s tipos abstratos de dados devem ser previamente declarados antes de serem utilizados, ou se+a, antes de ser declarada uma varivel com seu tipo. 1 acesso aos dados de uma 2struct3 so realizados atravs de uma varivel de acesso, declarada com o mesmo tipo do nome atribu4do ao registro. 5eralmente os tipos abstratos de dados so utilizados onde h a necessidade de armazenar diversos dados semelhantes referentes a um mesmo tipo de entidade. 6or e7emplo, os dados sobre funcionrios, sobre carros, sobre pessoas, clientes, etc. Abai7o, um e7emplo de declarao de uma struct para armazenar dados sobre um funcionrio8 struct endereco 9 char rua:;<=! char bairro:><=! char complemento:?<=! int numero! @! struct funcionario 9 char nomeAcompleto:B<<=! struct endereco endAfuncionario! int idade! float salario! @! Cepare que a declarao possui tipos de dados primitivos "int, char, float# e abstratos "struct endereco#. A fim de acessar um campo da struct funcionrio, devemos criar uma varivel do seu tipo8 struct funcionario f! Assim, a varivel f do tipo funcionrio, possuindo todos os campos listados na declarao do tipo de dado funcionrio. 6ara acessar um campo desta varivel, procede-se assim8 f.nomeAcompleto, f.idade, f.salario 6ara acessar um campo de um tipo abstrato de dado dentro de outro tipo, faz-se8 f.endAfuncionario.rua, f.endAfuncionario.bairro ESTRUTURAS DE DADOS CLSSICAS PILHA A pilha uma estrutura de dados que se assemelha a uma pilha do mundo real "uma pilha de livros, de pratos, de /DDs, etc#. A pilha baseia-se na idia de que os elementos so empilhados seqEencialmente, uns sobre os outros, sendo o elemento presente no topo o .ltimo a ter sido nela colocado. A retirada de elementos seqEencial e apenas o elemento do topo pode ser retirado. Fm outras palavras8 O primeiro elemento a ser colocado o ltimo a ser retirado! O ltimo elemento a ser colocado o primeiro a ser retirado! *al afirmao, em ingl)s, gerou a sigla LI"O #Last In$ "irst Out% para designar as pilhas. As principais opera-es que podem ser realizadas em uma pilha so8 Gnserir elemento no topo Cetirar elemento do topo Histar Flementos /ontar elementos Gnicializar a pilha 6esquisar por elemento As pilhas so declaradas como tipos abstratos de dados, sendo o m4nimo necessrio para seu funcionamento8 um vetor, cu+o tamanho representa o tamanho m7imo a que a pilha pode chegar uma varivel inteira, responsvel por controlar o topo da pilha. Ie+a como seria declarar uma pilha em /8 struct pilha 9 int vet:B<=! int topo! @! Deste modo, declaramos uma pilha que ter no m7imo B< elementos inteiros empilhados. A fim de utilizarmos suas fun-es bsicas, devemos inicializ-la, criando uma varivel do tipo pilha, primeiramente. struct pilha p! 1 pr7imo passo obrigatrio inicializar o valor do topo. J recomendvel que tal inicializao se+a feita em uma funo espec4fica para este fim. void inicializa"void# 9 p.topo K -B! @ Fmbora o valor do topo possa ser inicializado com zero, muito mais conveniente e prtico inicializ-lo com -B! Aps terem sido efetuados todos os procedimentos acima descritos, podemos comear a escrever as funcionalidades bsicas de pilha8 Gnsero A insero insere um elemento no topo da pilha. J conveniente checar, antes de cada insero, se a pilha no ir ser estourada caso um novo elemento se+a inserido. int insercao"int elemento# 9 if"p.topoLM# 9 p.vet:NNp.topo= K elemento! @else9 printf"2FrroO 6ilha Hotada3#! @ return <! @ Ie+a que a insero apenas realizada caso o topo se+a inferior 0 .ltima posio. /aso contrrio, mesmo que ele se+a igual a .ltima posio "que M, pois vet:B<= varia de vet:<= at vet:M=#, ocorrer um estouro, visto que o topo incrementado aps o teste ter sido realizado. ,a linha p.vet:NNp.topo= K elemento! fazemos, primeiramente, o incremento do topo. /aso se+a a primeira insero "p.topo KK -B, conforme inicializado#, teremos, antes de a insero ser efetuada, p.topo KK <, graas ao operador de incremento NN antes de p.topo, o que crucial "/aso voc) coloque o operador NN aps a varivel, ele colocar o primeiro elemento na posio -B, pois o incremento ser feito aps a insero. Iale ressaltar que este um erro grave na programao#. Cemoo Assim como na insero fazemos um teste para verificar se o vetor estourar "overfloP#, na remoo devemos verificar se h elementos a serem retirados antes de efetuarmos a retirada. Iale destacar que a pilha estar vazia quando o valor do topo for igual ao valor que atribu4mos a ele na inicializao! no nosso caso, -B. Hembre-se que a cada elemento retirado, o valor do topo dever ser decrementado. Abai7o, uma funo para retirar elementos da pilha8 int remover "void# 9 if"p.topoQ-B# 9 int removido K p.vet:p.topo=! p.topo--! printf"2Ioc) removeu o elemento Rd3, removido#! @else9 printf"2Frro ao remover elemento. 6ilha vazia.3#! @ return <! @ Cepare que atribu4mos 0 varivel 2int removido3 o elemento do topo que ser removido, para que possamos mostr-lo na tela. As tr)s linhas que utilizamos aps o 2if3 poder4am ser escritas em uma s8 printf"2Flemento removido8 Rd3, p.vet:p.topo--=#! Cepare que mostramos o elemento do topo antesde acontecer o decremento. 1 operador 2--3 aps a varivel do topo nos garante isso. Histar elementos 6ara listar elementos de uma pilha, utilizamos um lao de repetio de primeira posio at o topo. /omo nosso topo foi inicializado em -B, ele est sempre apontando para o .ltimo elemento que foi inserido. Fnto o lao deve iniciar em zero e fazer repeti-es at que encontremos um valor superior ao do topo. for"iK<! iLKp.topo! iNN# 9 printf"2RdSn3, p.v:i=#! @ Ioc) pode tambm mostrar o elemento do topo acima dos demais, basta inverter a ordem do lao8 for"iKp.topo! iQK<! i--# 9 printf"2RdSn3, p.v:i=#! @ /ontar Flementos 1 n.mero de elementos da pilha sempre ser igual ao nosso valor do topo acrescido de B. 6or e7emplo, quando o topo vale <, significa que + colocamos um elemento, pois ele foi inicializado com -B. Assim8 ,.mero de elementos da pilha K valor do topo N B! Hogo, quando p.topo KK <8 ,.mero de elementos da pilha K < N B ,.mero de elementos da 6ilha K B Fm linguagem /8 int contaFlementos"void# 9 printf"2A pilha possui Rd elementos. 2, p.topoNB#! return <! @ 6esquisa 6ara pesquisar um elemento, e7ecutamos um lao semelhante ao que e7ecutamos para mostrar todos os elementos da pilha. Ambos percorrem a pilha inteira, entretanto, enquanto um apenas imprime os elementos, o outro, faz compara-es entre os elementos que esto na pilha e o elemento que o usurio quer buscar. int busca "int elementoAprocurado# 9 int i! int flag K <! for"iK<! iLKp.topo! iNN# 9 if"elementoAprocurado KK p.vet:i=# 9 flagNN! @ @ if"flagQ<# 9 printf"21 elemento foi encontrado Rd vezes na pilha3, flag#! @else9 printf"21 elemento no foi encontrado na pilha.3#! @ return <! @ Cepare que a varivel inteira flag inicializada com < e incrementada caso encontremos na pilha um elemento igual ao procurado. Aps termos pesquisado por toda a pilha "ou se+a, o lao ter-se e7ecutado totalmente#, caso a flag tenha valor superior a zero, sinal que encontramos o elemento pelo qual procurvamos. /aso contrrio, ele no foi encontrado. "ILA A fila segue um padro semelhante ao da pilha, alteram-se apenas as caracter4sticas referentes a insero de elementos. Tma fila se assemelha a uma fila de pessoas, na qual a primeira pessoa a chegar a primeira a sair. As .ltimas pessoas que chegam ocupam as .ltimas posi-es da fila e so as .ltimas a sair dela. A sigla UGU1 a e7plicao genrica da fila8 Uirst Gn, Uirst 1ut. 1u se+a, o primeiro a entrar nela , tambm, o primeiro a sair. Fm uma fila, precisamos controlar a posio do primeiro elemento e do .ltimo elemento. 6or trabalharmos linearmente, assumimos, por praticidade, como a posio inicial da fila "aquela que ocupar o elemento que ser o primeiro a ser removido, quando houver uma remoo# a primeira posio do vetor, ou se+a, aquela inde7ada por 4ndice <. Deste modo, eliminamos a necessidade de uma varivel para controlar o seu in4cio, que ser fi7o. /aso se este+a trabalhando com uma fila circular, esta varivel obrigatria. As opera-es que podemos realizar em uma fila so semelhantes 0s realizadas em uma pilha8 Gnserir elemento no final da fila Cetirar elemento do in4cio da fila Histar Flementos /ontar elementos Gnicializar a fila 6esquisar por elemento Ieremos a seguir, como elas funcionam. Antes de comear a trabalharmos com suas fun-es, devemos declarar o tipo abstrato de dado fila, a varivel de acesso 0 fila e inicializ-la. struct fila 9 int vet:B<=! int fim! @! struct fila f! Ie+a que nossa fila poder ter no m7imo B< elementos. A fim de inicializ-la, criaremos uma funo espec4fica para isso. 1 valor inicial da posio fim -B, que indica 2fila vazia3. void inicializa"void# 9 f.fim K -B! @ A partir de agora, podemos comear a trabalhar com as opera-es de nossa fila. Gnsero Fm uma fila os elementos so sempre inseridos na .ltima posio, ou se+a, aquela referenciada pela varivel 2fim3. A insero de elementos de uma fila bastante semelhante 0 de uma pilha, fazendo inclusive, o mesmo teste a fim de testar se ela no ser estourada aps a insero. int inserir "int elemento# 9 if"f.fimLVAW-B# 9 f.vet:NNf.fim= K elemento! @else9 printf"2Gmposs4vel inserir elemento. Uila lotada3.#! @ return <! @ Cemoo A remoo de elementos de uma fila bem diferente da de uma pilha. Fm uma fila, remove-se o primeiro elemento e h a necessidade de fazer todos os demais elementos da fila avanarem uma posio "e7ceto se voc) estiver trabalhando com uma fila circular#. A cada remoo, a varivel responsvel por controlar o fim da fila deve ser decrementada. Analogamente 0 pilha, aqui tambm fazemos um teste a fim de verificar se h elementos a serem removidos, antes de e7ecutarmos a remoo. int remover "void# 9 if"f.fim Q -B# 9 int i! int removido K f.vet:<=! for"iK<! iLf.fim! iNN# 9 f.vet:i= K f.vet:iNB=! @ f.fim--! printf"21 elemento Rd foi removido da fila.3, removido#! @else9 printf"2Frro ao remover elemento. A fila est vazia.3#! @ return <! @ ,a linha int removido K f.vet:<=! guardamos o elemento que foi removido em uma varivel, a fim de mostr-lo ao usurio aps a remoo ter sido efetuada. Aps isso, no lao de repetio de zero at a posio final X B "ou se+a, de iK< at iLf.fim# fazemos todas as posi-es da fila, da segunda at a .ltima, avanarem uma posio. Assim, sobrepomos o elemento removido "que estava na primeira posio, 4ndice <# e fazemos a fila 2andar3. ,o se pode esquecer da linha f.fim--! que decrementa o ponteiro que aponta para o final da fila, aps termos e7ecutado o lao. Vostrar Flementos, /ontar elementos, 6esquisar por Flemento Fssas tr)s opera-es e7ecutadas em filas so id)nticas como as e7ecutadas nas pilhas. Heia como elas so e7plicadas para as pilhas que, certamente, entender como funcionam para as listas. A .nica diferena significativa que a varivel de 2topo3 nas pilhas substitu4da pela varivel de 2fim3, nas filas. *odavia, os procedimentos de procura, listagem e contagem so e7ecutados da mesma forma. DE&UE 1 deque consiste em duas pilhas horizontais cu+a base de uma est em contato direto com a base da outra. As regras de operao do deque so as seguintes8 1s elementos so inseridos a partir do seu centro. Hogo, cada lado preenchido do centro 0 lateral. 1s elementos retirados so os das e7tremidades! Tm lado no pode sobrepor o outro. Assim, deve-se estar atento para ocorr)ncias de overfloP e underfloP. As opera-es que podemos e7ecutar em um deque so8 Gnserir elemento 0 esquerda! Gnserir elemento 0 direita! Cemover elemento 0 esquerda! Cemover elemento 0 direita! Gnicializar deque! Vostrar deque! 6esquisar no deque "em um dos lados ou nele inteiro#. /ontar elementos do deque A seguir, veremos cada uma delas. G,G/GAHGYAC DF&TF Tm deque deve ser declarado, no m4nimo, com os seguintes campos8 um vetor, que ser o prprio deque! um ponteiro que controla o lado esquerdo! um ponteiro que controla o lado direito. struct deque 9 int vet:B<= int ptrdir! int ptresq! @! %eu acesso se d atravs da varivel declarada com seu tipo8 struct deque d! A inicializao do deque deve estabelecer posi-es iniciais para os ponteiros. Fm nosso deque, como possui tamanho m7imo de B< elementos, teremos cinco para cada lado. Gnicializaremos os ponteiros uma posio alm "NB 0 esquerda e -B 0 direita# da qual ser inserido o primeiro elemento. A razo disso simples8 estaremos decrementando "0 esquerda# e incrementando "0 direita# estes ponteiros antes da insero do elemento. Z esquerda, a primeira posio ser > "de < at >, temos ; elementos#. Assim, o ptresq ser inicializado com valor ;. 1 primeiro elemento 0 direita ser inclu4do na posio ;. 6ortanto, inicializaremos o ptrdir com o valor >. void inicializa"void# 9 int d.ptrdir K >! int d.ptresq K ;! @ G,%FCGC FHFVF,*1 Z F%&TFCDA &uando inserimos um elemento 0 esquerda, antes de tudo, devemos verificar se o lado esquerdo no est lotado. /omo o lado esquerdo vai at zero e o ponteiro que o controla "ptresq# aponta para o .ltimo elemento, caso seu valor se+a igual a zero, teremos o lado cheio. Aps termos feito o teste e verificado que o vetor no est lotado, decrementamos o ponteiro da esquerda A,*F% de inserir o elemento. "Hembre- se de que ele foi inicializado na posio posterior 0 primeira posio do lado esquerdo. Abai7o, a funo de insero de elemento no lado esquerdo do deque8 int insereFsquerda"int elemento# 9 if"d.ptresqQ<# 9 d.vet:--d.ptresq= K elemento! @else9 printf"2FrroO 1 deque est lotado 0 esquerda.3#! @ return <! @ ,ote que, como os elementos so inseridos a partir do centro, devemos DF/CFVF,*AC o ptresq a cada insero. G,%FCGC FHFVF,*1 Z DGCFG*A A insero 0 direita semelhante 0 da esquerda, entretanto, aqui devemos G,/CFVF,*AC o ponteiro a cada elemento inserido. 1 controle de overfloP aqui feito pela comparao do ponteiro da direita com o .ltimo elemento do vetor, ou se+a, o valor m7imo X B. ,o nosso e7emplo, como o vetor de B< elementos, o referencial ser o n.mero M. J altamente recomendvel utilizar um 2[define VAW B<3 no in4cio do cdigo a fim de facilitar seu entendimento. /aso isso fosse feito, comparar4amos ptrdir a VAW X B8 caso fosse menor, poder4amos realizar a insero, caso contrrio, ou se+a, igual, significa que a .ltima posio + foi ocupada e uma nova insero provocar um overfloP. Abai7o, a funo de insero 0 direita8 int insereDireita"int elemento# 9 if"d.ptrdirLVAW-B# 9 d.vet:NNd.ptrdir= K elemento! @else9 printf"2FrroO 1 deque est lotado 0 direita.3#! @ return <! @ CFV1IFC FHFVF,*1 Z F%&TFCDA Antes de removermos um elemento da esquerda do deque, devemos nos assegurar de que h elementos a serem removidos. 1 teste feito com a comparao entre o valor do ponteiro da esquerda "ptresq# e o valor com o qual ele foi inicializado no in4cio do programa "neste e7emplo, ;#. /aso ele se+a igual a ;, nosso deque est vazio 0 esquerda e no poderemos realizar a remoo de elemento. /aso contrrio, procederemos a remoo de um elemento apenas realizando a 16FCA\]1 /1,*C^CGA 0 realizada na insero. ,a insero 0 esquerda, DF/CFVF,*AV1% ptresq para acomodar um novo elemento. ,a remoo, G,/CFVF,*AV1% ptresq para que ele faa a e7cluso do elemento que est 0 e7tremidade esquerda do deque. Ie+a um e7emplo em funo8 int removeFsquerda"void# 9 if"d.ptresqL;# 9 d.ptresqNN! @else9 printf"2Gmposs4vel retirar elemento. Deque vazio 0 esquerda.3#! @ return <! @ /aso voc) quisesse mostrar o elemento removido, bastaria acrescentar a linha8 printf"2Rd3, d.vet:ptresq=#! antes de realizar o incremento. CFV1IFC FHFVF,*1 Z DGCFG*A Assim como fizemos na remoo 0 esquerda, na remoo 0 direita tambm faremos a operao inversa que fizemos na insero neste mesmo lado. ,a insero 0 direita, incrementamos ptrdir. ,a remoo, o decrementamos. Da mesma forma, antes de efetuar qualquer alterao no deque, checamos a consist)ncia de operao de remoo, ou se+a, deve e7istir algum elemento a ser removido. /aso o ponteiro da direita "ptrdir# tenha o mesmo valor de sua inicializao "no nosso e7emplo, >#, isso significa que o lado direito do que est vazio. Ie+a uma funo de remoo 0 direita8 int removeDireita"void# 9 if"d.ptrdirQ># 9 printf"2Ioc) removeu o elemento8 Rd3, d.vet:d.ptrdir--=#! @else9 printf"2FrroO Gmposs4vel retirar elemento. Deque vazio 0 direita.3#! @ return <! @ Cepare que usamos o operador de decremento aps a varivel d.ptrdir . Assim, primeiro imprimimos na tela seu conte.do e depois a decrementamos. 6F%&TG%AC FV TV HAD1 D1 DF&TF A pesquisa em um lado do deque deve percorrer desde a posio em que ouve a sua inicializao "entretanto, no devemos consider-la, pois ela faz parte do outro ladoO Apenas G,G/GAHGYAV1% a partir dela, mas as inser-es so feitas 0 frente "no caso do lado direito# ou atrs "no caso do lado esquerdo# dela# at a posio do ponteiro que controla o lado. 6or e7emplo, para mostrarmos todos os elementos que esto ao lado esquerdo do deque8 int mostraFsq"void# 9 int i! for"iKd.ptresq! iL;! iNN# 9 printf"2Rd3, d.vet:i=#! @ return <! @ %e quisermos fazer uma busca nesse lado, bastaria acrescentamos algumas linhas8 int procuraFsq"int elementoAprocurado# 9 int i! int flag K <! for"iKd.ptresq! iL;! iNN# 9 if"d.vet:i= KK elementoAprocurado# 9 flagNN! @ @ "flag# _ printf"21 elemento foi encontrado Rd vezes3, flag# 8 printf"21 elemento no foi encontrado3#! return <! @ 1 procedimento 0 direita anlogo. $astaria percorrer o deque a partir da posio posterior ao qual ele foi inicializado e e7ecutar o lao de repetio at "inclusive# a posio em que est o ponteiro. Ie+a a procura 0 direita8 int procuraDir"int elementoAprocurado# 9 int i! int flag K <! for"iK;! iLKd.ptrdir! iNN# 9 if"d.vet:i= KK elementoAprocurado# 9 flagNN! @ @ if"flag# printf"21 elemento foi encontrado Rd vezes3, flag#! else printf"21 elemento no foi encontrado3#! return <! @ 6F%&TG%AC ` V1%*CAC *1D1 1 DF&TF 1 procedimento para mostrar ou pesquisar um elemento em todo o deque trata de percorrer as posi-es e7istentes entre o ponteiro da direita "ptrdir# e o ponteiro da esquerda "ptresq#. 6ara mostrar todo o deque usar4amos8 int mostraDeque"void# 9 int i! for"iKd.ptresq! iLKd.ptrdir! iNN# 9 printf"2Rd3,d.vet:i=#! @ return <! @ 6ara pesquisar um elemento em todo o deque8 int pesquisaDeque"int elementoAprocurado# 9 int i! int flag K <! for"iKd.ptresq! iLKd.ptrdir! iNN# 9 if"d.vet:i= KK elementoAprocurado# 9 flagNN! @ @ if"flag# 9 printf"21 elemento foi encontrado Rd vezes no deque3, flag#! @else9 printf"21 elemento no foi encontrado no deque.3#! @ return <! @ /1,*A,D1 FHFVF,*1% ,1 DF&TF A contagem de elementos no deque simplesmente realizada em funo dos ponteiros que apontam para o .ltimo elemento inserido em cada lado. Assim, como ptrdir geralmente maior do que ptresq, utilizamos a operao8 &uantidade de elementos K "ptrdir -ptresq# NB! Ie+a como inicializamos nossos ponteiros8 void inicializa"void# 9 int d.ptrdir K >! int d.ptresq K ;! @ Ie+a que8 &uantidade de elementos K "ptrdir X ptresq# N B KKQ Assim8 &uantidade de elementos K "> X ;# N B K < %e inserirmos dois elementos 0 direita, ocorrero dois incrementos em ptrdir, que passar a valer a. &uantidade de elementos8 "a-;#N B K b /aso coloquemos tr)s elementos 0 esquerda do deque, ptresq sofrer tr)s decrementos, passando a valer b. &uantidade de elementos8 "a-b# NB K ; Assim, colocamos dois elementos 0 direita e mais tr)s 0 esquerda, totalizando cinco elementos no deque.