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

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

哈希函数:在记录的关键字与记录的存储地址之间建立的一 种对应关系叫哈希函数。
哈希函数是一种映象,是从关键字空间到存储地址空间的一 种映象。可写成: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>\n", 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.编译结果

原文地址:https://www.cnblogs.com/miaowulj/p/12240411.html

时间: 2024-10-11 16:25:23

数据结构与算法实例(哈希表实现)的相关文章

数据结构之哈希表实现浅析

看了下JAVA里面有HashMap.Hashtable.HashSet三种hash集合的实现源码,这里总结下,理解错误的地方还望指正 HashMap和Hashtable的区别 HashSet和HashMap.Hashtable的区别 HashMap和Hashtable的实现原理 HashMap的简化实现MyHashMap HashMap和Hashtable的区别 两者最主要的区别在于Hashtable是线程安全,而HashMap则非线程安全Hashtable的实现方法里面都添加了synchron

Java数据结构和算法之哈希表

五.哈希表 一般的线性表.树中,记录在结构中的相对位置是随机的即和记录的关键字之间不存在确定的关系,在结构中查找记录时需进行一系列和关键字的比较.这一类查找方法建立在"比较"的基础上,查找的效率与比较次数密切相关.理想的情况是能直接找到需要的记录,因此必须在记录的存储位置和它的关键字之间建立一确定的对应关系f,使每个关键字和结构中一个唯一的存储位置相对应.因而查找时,只需根据这个对应关系f找到给定值K的像f(K).若结构中存在关键字和K相等的记录,则必定在f(K)的存储位置上,由此不需

数据结构与算法实例(数组实现)

数据结构与算法实例分析-数组 ★数组是一种最简单的数据结构,它占据一块连续的内存并且顺序存储数据,所以我们需要首先指定数组的大小 ★数组的空间效率不是很好,会有空闲的区域没有得到充分的应用 ★时间复杂度为O(1); ★数组一旦被定义,它的维度和维界就不会再改变,因此除了结构的初始化和销毁之外,数组就只有存取和修改元素值得操作 1.数组的存储结构 2.基本操作 ⑴.建造空间并进行初始化:struct triple triple_init(int v1,int v2,int v3); ⑵.释放已开辟

《Java数据结构和算法》- 哈希表

Q: 如何快速地存取员工的信息? A: 假设现在要写一个程序,存取一个公司的员工记录,这个小公司大约有1000个员工,每个员工记录需要1024个字节的存储空间,因此整个数据库的大小约为1MB.一般的计算机内存都可以满足. 为了尽可能地存取每个员工的记录,使用工号从1(公司创业者)到1000(最近雇佣的工人).将工号作为关键字(事实上,用其他作为关键字完全没有必要).即使员工离职不在公司,他们的记录也是要保存在数据库中以供参考,在这种情况下需要使用什么数据结构呢? A: 一种可能使用数组,每个员工

数据结构与算法—一致性哈希

一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正了CARP使用的简单哈希算法带来的问题,使得分布式哈希(DHT)可以在P2P环境中真正得到应用. Hash算法 一致性hash算法提出了在动态变化的Cache环境中,判定哈希算法好坏的四个定义: 平衡性(Balance):平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去,这样可以使得所有的缓冲空间都得到利用.很多哈希算法

python数据结构与算法 29-1 哈希查找

前面的章节中,我们利用数据集中元素的相对位置信息来提高查找算法的性能. 比方知道列表是有序的,能够使用二分查找.本节我们走得更远一些,创建一个数据结构,使得查找性能提高到O(1).称为哈希查找. 要做到这种性能,我们要知道元素的可能位置.假设每一个元素就在他应该在的位置上,那么要查找的时候仅仅须要一次比較得到有没有的答案,但以下将会看到.不是这么回事. 哈希表是这样一种数据集合,元素的保存的时候就存在easy找到位置上.哈希表表中每个位置,一般称为槽位,每个槽位都能保存一个数据元素并以一个整数命

用哈希表实现图书管理系统

学校Java课的课程实验之一. 用到的数据结构:哈希表 题目要求: 1. 建立的图书类包含如下信息:编号.书名.作者.出版社.出版日期. 2. 能够实现根据以下关键字查询图书:编号.书名.作者.出版社. 3. 能够实现图书信息的录入.删除和修改. 4.录入的图书至少要有10本以上. 5.具有图形用户界面. 功能介绍: 录入.删除.修改图书: 按编号.书名.作者.出版社查询图书. 界面设计: 主界面(会的不多,所以用了最简易的流式布局): 检索模块: 从四个检索字段中选择一种,输入检索词,点击“检

【 python 学习笔记 -- 数据结构与算法 】哈希表 Implementation of a Hash Table

Python内建的字典就是用 hash table实现的.这里我们只是通过实现自己的hash table来加深对hash table 和hash functions的理解. [ 概念1: Mapping (映射)] 字典通过键(Key)来索引.一个key对应一个存储的value.任意不可变的数据类型均可作为key. [ 概念2:Hash Table (哈希表)] Hash Table根据key直接访问在内存存储位置的数据结构,因而加快了查找速度 (O(1)). 下图是一个size为11的空的Ha

利用哈希表实现数据查找

题目:现在有一个用来存放整数的Hash表,Hash表的存储单位称为桶,每个桶能放3个整数,当一个桶中要放的元素超过3个时,则要将新的元素存放在溢出桶中,每个溢出桶也能放3个元素,多个溢出桶使用链表串起来.此Hash表的基桶数目为素数P,Hash表的hash函数对P取模. #include<iostream> using namespace std; #define P 7 #define NULL_DATA -1 #define BUCKET_NODE_SIZE 3 struct bucket