C语言写一个散列表

C语言写一个散列表的完整攻略

什么是散列表?

散列表是一种数据结构,它将键映射到值。通过使用散列函数,散列表可以快速查找数据。散列表可以用于实现字典、哈希表、集合等数据结构。

散列表的实现

散列表的实现可以分为以下几步:

  1. 定义散列表的结构体以及散列表元素的结构体;
  2. 实现散列函数;
  3. 实现插入元素方法;
  4. 实现查找元素方法;
  5. 实现删除元素方法;
  6. 实现销毁散列表方法。
// 定义散列表元素的结构体
typedef struct node_s {
  char *key;
  void *value;
  struct node_s *next;
} node_t;

// 定义散列表的结构体
typedef struct hashtable_s {
  int size;
  node_t **table;
} hashtable_t;

// 计算散列值的函数
unsigned int hash_func(hashtable_t *hashtable, char *key) {
  unsigned int hashval = 0;
  for (; *key != '\0'; key++) {
    hashval = *key + (hashval << 5) - hashval;
  }
  return hashval % hashtable->size;
}

// 创建并初始化一个散列表
hashtable_t *create_hashtable(int size) {
  hashtable_t *hashtable;

  if (size < 1) {
    return NULL;
  }

  hashtable = (hashtable_t *)malloc(sizeof(hashtable_t));
  hashtable->table = (node_t **)malloc(sizeof(node_t *) * size);
  for (int i = 0; i < size; i++) {
    hashtable->table[i] = NULL;
  }
  hashtable->size = size;

  return hashtable;
}

// 插入一个元素到散列表
int hashtable_insert(hashtable_t *hashtable, char *key, void *value) {
  node_t *new_node;
  unsigned int hashval = hash_func(hashtable, key);
  node_t *current_node = hashtable->table[hashval];

  while (current_node != NULL && strcmp(current_node->key, key) != 0) {
    current_node = current_node->next;
  }

  if (current_node != NULL) {  // 更新值
    current_node->value = value;
  } else {  // 插入新元素
    new_node = (node_t *)malloc(sizeof(node_t));
    new_node->key = strdup(key);
    new_node->value = value;
    new_node->next = hashtable->table[hashval];
    hashtable->table[hashval] = new_node;
  }

  return 0;
}

// 从散列表中查找一个元素
void *hashtable_search(hashtable_t *hashtable, char *key) {
  unsigned int hashval = hash_func(hashtable, key);
  node_t *current_node = hashtable->table[hashval];
  while (current_node != NULL && strcmp(current_node->key, key) != 0) {
    current_node = current_node->next;
  }
  if (current_node == NULL) {
    return NULL;
  } else {
    return current_node->value;
  }
}

// 从散列表中删除一个元素
int hashtable_delete(hashtable_t *hashtable, char *key) {
  unsigned int hashval = hash_func(hashtable, key);
  node_t *current_node = hashtable->table[hashval];
  node_t *prev_node = NULL;

  while (current_node != NULL && strcmp(current_node->key, key) != 0) {
    prev_node = current_node;
    current_node = current_node->next;
  }

  if (current_node == NULL) {
    return -1;  // 没有找到元素
  } else {
    if (prev_node == NULL) {  // 需要删除的元素位于链表头部
      hashtable->table[hashval] = current_node->next;
    } else {
      prev_node->next = current_node->next;
    }
    free(current_node->key);
    free(current_node);
    return 0;
  }
}

// 销毁散列表
void hashtable_destroy(hashtable_t *hashtable) {
  node_t *current_node, *temp_node;
  for (int i = 0; i < hashtable->size; i++) {
    current_node = hashtable->table[i];
    while (current_node != NULL) {  // 释放散列表中每个元素的内存
      temp_node = current_node;
      current_node = current_node->next;
      free(temp_node->key);
      free(temp_node);
    }
  }
  free(hashtable->table);
  free(hashtable);
  return;
}

示例

示例1:实现一个电话簿

首先定义电话簿的结构体:

typedef struct phonebook_s {
  hashtable_t *hashtable;
} phonebook_t;

然后实现添加联系人的方法:

int phonebook_add_contact(phonebook_t *phonebook, char *name, char *phone) {
  contact_t *contact;
  contact = (contact_t *)malloc(sizeof(contact_t));
  contact->name = strdup(name);
  contact->phone = strdup(phone);

  hashtable_insert(phonebook->hashtable, name, contact);

  return 0;
}

实现查找联系人的方法:

contact_t *phonebook_search_contact(phonebook_t *phonebook, char *name) {
  return (contact_t *)hashtable_search(phonebook->hashtable, name);
}

实现删除联系人的方法:

int phonebook_delete_contact(phonebook_t *phonebook, char *name) {
  return hashtable_delete(phonebook->hashtable, name);
}

示例2:实现身份证号码的校验

身份证号码的前17位是数字,最后一位可能是数字或字母X。我们可以使用散列表存储身份证前17位的数字与其对应的权值(权值就是每一位数字所对应的权值,包括各种因子的加权和),并且使用所得到的总和进行校验。

定义存储身份证号码权值的结构体:

typedef struct idcard_value_s {
  char *num;
  int value;
} idcard_value_t;

定义身份证校验的方法:

int check_idcard(char *idcard) {
  int i, j;
  int sum = 0;

  // 计算身份证前17位数字的校验和
  idcard_value_t values[17] = {
    {"1", 7}, {"0", 9}, {"x", 10}, {"9", 0}, {"8", 1}, {"7", 3},
    {"6", 5}, {"5", 8}, {"4", 0}, {"3", 2}, {"2", 4}, {"1", 6},
    {"0", 8}, {"x", 11}, {"9", 3}, {"8", 5}, {"7", 9}
  };
  int value;
  for (i = 0; i < 17; i++) {
    value = 0;
    for (j = 0; j < 17-i; j++) {
      value += (idcard[j] - '0') * pow(2, 17-i-j-1);
    }
    sum += values[i].value * (value % 11);
  }

  // 校验最后一位数字或字母是否正确
  char last_char = tolower(idcard[17]);
  int last_num;
  if (last_char == 'x') {
    last_num = 10;
  } else if (last_char >= '0' && last_char <= '9') {
    last_num = last_char - '0';
  } else {
    return 0;
  }
  if ((sum + last_num) % 11 == 1) {
    return 1;
  } else {
    return 0;
  }
}

上述代码中使用了pwo()函数,需要包含math.h头文件:

#include <math.h>

更多用法示例可以参考散列表的应用场景。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言写一个散列表 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • 深入理解Spring注解@Async解决异步调用问题

    下面我来详细讲解如何深入理解Spring注解@Async解决异步调用问题。 什么是@Async注解 Spring框架提供了@Async注解,该注解用于标记方法,表示该方法是异步的。当被标记的方法被调用时,它会在另外一个线程中运行,而不是阻塞主调线程。@Async注解使用在Spring中非常普遍,特别是在需要执行一些耗时的任务时,例如发送电子邮件、生成报告、下…

    C 2023年5月23日
    00
  • C++应用Eigen库对应实现matlab中部分函数问题

    实现Matlab中的部分函数可以使用C++库Eigen。Eigen是一个开源的C++模板库,用于线性代数运算,支持数值计算、矩阵和向量操作等。Eigen提供的类和函数对应着Matlab中常用的线性代数函数。 以下是实现Matlab中矩阵操作的C++代码攻略: 一、安装Eigen 1.首先从Eigen的官网https://eigen.tuxfamily.org…

    C 2023年5月23日
    00
  • 如何通过wrap malloc定位C/C++的内存泄漏问题

    如果要通过 wrap malloc 定位 C/C++ 的内存泄漏问题,我会按照以下步骤进行: 1. 使用 wrap malloc wrap malloc 是一个 Linux 平台提供的工具,它可以拦截程序中的内存分配函数,比如 malloc 和 realloc,来实现内存泄漏的定位。首先需要安装 libwrap0-dev: sudo apt-get upda…

    C 2023年5月23日
    00
  • 荣耀畅玩7c怎么截长屏?荣耀畅玩7c滚动截屏教程

    荣耀畅玩7c怎么截长屏? 在荣耀畅玩7c中,想要截取整个长页面时,需要使用滚动截屏的功能。下面是具体的操作步骤: 打开你需要截屏的页面,滚动到页面最顶部; 按下电源键和音量减键同时按住,直到屏幕闪一下; 这时候就已经完成了第一张截屏,继续向下滚动,直到滑动到要截屏的最下面的部分; 继续按下电源键和音量减键同时按住,直到屏幕闪一下,即可完成整个页面的截屏。 需…

    C 2023年5月23日
    00
  • C++实现简单学生成绩管理系统

    C++实现简单学生成绩管理系统 系统概述 学生成绩管理系统是一个常见的应用程序,用于管理学生的各类信息,例如学生基本资料,选修课程等信息。本文将介绍如何使用C++实现一个简单的学生成绩管理系统。 系统需求 学生成绩管理系统需要实现的功能如下: 增加学生信息,包含学号、姓名及出生年月日 增加学生课程成绩信息,包含课程编号、课程名称及成绩 修改学生信息及学生课程…

    C 2023年5月23日
    00
  • PHP使用Http Post请求发送Json对象数据代码解析

    使用 HTTP POST 请求发送 JSON 对象数据是常见的网络编程需求。在 PHP 中,可以使用 CURL 扩展来实现这一过程。下面,我们来一步步详细讲解如何使用 PHP 发送 HTTP POST 请求以及发送 JSON 对象数据。 步骤 1 – 初始化 CURL 首先,我们需要初始化 CURL,如下所示: $curl = curl_init(); 步骤…

    C 2023年5月23日
    00
  • C语言中的状态机设计深入讲解

    C语言中的状态机设计深入讲解 什么是状态机 状态机(State Machine),也称状态自动机,是一种抽象的数学模型,是一种对事物变化过程进行描述的工具。状态机可分为两类:有限状态机和无限状态机。 有限状态机(FSM, Finite State Machine)是一种计算模型。有限状态机由有限个状态及在这些状态之间的转移和动作组成,其中一个状态是我们所关心…

    C 2023年5月22日
    00
  • C++实现航空订票程序

    C++实现航空订票程序 程序设计 题目描述:设计一个航空订票系统,要求能够查询航班、预订航班、退订航班等功能。 程序设计思路:将航班信息、旅客信息以及订单信息进行数据结构的设计,然后通过调用相应的函数实现不同的功能。 程序代码 数据结构: //航班信息结构体 struct flight{ string flightno; //航班号 string depar…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部