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


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

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

  • 相关阅读:
    arthas常用命令记录
    idea 的 http-client
    springboot 接口层参数校验 自定义参数校验
    Spring AOP 实现——使用annotation、pointcut、aspect
    Redis 热点名词
    SpringCloud注册发现配置
    【设计模式】-行为型-11-解释器模式
    【设计模式】-行为型-10-备忘录模式
    【设计模式】-创建型-9-访问者模式
    Kubernetes运行原理
  • 原文地址:https://www.cnblogs.com/miaowulj/p/12240411.html
Copyright © 2020-2023  润新知