数据结构与算法实例(哈希表实现)

Posted miaowulj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法实例(哈希表实现)相关的知识,希望对你有一定的参考价值。

数据结构与算法(哈希表)

哈希函数:在记录的关键字与记录的存储地址之间建立的一 种对应关系叫哈希函数。
哈希函数是一种映象,是从关键字空间到存储地址空间的一 种映象。可写成:addressi=H(keyi) ,其中i是表中某 个元素。
哈希表:应用哈希函数,由记录的关键字确定记录在表中的 地址,并将记录放入此地址,这样构成的表叫哈希
★哈希表的特点就是数据与其在表中的位置存在相关性,也就是有关系的,通过数据应该可以计算其位置,哈希表最大的特点是是可以快速实现查找,插入和删除。因为它独有的特点,Hash表经常用来解决大数据问题
1.哈希表的基本思想
数组的最大的特点是:寻址容易,插入和删除困难;而链表正好相反,寻址困难,而插入和删除操作容易。那么如果能够结合两者的优点。做出一种寻址,插入和删除操作同样快速的数据结构,这就是哈希表。哈希表是这样一个集查找,插入和删除操作于一身的数据结构

2.哈希表结构
技术图片

3.基本操作

//创建结构体存储键值对
struct element {
   int key;
   int value;
};
//创建结构体作为一级结构
struct table;
//初始化哈希表存储空间,返回指向该空间的结构体指针变量
struct table *table_init();
void table_free(struct table *t);

void table_clear(struct table *t);
int table_isempty(struct table *t);
int table_count(struct table *t);
//将新的键值对存储到哈希表存储结构中
void table_put(struct table *t, int key, int value);
// void table_put(struct table *t, struct element e);
//根据键值将键值对从哈希表存储结构中移除
struct element table_remove(struct table *t, int key);

/* 如果找到了返回key的元素,如果没找到返回{-1,-1}*/
struct element table_get(struct table *t, int key);

4.存储结构
结构①
技术图片
核心思想:使用结构体数组存储键值对作为哈希表的存储结构核心

结构②
技术图片
核心思想:将链表连接到数组中,数组变量作为各链表的索引达到方便操作数据的目的

5.代码实现
table.h

#ifndef __TABLE_H__
#define __TABLE_H__
//定义结构体存储键值对
struct element {
   int key;
   int value;
};

struct table;

struct table *table_init();
void table_free(struct table *t);

void table_clear(struct table *t);
int table_isempty(struct table *t);
int table_count(struct table *t);

void table_put(struct table *t, int key, int value);

struct element table_remove(struct table *t, int key);

struct element table_get(struct table *t, int key);


#endif

main.c

//将数据元素按照键值关系存储到哈希表存储结构中
#include <stdio.h>
#include <stdlib.h>

#include "table.h"

int main(int argc, char *argv[])
{
    //定义结构体指针变量t指向table结构体类型的数据
    struct table *t = NULL;
    int i;
    //定义element结构体类型变量e
    struct element e;
    //t指向已开辟的内存空间
    t = table_init();
    
    table_put(t,0,55);
    table_put(t, 1, 100);
    table_put(t, 2, 200);
    table_put(t, 3, 300);
    table_put(t, 5, 500);

    //键相同会产生"冲突",键不变,值覆盖
    table_put(t, 3, 333);
    //循环遍历,将键值取出
    for (i=0; i<10; i++) {
        e = table_get(t, i);      
        printf("the element is <%d, %d>
", e.key, e.value);
    }
    
    
    table_free(t);
      
    system("PAUSE");    
    return 0;
}

table.c
结构⑴
技术图片

#include "table.h"
#include <stdlib.h>
#include <assert.h>
#include <string.h>
//定义数组的初始长度
#define TABLE_INIT_SIZE 1
//定义数组每次扩容增加的长度
#define TABLE_INCR_SIZE 1
//定义table结构体类型作为一级结构体,指针变量elements指向在.h文件中定义的element结构体类型数据元素
//count记录结构体数组中数据元素的个数,size记录结构体数组的长度
struct table {
    struct element *elements;
    int count;
    int size;
};
//创建以结构体数组为核心的哈希表存储结构
struct table *table_init()
{
    struct table *t = NULL;
    
    t = (struct table *)malloc(sizeof(struct table));
    if (t == NULL) return NULL;
    
    assert(t != NULL);
    t->elements = NULL;
    t->size = 0;
    t->count = 0;
    
    t->elements = (struct element *)malloc(sizeof(struct element) * TABLE_INIT_SIZE); 
    if (t->elements == NULL) {
        free(t);
        return NULL;
    }
    
    assert(t->elements != NULL);
    
    memset(t->elements, 0, sizeof(struct element) * TABLE_INIT_SIZE);
    t->size = TABLE_INIT_SIZE;
    
    return t;
}
//通过table_free()释放内存空间
void table_free(struct table *t)
{
    assert(t != NULL);
    assert(t->elements != NULL);
    
    free(t->elements);
    free(t);
    
    return;
}
//清空哈希表存储结构中的数据元素
void table_clear(struct table *t)
{
    assert(t != NULL);
    assert(t->elements != NULL);
    
    t->count = 0;
    
    return;
}
//查看哈希表存储结构中是否为空
int table_isempty(struct table *t)
{
    assert(t != NULL);
    assert(t->elements != NULL);
    
    return (t->count == 0);
}
//计算哈希表存储结构中数据元素的个数
int table_count(struct table *t)
{
    assert(t != NULL);
    assert(t->elements != NULL);
    
    return t->count;
}
//将键值对push到哈希表存储结构中
void table_put(struct table *t, int key, int value)
{
    //如果已存储的数据元素等于已定义的数组的长度,进行扩容操作
    if (t->count == t->size) {
        t->elements = (struct element *)realloc(t->elements, sizeof(struct element) * (t->size + TABLE_INCR_SIZE));
        if (t->elements == NULL) {
            perror("struct table_put realloc error");
            exit(1);
        }
        
        t->size += TABLE_INCR_SIZE;
    }
    
    struct element e = {key, value};
    int i=0;
    //如果产生"冲突",键不变,值覆盖
    for (; i<t->count; i++) {
        if (t->elements[i].key == e.key) {
           t->elements[i].value = e.value;
           return;
        }
    }
    
    t->elements[i] = e; // t->count
    t->count++;
    return;
}

// void table_put(struct table *t, struct element e);
//将制定键的键值对移除
struct element table_remove(struct table *t, int key)
{
    struct element e = {-1, -1};
    int i=0;
    //定义pos标识键相同与制定键相同的键值对所在结构体中的位置
    int pos = -1;
    
    for (; i<t->count; i++) {
        e=t->elements[key];
        if (t->elements[i].key == key) {
           pos = i;
           break;
        }
    }
    //后面的数据元素往前移位
    if (pos != -1) {
        e = t->elements[pos];
        for (; pos < t->count-1; pos++) {
            t->elements[pos] = t->elements[pos+1];
        }
        t->count--;
    }
    
    return e;
}

struct element table_get(struct table *t, int key)
{
    int i;
    struct element e = {-1, -1}; /*未找到返回的值*/
    
    for (i=0;i<t->count; i++) {
        if (t->elements[i].key == key) return t->elements[i];
    }
    
    return e;
}

结构⑵
技术图片

#include "table.h"

#include <stdlib.h>
#include <assert.h>
#include <string.h>
//定义作为索引的数组的长度
#define TABLE_SLOTS_INIT_SIZE 10
//定义table_node的结构体类型作为链表的数据节点,e为element结构体类型的数据元素(element结构体在.h文件中已定义)
//next指向下一个table_node数据类型的数据
struct table_node {
    struct element e;
    struct table_node *next;
};
//table结构体类型作为一级结构,数据节点地址存储在数组中,数组的首地址存放在slots指针变量中
struct table {
    struct table_node **slots;
    int count;
    int size;
};


struct table *table_init()
{
   struct table *t = NULL;
   
   t = (struct table *)malloc(sizeof(struct table));
   if (t == NULL) return NULL;
   
   assert(t != NULL);
   t->slots = NULL;
   t->count = 0;
   t->size = 0;
   
   t->slots = (struct table_node **)malloc(sizeof(struct table_node *) * TABLE_SLOTS_INIT_SIZE);
   
   if (t->slots == NULL) {
       free(t);
       return NULL;     
   }
   
   assert(t->slots != NULL);
   
   memset(t->slots, 0, sizeof(struct table_node *) * TABLE_SLOTS_INIT_SIZE);
   
   t->size = TABLE_SLOTS_INIT_SIZE;
   
   return t;
}

void table_free(struct table *t)
{
   struct table_node *node = NULL;
   int i;
   
   for (i=0; i<t->count; i++) {
       while (t->slots[i] != NULL) {
           node = t->slots[i];
           t->slots[i] = node->next;
           free(node);   
       }
       
       assert(t->slots[i] == NULL);
   }
   
   free(t->slots);
   free(t);
   
   return;
}

void table_clear(struct table *t)
{
   struct table_node *node = NULL;
   int i;
   
   assert(t != NULL);
   assert(t->slots != NULL);
   
   for (i = 0; i < t->count; i++) {
       while (t->slots[i] != NULL) {
           node = t->slots[i];
           t->slots[i] = node->next;
           free(node);   
       }
       
       assert(t->slots[i] == NULL);
   }
   
   t->count = 0;
   
   return;
}

int table_isempty(struct table *t)
{
   assert(t != NULL);
   assert(t->slots != NULL);
   
   return (t->count == 0);
}

int table_count(struct table *t)
{
   assert(t != NULL);
   assert(t->slots != NULL);
   
   return (t->count);
}

void table_put(struct table *t, int key, int value)
{
    struct table_node *p = NULL;
    struct table_node *node = NULL;
    
    p = t->slots[key % t->size];
    while (p != NULL) {
        if (p->e.key == key) {
            p->e.value = value;
            return;          
        }
        p = p->next;
    }
    
    node = (struct table_node *)malloc(sizeof(struct table_node));
    if (node == NULL) {
       perror("table_put malloc error");
       exit(1);
    }
    
    assert(node != NULL);
    node->e.key = key;
    node->e.value = value;
    
    /* 把链上结点挂在node结点之后,注意,链上没有结点也没关系*/
    node->next = t->slots[key % t->size];
    t->slots[key % t->size] = node;
    t->count++;
    
    return;
}

// void table_put(struct table *t, struct element e);
struct element table_remove(struct table *t, int key)
{
    struct table_node *p = NULL;
    struct table_node *node = NULL;
    struct element e = {-1, -1};
    
    p = t->slots[key % t->size];
    
    if (p->e.key == key) {
        node = p;
        t->slots[key % t->size] = node->next;
        e = node->e;
        free(node);
        t->count--;
        return e;
    }
    
    while (p != NULL && p->next != NULL) {
       if (p->next->e.key == key) {
           node = p->next;
           p->next = node->next;
           e = node->e;
           t->count--;
           free(node);
           return e;
       }
       p = p->next;
    }
    
    return e;
}

/* 如果找到了返回key的元素,如果没找到返回{-1,-1}*/
struct element table_get(struct table *t, int key)
{
    struct table_node *p = NULL;
    struct element e = {-1, -1};
    
    p = t->slots[key % t->size];
    while (p != NULL) {
       if (p->e.key == key) {
           e = p->e;
           break; 
       }
       p = p->next;
    }
    
    return e;
}

6.编译结果
技术图片

以上是关于数据结构与算法实例(哈希表实现)的主要内容,如果未能解决你的问题,请参考以下文章

哈希表及其常用算法(代码实例)

哈希表与哈希(Hash)算法

数据结构与算法--------哈希表

数据结构与算法——哈希函数与哈希表等

一致性哈希算法PHP测试片段

数据结构与算法之数组链表和哈希表的Java实现