嵌入式第二十二课!!!链式队列与哈希表
链式队列
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");}
}
以上就是今天和大家分享的内容!!!!感谢你的阅读!!!!如有疑问和错误请在评论区进行评论!!!