aula 260

Como implementar uma TABELA HASH com vetor na prática?

Dando continuidade ao nosso Curso de Programação C e ao módulo sobre a estrutura de busca tabela hash, vamos ver nesta aula como implementar uma TABELA HASH com vetor na prática.

O primeiro passo é definir o tamanho da nossa tabela. Como vimos na aula anterior, o tamanho da tabela deve ser definido em função da quantidade de elementos que serão inseridos na tabela. Assim, estou assumindo que nosso conjunto de dados possui tamanho 15.

Ainda orientado pela teoria da aula anterior, os números primos ideais para serem o tamanho da nossa tabela é 29 e 31, o primo mais próximo do dobro da quantidade de elementos a serem armazenados na tabela. Vou escolher o 31. Esse valor será definido como a constante global TAM.

Como vamos inserir 15 elementos em um vetor que possui tamanho 31, precisamos ser capazes de identificar corretamente uma posição vazia do vetor. Para isso estou assumindo que o elemento zero não pertence ao conjunto dos 15 elementos que serão armazenados na tabela. Assim, a posição que possuir o valor zero será considerada uma posição vazia.

Agora, antes de fazer qualquer operação, precisamos limpar nossa tabela, ou seja, inicializar o vetor com zero, indicando que todas as posições estão vazia. Isso será feito com o procedimento a seguir.

/*
    Inicializa o vetor com zero em todas as posições
*/
void inicializarTabela(int t[]){
    int i;

    for(i = 0; i < TAM; i++)
        t[i] = 0;
}

Para inserir qualquer valor na tabela hash precisamo da função hash ou função de espalhamento. Como vimos na aula anterior, é esta função que irá distribuir, espalhar os elementos pela tabela durante o processo de inserção. Uma boa função hash fará uma boa distribuição dos elementos na tabela enquanto uma função hash ruim irá produzir muitas colisões, podendo prejudicar o processo de busca.

Aqui neste exemplo usaremos o resto da divisão do valor a ser inserido pelo tamanho da tabela, como escrito a seguir.

/*
   Função hash ou função de espalhamento
   Retorna o resto da divisão do valor a ser inserido pelo tamanho da tabela, que é o índice onde o elemento será inserido
*/
int funcaoHash(int chave){
    return chave % TAM;
}

Agora que temos a função hash podemos escrever um procedimento para realizar o processo de inserção de um elemento na tabela. Este procedimento precisa receber a tabela e o valor a ser inserido (ou o valor pode ser lido dentro do procedimento). Tendo o valor a ser inserido, usamos a função hash vista acima para descobrir onde o elemento será inserido e fazemos a inserção.

Observe que, como vimos na aula teórica, pode ocorrer colisão ao fazer uma inserção, quando a função hash gera o mesmo índice para elementos diferentes. Neste caso, precisamos procurar a próxima posição vazia para inserir este elemento. Isso pode ser feito com uma repetição do tipo enquanto. Enquanto a posição do índice gerado for diferente de zero, geramos um novo índice, mas agora passamos para a função hash não o elemento a ser inserido, mas o índice gerado mais 1. Assim, se foi gerado por exemplo o índice 15 e esta posição já está ocupada, passamos para a função hash 15 + 1.

O interessante deste método é que não precisamos nos preocupar com o fim do vetor pois, como a função retorna o resto da divisão pelo tamanho da tabela, quando o fim do vetor for atingido o resto será zero e automaticamente iremos para o início do vetor.

/*
    Procedimento para inserir um elemento na tabela hash
*/
void inserir(int t[], int valor){
    int id = funcaoHash(valor);
    while(t[id] != 0){
        id = funcaoHash(id + 1);
    }
    t[id] = valor;
}

A função de busca segui os mesmos passos da inserção. Recebemos a tabela e o valor a ser procurado. Com a função hash descobrimos o índice onde o elemento deve estar caso ele exista na tabela. Com o índice gerado pela função hash, basta verificar se o valor procurado está naquela posição.

Novamente precisamos lembrar que pode ter ocorrido colisão no momento da inserção. Assim, caso a posição indicada pela função hash não esteja vazia (diferente de zero) precisamos verificar as posições seguintes até encontrar o elemento ou uma posição vazia.

/*
    Função para buscar na tabela hash
*/
int busca(int t[], int chave){
    int id = funcaoHash(chave);
    printf("\nIndice gerada: %d\n", id);
    while(t[id] != 0){
        if(t[id] == chave)
            return t[id];
        else
            id = funcaoHash(id + 1);
    }
    return 0;
}

Para imprimir toda a tabela, basta fazer uma repetição para imprimir um vetor de inteiros, como apresentado abaixo.

/*
    Procedimento para imprimir a tabela
*/
void imprimir(int t[]){
    int i;
    for(i = 0; i < TAM; i++){
        printf("%d = %d\n", i, t[i]);
    }
}

Código completo em C para a Tabela Hash com Vetor

/*
            Aula 260: Tabela Hash linear com vetor

            Código escrito por Wagner Gaspar
            Setembro de 2021
*/

// 2 * 15 = 31
#define TAM 31

void inicializarTabela(int t[]){
    int i;

    for(i = 0; i < TAM; i++)
        t[i] = 0;
}

int funcaoHash(int chave){
    return chave % TAM;
}

void inserir(int t[], int valor){
    int id = funcaoHash(valor);
    while(t[id] != 0){
        id = funcaoHash(id + 1);
    }
    t[id] = valor;
}

int busca(int t[], int chave){
    int id = funcaoHash(chave);
    printf("\nIndice gerada: %d\n", id);
    while(t[id] != 0){
        if(t[id] == chave)
            return t[id];
        else
            id = funcaoHash(id + 1);
    }
    return 0;
}

void imprimir(int t[]){
    int i;
    for(i = 0; i < TAM; i++){
        printf("%d = %d\n", i, t[i]);
    }
}

int main(){

    int opcao, valor, retorno, tabela[TAM];

    inicializarTabela(tabela);

    do{
        printf("\n\t0 - Sair\n\t1 - Inserir\n\t2 - Buscar\n\t3 -Imprimir\n");
        scanf("%d", &opcao);

        switch(opcao){
        case 1:
            printf("\tQual valor desseja inserir? ");
            scanf("%d", &valor);
            inserir(tabela, valor);
            break;
        case 2:
            printf("\tQual valor desseja buscar? ");
            scanf("%d", &valor);
            retorno = busca(tabela, valor);
            if(retorno != 0)
                printf("\tValor encontrado: %d\n", retorno);
            else
                printf("\tValor nao encontrado!\n");
            break;
        case 3:
            imprimir(tabela);
            break;
        default:
            printf("Opcao invalida!\n");
        }
    }while(opcao != 0);

    return 0;
}

Deixe um comentário

quatro × cinco =

Wagner Gaspar

Capixaba de São Gabriel da Palha, Espírito Santo. Bacharel em Ciência da Computação pela Universidade Federal do Amazonas e mestre em informática pela Universidade Federal do Espírito Santo.