C语言:队列
2015-09-13 09:41
411 查看
一、基本概念
队列和堆栈的顺序不同: 队列是一种先进先出(First-In First-Out, FIFO)的结构。
二、实现原理
在队列的尾部插入以及在头部删除,因为它准确的描述了人们在排队时的实际体验。
三、过程分析
队列的实现比堆栈稍微复杂一点。它需要两个指针------- 一个指向队头,一个指向队尾。同时,数组并不像适合堆栈那样适合队列的实现,这是由队列使用内存的方式决定的。
1. 考虑一个用5个元素的数组实现的队列。下图是10、20、30、40、50这几个值插入队列以后队列的样子:
2. 经过三次删除之后,队列的样子如下:
这种情况,数组并没有填满,但它的尾部已经没有空间,无法再插入新的元素了。这个问题的一种解决方法是当一个元素被删除之后,队列中的其余元素朝数组起始位置方向移动一个位置。由于复制元素所需的开销,这种方法几乎不可行,尤其是那些较大的队列。
一个好一点的方案就是让队列的尾部“环绕”到数组的头部,这样新元素就可以存储到以前删除元素所留出来的空间中。这个方法常常称为循环数组,示意图如下:
1. 假设初始阶段结构如下:
2. 插入另一个元素之后的结果:
这里有两点需要说明:
1.
循环数组的插入操作只会改变rear的值,而front的值保持不变。
2. 当尾部下标移出数组尾部时,把它设置为0。用下面的代码就可以实现:
3. 我们继续往循环数组中插入几个元素,直到数组 "满" 为止,结构如下:
4. 我们尝试将循环数组中的元素全部删除,最终结构图如下:
注:循环数组的删除操作只会改变front的值,而rear的值保持不变。
可以看出,循环数组 "满" 的时候 和 循环数组 ”空“ 的时候,front和rear的值都是一致的,这样就会导致我们无法判断循环数组是"空"还是"满"。
解决思路:重新定义"满"的含义。如果使数组中的一个元素始终保留不用,这样队列"满"时,front和rear的值便不相同,可以和队列为空的情况区分开来。通过不允许数组完全填满,问题便得以避免。示意图如下:
为"空"满足的条件为:
队列和堆栈的顺序不同: 队列是一种先进先出(First-In First-Out, FIFO)的结构。
二、实现原理
在队列的尾部插入以及在头部删除,因为它准确的描述了人们在排队时的实际体验。
三、过程分析
队列的实现比堆栈稍微复杂一点。它需要两个指针------- 一个指向队头,一个指向队尾。同时,数组并不像适合堆栈那样适合队列的实现,这是由队列使用内存的方式决定的。
1. 考虑一个用5个元素的数组实现的队列。下图是10、20、30、40、50这几个值插入队列以后队列的样子:
2. 经过三次删除之后,队列的样子如下:
这种情况,数组并没有填满,但它的尾部已经没有空间,无法再插入新的元素了。这个问题的一种解决方法是当一个元素被删除之后,队列中的其余元素朝数组起始位置方向移动一个位置。由于复制元素所需的开销,这种方法几乎不可行,尤其是那些较大的队列。
一个好一点的方案就是让队列的尾部“环绕”到数组的头部,这样新元素就可以存储到以前删除元素所留出来的空间中。这个方法常常称为循环数组,示意图如下:
1. 假设初始阶段结构如下:
2. 插入另一个元素之后的结果:
这里有两点需要说明:
1.
循环数组的插入操作只会改变rear的值,而front的值保持不变。
2. 当尾部下标移出数组尾部时,把它设置为0。用下面的代码就可以实现:
rear += 1; if (rear >= QUEUE_SIZE) { rear = 0; }等效的写法如下:
rear = (rear + 1) % QUEUE_SIZE
3. 我们继续往循环数组中插入几个元素,直到数组 "满" 为止,结构如下:
4. 我们尝试将循环数组中的元素全部删除,最终结构图如下:
注:循环数组的删除操作只会改变front的值,而rear的值保持不变。
可以看出,循环数组 "满" 的时候 和 循环数组 ”空“ 的时候,front和rear的值都是一致的,这样就会导致我们无法判断循环数组是"空"还是"满"。
解决思路:重新定义"满"的含义。如果使数组中的一个元素始终保留不用,这样队列"满"时,front和rear的值便不相同,可以和队列为空的情况区分开来。通过不允许数组完全填满,问题便得以避免。示意图如下:
为"空"满足的条件为:
(rear + 1) % QUEUE_SIZE == front为"满"满足的条件为:
(rear + 2) % QUEUE_SIZE == front四、代码清单
#define QUEUE_SIZE 100 #define ARRAY_SIZE (QUEUE_SIZE + 1) // 数组中的一个元素始终保留不用,为了区分队列是满还是空 static QUEUE_TYPE queue[ARRAY_SIZE]; static size_t front = 1; static size_t rear = 0; void insert(QUEUE_TYPE value) { assert(!is_full()); rear = (rear + 1) % ARRAY_SIZE; queue[rear] = value; } void delete(void) { assert(!is_empty()); front = (front + 1) % ARRAY_SIZE; } QUEUE_TYPE first(void) { assert(!is_empty()); return queue[front]; } int is_empty(void) { return (rear + 1) % ARRAY_SIZE == front; } int is_full(void) { return (rear + 2) % ARRAY_SIZE == front; }
相关文章推荐
- C++ string 字符串匹配
- c++字符串详解
- 提高C++代码质量 - [92]让代码运行得再快些
- C++中引用和指针的区别
- 黑马程序员-c语言回顾-数组
- 在伦敦对冲基金工作多年的quant学习C++的经验
- 【九度OJ】题目1001:A+B for Matrices
- Effective C++ 条款52 写了placement new也要写placment delete
- C++ 链表
- Effective C++ 条款51 编写new和delete时需固守常规
- C语言之变量与常量
- C语言之左移和右移运算符
- C语言之外部变量与作用域
- C语言之函数值传递的好处
- C语言之argument和parameter的区别
- C语言之char类型研究
- Effective C++ 条款50 了解new和delete的合理替换时机
- 如何在windows中使用cmd命令去编译,运行C++程序
- 哈密顿回路的非暴力解法(转自CSDN大神GDTZX)
- (C++)string类杂记