Vous êtes sur la page 1sur 9

/*Em duplas Critrios de avaliao: - edentao - documentao - lgica e execuo - otimiza - apresentao: domnio e capacidade de explicao (os cdigos

entregues devero ser apresen ados) Construir um programa em C que receba nmeros inteiros entre 0 a 99 e os adicione em uma tabela hash (vetor de 10 posies). Os processos de insero, busca e remoo devero ser baseados no clculo de endereamento: uno( h ) = chave % tamanhoVetor. O tratamento de coliso dever ser o ENCADEAMENTO SEPARADO (uso de listas encadeada s em vetores). Finalmente, o programa dever ter um MENU com a seguinte estrutura: 1 - Inserir 2 - Pesquisar 3 - Remover 4 Sair Opo: _ Sempre que um dado for inserido necessrio: - mostrar o endereo calculado para o dado; - se houve ou no coliso; Semp re que um dado for pesquisado ou removido necessrio: - mostrar o endereo calculado para o dado; - e se estava ou no em situao de coliso;*/ //Nomes: Rodrigo e Igor #include #include #include #define TAM 10 typedef struct cel{ int chave; // valor a ser inserido struct cel *prox; //ponteiro para celula proxima }Celula; /* Esta funcao insere uma nova celula j ordenado em uma lista encadeada. * A nova celula eh inserida no final da lista. * Ao final, a lista modificada eh retornada */ Celula *inserir(int valor, Celula *lista){ int aux; Celula *nova,*p; nova = (Celula *) malloc(sizeof(Celula)); nova->chave = valor; if(!lista){ printf("o numero %d nao se encontra em colisao\n",valor); nova->prox=NULL; lista=nova; } else{//quando entra nesse else, j est em coliso printf("o numero %d se encontra em colisao\n",valor); p=lista; while(p->prox!=NULL) p=p->prox; if(nova->chave < p->chave){//inserir ordenado aux=nova->chave; p->chave=nova->chave; nova->chave=aux; } p->prox=nova; nova->prox=NULL; } return lista; } /* Esta funcao recebe como parametro o valor a ser

* removido e a lista encadeada, remove e retorna a lista. */ Celula *remover(int valor, Celula *lista){ Celula *p,*aux; if(!lista){ printf("numero nao existe"); return lista; } if(!lista->prox && lista->chave==valor){ printf("o endereco do dado eh: %d\n",valor%TAM); printf("o numero %d nao estava em coliso\n",valor); free(lista); } else if(lista->prox){//caso entre aki ja esta em colisao printf("o endereco do dado eh: %d\n",valor%TAM); printf("o valor %d estava em colisao\n",valor); p=lista; for(;p;p=p->prox){ if(valor==p->chave){ aux=p; p=p->prox; free(aux); lista->prox=p; } } } else printf("valor naum encontrado\n"); return lista; } /* Esta metodo busco o valor recebido como parametro * na lista encadeada, verifica se o valor esta em * colisao e se esta na lista * se estiver mostra o valor do calculo da tebela hash */ void busca(Celula *lista, int valor){ Celula *p; if(!lista){ printf("numero nao encontrado\n"); return 0; } if(!lista->prox){ if(lista->chave == valor){ printf("o endereco do dado eh: %d\n",valor%TAM); printf("o numero %d nao estava em colisao\n",valor); } else printf("valor nao encontrado\n"); } else if(lista->prox){ p=lista; while (p->prox){ if(p->chave == valor){ printf("o endereco do dado eh %d\n",valor%TAM); printf("o numero %d esta em colisao\n",valor); } else printf("valor nao encontrado\n"); p=p->prox; } }

} // Programa Principal int main(){ Celula *t[TAM]; int chave,hash, op=0,i; for(i=0;i

*************************************************************************** Estruturas de Dados Captulo 13: Tabelas Hash 13.1. Introduo Uma maneira de organizar dados, que apresenta bons resultados na prt ica, conhecida como hashing1, e se baseia na idia de distribuir os dados em posies aleatrias de uma tabela. Podemos apresentar esta idia atravs de um exemplo. Suponha mos que desejamos organizar o cadastro de aproximadamente 500 empregados de uma empresa usando para identificar cada empregado o seu CPF2. Por exemplo, a inform ao sobre cada empregado pode ser guardada em um registro INFO: typedef struct info INFO, *PT; struct info{ int cpf; char nome[80]; char ender[1 20]; ... }; Como os CPFs variam entre 000 000 000 e 999 999 999, ignorando-se os cadores , podemos guardar toda a informao em um vetor INFO vet[1000000000]; dgitos verifi

ou para economizar algum espao, em posies apontadas por componentes do vetor PT vet[1000000000];

(A economia de espao viria do fato de que INFO* ocupa menos espao do que INFO, e d o fato de que s precisariam ser representadas em estruturas INFO as informaes assoc iadas aos 500 empregados.) Estas duas maneiras tornariam o acesso muito simples: no primeiro caso, a informao sobre o empregado de CPF c estaria em vet[c], e, no segundo caso, em *vet[c]. Em qualquer dos dois casos, entretanto, a idia absurda, por causa do espao total requerido. Uma variante desta idia procura reduzir o esp ao usando um CPF parcial , por exemplo, os trs ltimos dgitos. Neste caso, poderamos ter um vetor PT vet[1000];

e a informao sobre o mesmo empregado estaria em *vet[c%1000], usando-se aqui o ope rador % de C, que representa mdulo , ou resto da diviso . O espao foi reduzido a um tota aceitvel, o acesso continua simples, mas um problema adicional surgiu: dois empr egados que tem CPFs com os mesmos trs ltimos dgitos passam a ter as informaes guardad as na mesma posio do vetor. Esta situao chamada de coliso , e deve ser resolvida enco ando-se uma posio alternativa para os dados de um dos empregados. 1 2 to hash significa cortar em pedacinhos, picar; falando de comida, hash pode ser picadinho. ou, mais precisamente, seu nmero de inscrio no cadastro de pessoas fsicas da receita federal Estruturas de Dados, J. L. Rangel, 13-1

No contexto da nossa discusso neste captulo, a funo tomar os trs ltimos dgitos do CPF uno de hash, vet uma tabela hash. Naturalmente este sistema s pode ser utilizado se tivermos uma boa soluo para o problema da coliso. Em particular, a probabilidade d e coliso pode ser reduzida usando uma tabela suficiente para vrias vezes o nmero to tal de entradas. Por exemplo, uma tabela com 1000 entradas (como acima), no caso de uma empresa com 500 empregados (500 posies ocupadas) teria uma probabilidade d e 50% de coliso, se fosse feita a insero de um novo empregado. A propriedade fundam ental da funo de hash a de espalhar bem as chaves de busca (os valores pelos quais se faz a busca na tabela), para que o nmero de colises seja o menor possvel, e nes te sentido que dissemos, no incio desta Introduo, que seria bom usar posies aleatrias da tabela para guardar as informaes. 13.2. Formas possveis de tratamento de colises H vrias formas possveis de tratar colises. A mais simples usar a prxima posio vazia, caso de coliso. Por exemplo, para inserir um elemento x numa tabela, usando a fu no de hash h, podemos usar a primeira das posies h(x), h(x)+1, h(x)+2, que estiver v azia. (Se o final da tabela for atingido, continuamos, circularmente, a partir d o incio.) Esta forma de tratamento de colises tem uma desvantagem fundamental, que a tendncia de formao de grupos de posies ocupadas consecutivas, fazendo com que a pr imeira posio vazia, na prtica, possa ficar muito longe da posio original, dada pela f uno de hash. Para inserir um determinado valor x na tabela, ou para concluir que o valor no se encontra na tabela, necessrio encontrar a primeira posio vazia aps a pos io h(x). Para fixar as idias, suponha que inserimos u, x, v, w, y e z na tabela, ne ssa ordem, e que h(u)=h(v)=h(w)=423, e h(x)=h(y)=h(z)=425. Inicialmente, inserim os u na posio h(u)=423, e x na posio h(x)=425. 422 423 u 424 425 x 426 427 428 Em seguida, como h(v)=423 est ocupada, v inserido na posio seguinte, 424. 422 423 u 424 v 425 x 426 427 428 De forma semelhante, w vai ser inserido na primeira posio vazia aps h(w)=423, ou se jam na posio 426. 422 423 u 424 v 425 x 426 w 427 428 Idem, y e z, nas posies 427 e 428. 422 423 u 424 v 425 x 426 w 427 y 428 z Estruturas de Dados, J. L. Rangel, 13-2

Suponha agora que vamos procurar n na tabela, e que h(n)=424. Para concluir que este valor no se encontra na tabela, devemos visitar 6 posies da tabela, de 424 a 4 29. Normalmente no se utilizam tabelas hash em situaes em que elementos devem ser r emovidos, pelas dificuldades impostas pelos esquemas de tratamento de colises. Co ntinuando o exemplo anterior, suponha que x simplesmente removido: 422 423 u 424 v 425 426 w 427 y 428 z

De todos os elementos mencionados, apenas u e v continuam acessveis: o acesso a w , y e z foi perdido. Para remover x, de forma correta, seria necessrio mudar dive rsos outros elementos de posio na tabela. Um esquema um pouco mais complicado util iza uma segunda funo r, a funo de re-hash, para resolver colises. Assim, um elemento x seria inserido na primeira das posies vazias entre h(x), h(x)+r(x), h(x)+2*r(x), A vantagem que se tivermos h(x)=h(y)=h(z)=i, ser pouco provvel que tenhamos tambm r(y)=r(z). Assim, x seria inserido na posio i, y seria inserido na posio i+r(y), e z seria inserido numa posio diferente i+r(z). Com isso, a busca de z no passaria pel a posio ocupada por y. Uma possibilidade adicional para o problema das colises ter uma lista de entradas associada a uma posio na tabela. No exemplo acima, a posio 423 da tabela conteria um apontador para uma lista encadeada com trs ns, corresponden tes a u, v e w; idem 425, para x, y e z. Esta lista pode tambm ser implementada e m uma rea de overflow na prpria tabela, onde so feitas as inseres em caso de coliso. implementao de uma tabela com esta organizao pode ser encontrada na ltima seo deste c ptulo. Considera-se que, em uma tabela hash bem dimensionada, devemos ter 1,5 ace ssos tabela, em mdia, para encontrar um elemento. Isto corresponde a uma situao em que metade dos acessos feita diretamente, e, para a outra metade, ocorre uma col iso. Voltando aos nmeros do exemplo da Introduo, a tabela com um bilho de entradas ga rantia um custo de 1,0 acessos; se o preo a pagar por uma tabela de tamanho 1000 for o adicional de 0,5 acesso, em mdia, pode ser considerado razovel. 13.3. Estrut uras possveis para tabelas de hash Para definir uma tabela de hash, precisamos de finir uma chave de busca para a informao. Esta chave pode ser um nmero, como um CPF , pode ser uma cadeia de smbolos, como um nome, ou pode ser a combinao de vrias info rmaes. Os registros que contm a informao podem ser armazenados em memria ou em arquivo s, dependendo basicamente do tamanho e do nmero de registros a ser considerado. A ssim, se a informao sobre cada elemento pode ser representada por uma estrutura IN FO, a tabela de hash pode ter a forma INFO vet[max]; mas o normal seria INFO *vet[max]; Estruturas de Dados, J. L. Rangel, 13-3

para reduzir o custo de manter posies vazias na tabela. No caso de informao armazena da em um arquivo, poderamos ter como apontador um nmero inteiro, o nmero do registr o correspondente no arquivo. Neste caso, seria interessante fazer com que a tabe la tivesse duas colunas, uma para conter o valor da chave de busca, e outra para o nmero do registro correspondente no arquivo, para evitar que fosse necessrio co nsultar o arquivo apenas para concluir que no se trata do elemento desejado, como acontece na resoluo de colises. Poderamos ter typedef struct linha { int CPF; /* ou outra chave de busca */ int reg; /* nmero d o registro no arquivo */ } LINHA; LINHA vet[max]; A exata estrutura de uma tabela vai depender da aplicao pretendida. 13.4. Critrios para escolha de uma funo de hash A primeira propriedade desejvel para uma funo de has h (ou de re-hash) a facilidade de sua avaliao. Por essa razo, normalmente as operaes utilizadas em uma funo de hash so as operaes correspondentes s instrues mais rpidas computador: and (e), or (ou), xor (ou exclusivo) e os deslocamentos de bits. Op eraes como a soma podem ser utilizadas, embora sejam mais lentas que as outras men cionadas, mas funes matemticas como senos ou logaritmos normalmente no chegam a ser consideradas. Por exemplo, para acelerar o clculo da funo de hash, em vez de usar o resto da diviso por 1000, como proposto na Introduo, seria prefervel usar o resto d a diviso pela potncia de 2 mais prxima, 1024, uma vez que o valor x%1024 pode ser c alculado de forma mais rpida (em C) como x&1023. Isto acontece porque 1023 em binr io 00...0111111111, de maneira que x&1023 tem todos os bits iguais a zero, com e xceo dos ltimos 9 bits, que so iguais aos bits correspondentes de x. (O operador & d e C faz o and lgico de dois nmeros bit a bit. Mesmo neste caso simples, a escolha do s bits do CPF que sero usados na funo de hash precisa ser feita com cuidado. No nos so caso, escolhemos os ltimos porque os CPFs so atribudos, em princpio, consecutivam ente, o que faz com que os valores dos trs ltimos dgitos possam, na prtica, ser cons iderados aleatrios. Se usssemos os trs primeiros, provavelmente teramos mais colises, entre empregados com a mesma idade aproximada. 13.5. Um exemplo Neste exemplo, vamos montar uma tabela hash, cuja finalidade seria armazenar identificadores, ( por exemplo, nomes de variveis) durante a compilao de um programa. Suporemos que os identificadores so formados de letras e dgitos, e que o tipo da informao sobre cada identificador j foi definido, de forma que dispomos de declaraes typedef struct info INFO, *PT; struct info { ... }; Estruturas de Dados, J. L. Rangel, 13-4

Suporemos tambm que a tabela deve ter 512 linhas , e que dessas, as primeiras 256 de vem ser acessveis atravs da funo hash, ficando as demais para ser usadas em caso de coliso. Vamos apresentar uma funo de hash relativamente simples, mas que permite mo strar alguns dos aspectos que podem (devem) ser levados em considerao. A funo de has h Os caracteres que podem aparecer num identificador so letras e dgitos, cujos cdig os ASCII ocorrem entre 48 e 122. Consultando uma tabela ASCII completa, ou a tab ela resumida apresentada na Fig. 1, verificamos que, para todos estes caracteres , o primeiro bit ser sempre 0, e na maioria das vezes, o segundo ser 1. Por essa r azo, a funo de hash aqui apresentada ignora estes dois primeiros bits. Decimal ... 48 49 ... 57 ... 65 66 ... 90 ... 97 98 ... 122 ... Hexadecimal ... 30 31 ... 39 ... 41 42 ... 5A ... 61 62 ... 7A ... Binrio ... 0011 0000 0011 0001 ... 0011 1001 ... 0100 0001 0100 0010 ... 0101 1010 ... 0110 0001 0110 0010 ... 0111 1010 ... Caracter ... 0 1 ... 9 ... A B ... Z ... a b ... z ...

Fig.1 Tabela ASCII resumida Exerccio: Escreva um programa que imprima uma tabela ASCII completa. Como a funo de hash deve fornecer um nmero entre 0 e 255, precisamo s de 8 bits. Para no complicar muito, vamos considerar apenas 4 caracteres do ide ntificador, os dois primeiros e os dois ltimos. Ignorados os 2 primeiros bits, ca da caracter vai fornecer 6 bits. Com 4 caracteres, teremos 24 bits, ou seja, 3 b ytes. O resultado da funo ser o ou exclusivo desses 3 bytes. A idia de usar tambm cara teres do incio e do fim do identificador procura distinguir identificadores como matriz00, matriz01, vetor00, vetor01. Claro que, ainda assim, teramos uma coliso e ntre vetor00 e vetorx00. Outro valor que pode ser considerado pela funo de hash o comprimento da cadeia. A funo hash pode ser: Estruturas de Dados, J. L. Rangel, 13-5

char hash(char *s) { char c1,c2=0,c3=0,c4=0; char b1,b2,b3; int l=strlen(s); c1= s[0]; if (l>=2) c2=s[1]; if (l>=3) c3=s[l-1]; if (l>=4) c4=s[l-2]; b1=((c1&63)4) ; b2=((c2&15)2); b3=((c3& 3) e

***************************************************************************

#include #include /* Diviso alfa=3 & alfa=5 n=339 & n=205 m=n/3 & m=n/alfa m==113 & m==41 */ //>< /* Multiplicao p=20 & p=40 a=0.6180 & a=7114 */ //tamanho do cojunto universo e 500 para diviso e para multiplicao....FUIIIIIIIII struct alunos{ int matricula; char nome[50]; int curso,turno; }; struct alunos cadrasto[500]; char tt[50],aluno[50]; int opc2,ii,i,numero,ponta,desejo,pass=0; int t,opc,conti,local,contador=0,tam,k1,kk,tipo; int m; float k2,k3,a=0.6180;//prox!=NULL){ y=y->prox; } n=(struct no*)malloc(sizeof(struct no)); n->chave=numero; n->prox=NULL; y->prox=n; }//ELSE }//ELSE }

printf("Deseja continuar 1-Para sim 2-Para nao: "); scanf("%i",&desejo); }while(desejo!=2); }//FIM IF if(opc2==2){ i=0; ponta=0; system("cls");

printf("Qual o nome do aluno: "); scanf("%s",&aluno); printf("Qual a sua metricula: "); scanf("%i",&numero); for(i=0;ichave==numero){ // Se o no apontado por y diferente do w=y; y=y->prox; // numero que ser excludo, usamos o w // como auxiliar e y aponta para o proximo

} else{ y=y->prox; // y aponta para o proximo if(y==NULL){ // se y nulo imprime NULL u=w; // u aponta para o auxiliar(w) } w->prox=y; // o ponteiro prox do n apontado por } /// w aponta para y }// fim do while }// fim do else printf("Aluno excluido...");system("paus e"); }//IF if(cadrasto[i].matricula==numero & cadra sto[i].curso!=1){ cadrasto[i].matricula=-1; printf("Aluno excluido...");system("p ause"); }//IF }//Fim for }//FIM IF }while(opc2!=4); }

Vous aimerez peut-être aussi