数据结构 --静态队列的一个简单的C语言代码实现
2013-04-21 23:11
1166 查看
静态队列的大概原理和部分算法讲解已经在上一篇博文中讲过了..
http://blog.csdn.net/nvd11/article/details/8816699
这里接上篇文章, 用c语言来实现1个简单的静态队列容器.'
1. 首先是写上静态队列本身的类型.
2. 我们也会把这个容器的公共函数声明到这个头文件中.
那么其他文件只需要引用这个头文件, 就可以使用这个容器类型和公共函数了.
代码如下:
arrqueue.h
适当地解析下:'
首先. bool_me.h 头文件只不过是定义了 BOOL 宏的头文件.. 实际上是char类型啦.
1. 结构体 PERSON_AQ 是1个存放数据的结构体类型, 它有两个成员id, name. 因为下面的静态数组实际上是1个静态结构体数组
2. 结构体 AQ_PERSON 是1个静态队列的容器类型, 它里面包含1个动态分配的 PERSON_AQ结构体数组.
成员 PArr 就是该动态数组的头部地址
成员 Front Rear 就是队列的出口元素地址 和 入口地址了.
成员 arrlen 就是动态数组的长度, 实际上也等于静态队列的最大长度 + 1
成员 is_inited 用于判断这个结构体是否被初始化, 否则不能使用啊.
下面还定义了1些必要的函数成员(函数), 这些函数成员在结构体初始化时会被指定指向哪个函数. 其中出列和入列函数都在这些函数成员中了.
3. 最后还定义3个公共函数, 分别是静态队列结构体初始化函数和释放函数, 和打印1个队列中的1个结构体元素函数.
至于每个函数的大概用途我都注释在旁边了, 下面会对这些函数逐个实现.
1. 为1个静态队列指针, 根据传入的长度参数动态动态分配1段内存.
2. Front 和 Rear 成员的值都设为0, 表示这个是1个空队列, 并根据参数为arrlen 这个数据长度成员赋值.
3. 为成员函数赋值..
4. 成员is_inited 设为 TRUE, 表示已经初始化过了.
5. 返回这个静态队列指针
代码如下:
在上一篇文章里详细解析过了, 这里不在多说了, 只会写下公式.
((Rear - Front) + arrlen) % arrlen
代码如下:
当然也可以判断队列的长度是否等于数组的长度(arrlen) -1
代码如下:
代码如下:
大概逻辑在上一篇文章中提过了, 但是实现起来还是有点复杂的.
大概逻辑步骤:
1. 判断对列是否已满
2. 如果满了, 则对包含这个队列的静态进行扩充(aq_extend), 扩充的长度是当前数组长度的2分1
3. 把 id 和 name写入 Rear位置的 数组结构体成员中.
4. Rear的位置加1
代码如下:
问题来了, 关键是 aq_extend 的函数怎样写? 下面会讲
实际上的原理就是对队列所在的动态数组进行 重新分配内存(realloc).
而用户也不需关心这些信息, 所以这个函数是静态函数, 也不会加入结构体的函数成员中, 所以外部是无法直接调用的.
大概原理也在上一篇文章的最后讲过了, 这里写下步骤:
1. 对动态分配的数组重新分配一段更长的内存.
2. 如果Rear 的位置比 Front 更前...就将Front的位置向后移动x , x是扩充的数量, 这个过程包括数组元素在数组内的移动, 具体请参考上一篇文章啦
代码如下:
8. 根据1个结构体参数的入列函数 aq_queue_by_struct
因为c语言没有函数重载功能, 只能写多1个函数了, 也很简单, 直接调用上面的 入列函数就ok了
出列的意思就是把出口元素 从队列中删除啦, 实际应用大部分情况下用户还需要获得这个出口元素, 所以这个出列函数还会接受1个 结构体指针, 把出列函数的数据复制到这个指针所指向的结构体中.
步骤:
1. 判断是否空队列, 否则返回FALSE
2. 把出口元素的数据 赋值给 output 参数指针
3. Front 移向下1个位置
代码 如下:
很简单啦, 代码如下
代码如下:
效果如下:
3, 4, x, x, 5, 6, 7, 1, 2
3, 4, 8, 9, x, x, x, x, 5, 6, 7, 1, 2
作用? 方便我调试啦, 可以直观地知道队列每个元素在数组的位置
代码如下:
13. 根据下标判断数组中某个元素是否在队列中 is_in_queue
为什么要写这个函数? 因为上面的函数用到啊....
逻辑也很简单:
代码如下:
步骤很简单
1.释放静态队列结构体里面的 数组成员
2. 释放结构体本身
代码如下:
好了, 队列的必要函数我大概都写出来, 因为队列不能中间插入和删除, 也不需排序, 所以函数还是比较少的.
可以见到我不断地执行入列操作, 其中也有自动扩容的情况啦~
输出:
,
````````
http://blog.csdn.net/nvd11/article/details/8816699
这里接上篇文章, 用c语言来实现1个简单的静态队列容器.'
1. 首先编写1个头文件
国际惯例, 我们会在这个头文件中写如如下内容:1. 首先是写上静态队列本身的类型.
2. 我们也会把这个容器的公共函数声明到这个头文件中.
那么其他文件只需要引用这个头文件, 就可以使用这个容器类型和公共函数了.
代码如下:
arrqueue.h
#include "bool_me.h" #ifndef __ARRQUEUE1_H_ #define __ARRQUEUE1_H_ struct person_aq{ int id; char name[16]; }; typedef struct person_aq PERSON_AQ; struct aq_person{ PERSON_AQ * pArr; int Front; int Rear; int arrlen; BOOL is_inited; int (* len)(); //function member of a structure BOOL (* is_full)(); //judge whether array queue is full BOOL (* is_empty)(); //judge whether array queue is empty BOOL (* extend)(); //extend the max length of the array queue BOOL (* en_queue)(); //enqueue by id and name BOOL (* en_queue_by_struct)(); //enqueue by structure BOOL (* de_queue)(); //dequeue void (* print)(); //print info of all the elements in the array queue void (* print_arr_id_st)(); //print all the id of elements of the array }; typedef struct aq_person AQ_PERSON; //initial and return an array queue with dynamic memory assigned AQ_PERSON * aq_person_new(int arrlen); //free the memory of array queue BOOL aq_person_free(AQ_PERSON * pAq); //print an structure object void person_aq_print(PERSON_AQ * pnode); #endif /* ARRQUEUE1_H_ */
适当地解析下:'
首先. bool_me.h 头文件只不过是定义了 BOOL 宏的头文件.. 实际上是char类型啦.
1. 结构体 PERSON_AQ 是1个存放数据的结构体类型, 它有两个成员id, name. 因为下面的静态数组实际上是1个静态结构体数组
2. 结构体 AQ_PERSON 是1个静态队列的容器类型, 它里面包含1个动态分配的 PERSON_AQ结构体数组.
成员 PArr 就是该动态数组的头部地址
成员 Front Rear 就是队列的出口元素地址 和 入口地址了.
成员 arrlen 就是动态数组的长度, 实际上也等于静态队列的最大长度 + 1
成员 is_inited 用于判断这个结构体是否被初始化, 否则不能使用啊.
下面还定义了1些必要的函数成员(函数), 这些函数成员在结构体初始化时会被指定指向哪个函数. 其中出列和入列函数都在这些函数成员中了.
3. 最后还定义3个公共函数, 分别是静态队列结构体初始化函数和释放函数, 和打印1个队列中的1个结构体元素函数.
至于每个函数的大概用途我都注释在旁边了, 下面会对这些函数逐个实现.
2. 静态队列初始化函数 ap_person_new
分析下这个函数的逻辑, 我们要在这个函数里做如下事情:1. 为1个静态队列指针, 根据传入的长度参数动态动态分配1段内存.
2. Front 和 Rear 成员的值都设为0, 表示这个是1个空队列, 并根据参数为arrlen 这个数据长度成员赋值.
3. 为成员函数赋值..
4. 成员is_inited 设为 TRUE, 表示已经初始化过了.
5. 返回这个静态队列指针
代码如下:
//initail and return an array queue with dynamic memory assiganed AQ_PERSON * aq_person_new(int arrlen){ if (arrlen <= 1){ printf("length of array must > 1!!\n"); return NULL; } AQ_PERSON * pAq; pAq = (AQ_PERSON *)malloc(sizeof(AQ_PERSON)); if (NULL == pAq){ base_error("fail to assign memory to a new array queue!!"); } pAq->pArr = (PERSON_AQ *)malloc(sizeof(PERSON_AQ) * arrlen); if (NULL == pAq->pArr){ base_error("fail to assign memory to a new array queue!!"); } pAq->Front = 0; pAq->Rear = 0; pAq->arrlen = arrlen; pAq->len = &aq_len; pAq->is_full = &aq_is_full; pAq->is_empty = &aq_is_empty; pAq->extend = &aq_extend; pAq->en_queue = &aq_enqueue; pAq->en_queue_by_struct = &aq_enqueue_bystruct; pAq->de_queue = &aq_dequeue; pAq->print = &aq_print; pAq->print_arr_id_st = &aq_print_all_id_status; pAq->is_inited = TRUE; return pAq; }
3. 获取队列长度函数 aq_len
至于怎样根据 Front 和 Rear 位置 和 arrlen数组长度这个3个参数去获取队列的长度?在上一篇文章里详细解析过了, 这里不在多说了, 只会写下公式.
((Rear - Front) + arrlen) % arrlen
代码如下:
//get the length of array queue static int aq_len(AQ_PERSON * pAq){ if (TRUE != pAq->is_inited){ base_error("the array queue is not initialed!!"); } return (pAq->Rear - pAq->Front + pAq->arrlen) % pAq->arrlen; }
4. 判断队列是否已满函数, qa_is_full
至于怎样判断也请参考上一篇文章, 就是判断 是否 Rear 下1个位置是 Front当然也可以判断队列的长度是否等于数组的长度(arrlen) -1
代码如下:
//judge whether the array queue is full static BOOL aq_is_full(AQ_PERSON * pAq){ if (TRUE != pAq->is_inited){ base_error("the array queue is not initialed!!"); } if ((pAq->Rear +1) % pAq->arrlen == pAq->Front){ return TRUE; } return FALSE; }
5. 判断队列是否空队列函数, qa_is_empty
这个更简单. 判断 Front 和 Rear 是否相等就ok了.代码如下:
static BOOL aq_is_empty(AQ_PERSON * pAq){ if (TRUE != pAq->is_inited){ base_error("the array queue is not initialed!!"); } if (pAq->Front == pAq->Rear){ return TRUE; } return FALSE; }
6. 根据 id 和 name 的入列函数 aq_en_queue
就是把 id 和 name的数据作为参数, 新加入1个队列到队列中.大概逻辑在上一篇文章中提过了, 但是实现起来还是有点复杂的.
大概逻辑步骤:
1. 判断对列是否已满
2. 如果满了, 则对包含这个队列的静态进行扩充(aq_extend), 扩充的长度是当前数组长度的2分1
3. 把 id 和 name写入 Rear位置的 数组结构体成员中.
4. Rear的位置加1
代码如下:
//add an elements to rear of queue by id and name static BOOL aq_enqueue(AQ_PERSON * pAq, int id, char * pname){ if (TRUE != pAq->is_inited){ base_error("the array queue is not initialed!!"); } if (TRUE == pAq->is_full(pAq)){ if(FALSE == pAq->extend(pAq, pAq->arrlen/2)){ return FALSE; } } pAq->pArr[pAq->Rear].id = id; strncpy(pAq->pArr[pAq->Rear].name, pname+0, 16); pAq->Rear = (pAq->Rear + 1) % pAq->arrlen; return TRUE; }
问题来了, 关键是 aq_extend 的函数怎样写? 下面会讲
7. 队列最大长度扩展函数 aq_extend
当队列已经满, 还需要入列函数时, 怎么办? 当然可以提示用户不能再入列, 但是通常我们会实现自动扩容功能.实际上的原理就是对队列所在的动态数组进行 重新分配内存(realloc).
而用户也不需关心这些信息, 所以这个函数是静态函数, 也不会加入结构体的函数成员中, 所以外部是无法直接调用的.
大概原理也在上一篇文章的最后讲过了, 这里写下步骤:
1. 对动态分配的数组重新分配一段更长的内存.
2. 如果Rear 的位置比 Front 更前...就将Front的位置向后移动x , x是扩充的数量, 这个过程包括数组元素在数组内的移动, 具体请参考上一篇文章啦
代码如下:
//extend the max length of array queue static BOOL aq_extend(AQ_PERSON * pAq, int exlen){ PERSON_AQ * pold; pold = pAq->pArr; pAq->pArr = (PERSON_AQ *)realloc(pAq->pArr, sizeof(PERSON_AQ) * (pAq->arrlen + exlen)); if (NULL == pAq->pArr){ printf("fail to assign memory to extend the array!\n"); pAq->pArr = pold; return FALSE; } // realloc will free the old memory automatically, // it's now allow to free it manual!!! // if (pAq->pArr != pold){ // free(pold); // } if (pAq->Rear < pAq->Front){ int i; for (i=pAq-> arrlen - pAq->Front; i>0; i--){ pAq->pArr[pAq->Front+i-1+exlen] = pAq->pArr[pAq->Front + i - 1]; } pAq->Front += exlen; } pAq->arrlen += exlen; return TRUE; }
8. 根据1个结构体参数的入列函数 aq_queue_by_struct
因为c语言没有函数重载功能, 只能写多1个函数了, 也很简单, 直接调用上面的 入列函数就ok了static BOOL aq_enqueue_bystruct(AQ_PERSON * pAq, PERSON_AQ * pnode){ return aq_enqueue(pAq, pnode->id, pnode->name); }
9. 出列函数 aq_dequeue
这个函数的返回值是也是布尔类型, 因为出列是不一定成功的, .出列的意思就是把出口元素 从队列中删除啦, 实际应用大部分情况下用户还需要获得这个出口元素, 所以这个出列函数还会接受1个 结构体指针, 把出列函数的数据复制到这个指针所指向的结构体中.
步骤:
1. 判断是否空队列, 否则返回FALSE
2. 把出口元素的数据 赋值给 output 参数指针
3. Front 移向下1个位置
代码 如下:
//dequeue static BOOL aq_dequeue(AQ_PERSON * pAq, PERSON_AQ * pnode){ if (TRUE != pAq->is_inited){ base_error("the array queue is not initialed!!"); } if (TRUE == pAq->is_empty(pAq)){ printf("the array queue is empty!\n"); return FALSE; } pnode->id = pAq->pArr[pAq->Front].id; strncpy(pnode->name, pAq->pArr[pAq->Front].name+0, 16); pAq->Front = (pAq->Front + 1) % pAq->arrlen; return TRUE; }
10. 打印队列中其中1个元素的函数 person_aq_print
这个函数作用就是输出其中1个元素的信息.很简单啦, 代码如下
//print an structure object void person_aq_print(PERSON_AQ * pnode){ printf("id is %d, name is %s\n", pnode->id, pnode->name); }
11. 打印队列中所有元素函数 aq_print
原理也不复杂, 就是从Front 开始遍历 直到 Rear , 然后调用上面的函数输出就ok了代码如下:
//print all the elements of array queue static void aq_print(AQ_PERSON * pAq){ if (TRUE != pAq->is_inited){ base_error("the array queue is not initialed!!"); } if (TRUE == pAq->is_empty(pAq)){ printf("the array queue is empty!\n"); } int index; index = pAq->Front; while(index != pAq->Rear){ person_aq_print(&(pAq->pArr[index])); index = (index+1) % pAq->arrlen; } }
12. 打印数组中所有元素的id 的信息 aq_print_all_id_status
就是按照数组自然顺序输出数组中所有元素信息, 如果某个元素不在队列中, 则输出'x', 否则输出元素的id.效果如下:
3, 4, x, x, 5, 6, 7, 1, 2
3, 4, 8, 9, x, x, x, x, 5, 6, 7, 1, 2
作用? 方便我调试啦, 可以直观地知道队列每个元素在数组的位置
代码如下:
//print all the id of element in the array, not only in queue static void aq_print_all_id_status(AQ_PERSON * pAq){ if (TRUE != pAq->is_inited){ base_error("the array queue is not initialed!!"); } if (TRUE == pAq->is_empty(pAq)){ printf("the array queue is empty!\n"); return; } int index; for (index=0; index < pAq->arrlen; index++){ if (TRUE == is_in_queue(pAq, index)){ printf("%d", pAq->pArr[index].id); } else{ printf("x"); } if (index < pAq->arrlen -1){ printf(", "); } } printf("\n"); return; }
13. 根据下标判断数组中某个元素是否在队列中 is_in_queue
为什么要写这个函数? 因为上面的函数用到啊....逻辑也很简单:
代码如下:
//judge whether an element of the array is in the queue static BOOL is_in_queue(AQ_PERSON * pAq, int index){ int Front= pAq->Front; int Rear = pAq->Rear; if (Front == Rear){ return FALSE; } else if (Front < Rear){ if (index >= Front && index < Rear){ return TRUE; } return FALSE; } else{ //Front > Rear if (index < Rear || index >= Front){ return TRUE; } return FALSE; } }
14. 释放静态队列函数 aq_person_free
因为静态队列容器本身和 里面的数组都是动态分配的, 所以必须手动释放啦步骤很简单
1.释放静态队列结构体里面的 数组成员
2. 释放结构体本身
代码如下:
//free the memory of array queue BOOL aq_person_free(AQ_PERSON * pAq){ if (TRUE != pAq->is_inited){ printf("the array queue is not initialed!!\n"); return FALSE; } free(pAq->pArr); free(pAq); return TRUE; }
好了, 队列的必要函数我大概都写出来, 因为队列不能中间插入和删除, 也不需排序, 所以函数还是比较少的.
15. 最后写个小测试程序..
代码如下:int arrqueue1(){ AQ_PERSON * paq1 = aq_person_new(6); paq1->en_queue(paq1, 1, "Jason"); paq1->en_queue(paq1, 2, "Gateman"); paq1->en_queue(paq1, 3, "Youyi"); paq1->en_queue(paq1, 4, "Snow"); paq1->en_queue(paq1, 5, "Moon"); paq1->en_queue(paq1, 6, "Crystal"); paq1->en_queue(paq1, 7, "AI"); paq1->print(paq1); paq1->print_arr_id_st(paq1); printf("\n"); PERSON_AQ node; paq1->de_queue(paq1, &node); printf("the dequeue object is:\n"); person_aq_print(&node); printf("\n"); paq1->en_queue_by_struct(paq1, &node); paq1->de_queue(paq1, &node); printf("the dequeue object is:\n"); person_aq_print(&node); printf("\n"); paq1->en_queue_by_struct(paq1, &node); paq1->de_queue(paq1, &node); printf("the dequeue object is:\n"); person_aq_print(&node); printf("\n"); paq1->en_queue_by_struct(paq1, &node); paq1->de_queue(paq1, &node); printf("the dequeue object is:\n"); person_aq_print(&node); printf("\n"); paq1->en_queue_by_struct(paq1, &node); paq1->print_arr_id_st(paq1); paq1->en_queue(paq1, 8, "Cindy"); paq1->en_queue(paq1, 9, "Inzaghi"); paq1->print_arr_id_st(paq1); paq1->print(paq1); aq_person_free(paq1); printf("len of array queue is %d\n",paq1->len(paq1)); printf("arrqueue1_main done\n"); return 0; }
可以见到我不断地执行入列操作, 其中也有自动扩容的情况啦~
输出:
,
````````
相关文章推荐
- 数据结构 - 队列简介 及 1个简单的c语言链式队列代码实现
- 请实现一个队列,既可以存放整数,又可以存放字符串。简单的说,队列是一种数据结构,按照先进先出的顺序管理进、出队列的元素
- 请实现一个队列,既可以存放整数,又可以存放字符串。简单的说,队列是一种数据结构,按照先进先出的顺序管理进、出队列的元素
- 请实现一个队列,既可以存放整数,又可以存放字符串。简单的说,队列是一种数据结构,按照先进先出的顺序管理进、出队列的元素
- 数据结构中栈与队列的c语言代码实现
- 数据结构C语言实现之链式队列的6种算法代码
- <C语言>如何一步一步根据简单的代码联想到更多的功能?(实现输入一个整数,输出比它小包括它本身的所有素数。)
- 用C语言实现一个简单的计算器代码
- 数据结构学习三(一个简单的队列实现)
- C语言实现一个最简单的队列
- 分享实现类似QQ的自动登陆的方法,代码比较简单,主要是给大家提供一个实现逻辑,具体的要结合自身的app来做
- C#队列Queue实现一个简单的电商网站秒杀程序
- 代码录播:jQueryMobile 实现一个简单的弹出框效果
- 【C语言】通讯录代码(一个文件下实现)
- 数据结构面试题(1)--用两个队列实现一栈和用两个栈实现一个队列
- 数据结构学习中的简单问题(一):用链表方式实现的队列输出杨辉三角
- 【转】200行代码实现一个区块链之一-----最简单的区块链
- 用C语言实现简单循环队列结构
- 数据结构-链队列代码实现
- C语言字符串库函数的实现也是笔试题常考的题目,以下代码没有严格测试,只是简单的实现: