当前位置: 首页 > news >正文

嵌入式第二十二课!!!链式队列与哈希表

链式队列

1. 创建链式队列

先对声明文件进行结构体声明:

#ifndef __LQUEUE_H__
#define __LQUEUE_H__typedef int Data_type_t;typedef struct lqnode
{Data_type_t data;struct lqnode *pnext;
}LQNode_t;typedef struct lqueue
{LQNode_t *phead;LQNode_t *ptail;int clen;
}LQueue_t;#endif

在函数体文件编写函数:

#include "lqueue.h"
#include <stdio.h>
#include <stdlib.h>LQueue_t *create_link_queue()
{LQueue_t *plq = malloc(sizeof(LQueue_t));if (NULL == plq){printf("malloc error\n");return NULL;}plq->phead = NULL;plq->ptail = NULL;plq->clen = 0;return plq;
}


2. 入队操作(尾插)

int is_empty_link_queue(LQueue_t *plq)
{return NULL == plq->phead;
}int push_link_queue(LQueue_t *plq, Data_type_t data)
{LQNode_t *pnode = malloc(sizeof(LQNode_t));if (NULL == pnode){printf("malloc error\n");return -1;}pnode->data =data;pnode->pnext = NULL;if (is_empty_link_queue(plq)){plq->ptail = pnode;plq->phead = pnode;}else{plq->ptail->pnext = pnode;plq->ptail = pnode;}plq->clen++;return 0;
}


3. 出队操作(头删)

int pop_link_queue(LQueue_t *plq, Data_type_t *pdata)
{if (is_empty_link_queue(plq)){return  -1;}LQNode_t *pdel = plq->phead;plq->phead = pdel->pnext;if (pdata != NULL){*pdata = pdel->data;}free(pdel);if (NULL == plq->phead){plq->ptail = NULL;}plq->clen--;return 0;
}

4. 判空

int is_empty_link_queue(LQueue_t *plq)
{return NULL == plq->phead;
}

5. 获取队头元素

int get_queue_head(LQueue_t *plq, Data_type_t *pdata)
{if (is_empty_link_queue(plq)){return -1;}if (NULL == pdata){return -1;}*pdata = plq->phead->data;return 0;
}

6. 销毁队列

void destroy_link_queue(LQueue_t **pplq)
{while (!is_empty_link_queue(*pplq)){pop_link_queue(*pplq, NULL);}free(*pplq);*pplq = NULL;
}

7. 遍历队列

void link_queue_for_each(LQueue_t *plq)
{LQNode_t *ptmp = plq->phead;while (ptmp){printf("%d ", ptmp->data);ptmp = ptmp->pnext;}printf("\n");
}

顺序队列补充:

1.判空

int is_empty_seqque(Seqque_t *psq)
{if (psq->head == psq->tail){return 1;}return 0;
}

2.获取队头元素

int get_seqque_head(Seqque_t *psq, Data_type_t *pdata)
{if (is_empty_seqque(psq) || NULL == pdata){return -1;}*pdata = psq->pbase[psq->head];return 0;
}

3.销毁队列

void destroy_seqque(Seqque_t **ppsq)
{free((*ppsq)->pbase);free(*ppsq);*ppsq = NULL;
}

哈希表

哈希表的作用是可以提高数据查找的效率,它的时间复杂度远远小于遍历与二分查找法;

哈希存储

哈希存储就是将要存储的数据的关键字和存储位置之间,建立起对应的关系,这个关系称之为哈希函数。存储数据时,通过对应的哈希函数可以将数据映射到指定的存储位置;查找时,仍可通过该函数找到数据的存储位置。

举个例子:

在存储这组数据的时候,其本身作为关键字,通过哈希函数(addr = key % 10)来确定存储的位置;

哈希冲突/哈希矛盾

在存储数据的时候,有可能会出现这种情况:

要存储的数据关键字通过哈希函数和已经存储的地址出现冲突,即:

key1 != key2
f(key1) == f(key2)

为了解决这种情况,有两种方法:

开放地址法

这种方法是:如果发生哈希冲突,判断其后有没有空间对其进行存储;如果没有,再从第一个存储空间开始找空闲空间;

我们一般不使用这种方法;

链地址法

在存储空间存储链表对象,通过链表将冲突的数据链在其后;

我们常用这种方法来解决哈希冲突;

哈希表的应用

1.创建哈希表

在声明文件里声明结构体文件:

#ifndef __HASH_H__
#define __HASH_H__#define HASH_TABLE_MAX_SIZE 27typedef struct per
{char name[32];char tel[32];
}Data_type_t;typedef struct node
{Data_type_t data;struct node *pnext;
}HSNode_t;#endif

我们创建的实际上是一个指针数组,它的每个元素是一个指针,指向链表第一个结点,每个结点由data和指针域pnext组成;在声明设计宏定义,根据需要先对数组长度进行设计;

include <stdio.h>
#include "hash.h"int main(void)
{Data_type_t pers[5] = {{"zhangsan", "110"}, {"lisi", "120"},{"wanger", "119"}, {"Zhaowu", "122"},{"maliu", "10086"}};HSNode_t *hash_table[HASH_TABLE_MAX_SIZE] = {NULL};
}

创建好这个长度为27的指针数组:这是一个保存通讯录的哈希表,故使用27个元素,对应26个字母,剩余一个元素防止特殊字符;

2.设计哈希函数

#include "hash.h"
#include <stdio.h>int hash_function(char key)
{if (key >= 'a' && key <= 'z'){return key-'a';}else if (key >= 'A' && key <= 'Z'){return key-'A';}else{return HASH_TABLE_MAX_SIZE-1;}
}

这个哈希函数就是以名字的首字母作为关键字进行计算存储的位置;

3.插入数据

int insert_hash_table(HSNode_t **hash_table, Data_type_t data)
{int addr = hash_function(data.name[0]);//申请结点保存数据//头插//hash_table[addr];   //---->pheadHSNode_t *pnode = malloc(sizeof(HSNode_t));if (NULL == pnode){printf("malloc error\n");return -1;}pnode->data = data;pnode->pnext = NULL;if (NULL == hash_table[addr]){hash_table[addr] = pnode;}else{if (strcmp(pnode->data.name, hash_table[addr]->data.name) <= 0){pnode->pnext = hash_table[addr];hash_table[addr] = pnode;}else{HSNode_t *p = hash_table[addr];while (p->pnext != NULL && (p->pnext->data.name, pnode->data.name) < 0){p = p->pnext;}pnode->pnext = p->pnext;p->pnext = pnode;}}return 0;
}

我们插入数据的方式实际上就是链表,故要在堆区申请空间进行存放;这个插入数据方法是按照字符串大小排序存放的;

4.查找数据

HSNode_t *find_hash_table(HSNode_t **hash_table, char *name)
{int addr = hash_function(name[0]);HSNode_t *ptmp = hash_table[addr];while (ptmp){if (0 == strncmp(ptmp->data.name, name, strlen(name))){return ptmp;}ptmp = ptmp->pnext;}return NULL;
}

先使用哈希函数判断存储的数据在哪条链表上,然后再进行遍历查找;

5.销毁哈希表

void destroy_hash_table(HSNode_t **hash_table)
{for (int i = 0;i < HASH_TABLE_MAX_SIZE; i++){HSNode_t *pdel = hash_table[i];while (hash_table[i] != NULL){hash_table[i] = pdel->pnext;free(pdel);pdel = hash_table[i];}}
}

哈希表只在各个链表的结点上申请了地址,故把所有链表上的结点空间所有释放即可完成销毁;

6.遍历

void hash_for_each(HSNode_t **hash_table)
{for (int i = 0; i < HASH_TABLE_MAX_SIZE; ++i){HSNode_t *ptmp = hash_table[i];while (ptmp){printf("%s : %s\n", ptmp->data.name, ptmp->data.tel);ptmp = ptmp->pnext;}printf("\n");}
}

以上就是今天和大家分享的内容!!!!感谢你的阅读!!!!如有疑问和错误请在评论区进行评论!!!

http://www.dtcms.com/a/319288.html

相关文章:

  • Maven分模块开发实战指南
  • Qt 子类重新实现父类的槽函数
  • 「iOS」————持久化
  • 【0基础3ds Max】菜单栏介绍
  • 【分享】我国八大沙漠空间矢量范围
  • Bonree ONE发布直通车 | 可观测平台如何深度应用LLM技术
  • 如何科学选择光伏运维系统?
  • docker安装半本地化安装方法
  • Shuffle SOAR使用学习经验
  • FreeRTOS2
  • 4G/5G无线电单元系统
  • 水下管道巡检机器人cad【10张】三维图+设计说明书
  • ai短视频与真人短视频哪个更好?
  • Docker容器部署harbor-小白级教学
  • Aurora MySQL 8.0 性能分析账号创建完整指南
  • ego-planner代码个人阅读笔记
  • 智慧物流分拣效率↑40%:陌讯多模态融合算法实战解析
  • Spring AI Alibaba 项目接入阿里云百炼平台大模型
  • leetcode-hot-100 (技巧)
  • STM32 HAL库外设编程学习笔记
  • SpringBoot中的单例注入方式
  • 上位机知识篇---AT指令
  • 「日拱一码」045 机器学习-因果发现算法
  • C 语言第 17 天学习笔记:从二级指针到内存布局的进阶指南
  • 力控汽车零部件冲压MES系统方案
  • 2025最新国内服务器可用docker源仓库地址大全(2025年8月更新) · DockerHub镜像加速全面指南
  • STM32学习笔记4-OLED外部中断和中断系统
  • nlp-句法分析
  • 虚幻GAS底层原理解剖八 (自定义子类)
  • nohup 学习笔记