【算法和数据结构】线性表(二)队列的定义和封装
2017-01-12 13:30
387 查看
在前面一篇文章中,和大家分享了一种简单的数据结构—–列表。今天和大家分享的是另外一种类似但本质又不尽相同的一种数据结构—–队列。
我们用这样一个现实生活中的例子来引出队列,以及其和列表的区别:
现实生活中,我们以排队买票为例,假设把买票时人们排的队伍想象成一个容器,那么我们可以得到这样的结论:先排队的人总是先买到票。抽象出来,就可以得到队列的基本思想:FIFO即 First in First out。
定义:A restricted form of list - Insert at one end, remove from the other.
有了上面的思想,就很容易可以得到对于队列的两种操作:
插入:我们把这个操作过程称为入队(enqueue);
删除:称之为出队(dequeue)
我们先考虑在一个数组中来实现上述两种操作。要实现从数组一端插入,从另一端删除,有这样两个关键的问题:第一就是如何标记第一个元素和最后一个元素(因为队列总是处于动态变化中的);第二个就是标记了之后如何动态的维护第一元素位置和最后元素位置。为此,我们引入两个变量,front标记第一个元素,rear标记最后一个元素。从rear端入队,从front端出队。
很自然的,我们可以想到用下面这种形式来表示:
但是随着不断的入队和出对操作,很快又会产生另外一个问题:如下图示,这个时候队列空间明明还有空位,那么如何再插入一个元素呢?
为了解决这个问题,我们引入如下环形队列来表示:
这样就可以解决上述空间有冗余但是无法插入新元素的问题。但是很快的,一个新的问题就产生了:
如上图所示,对于队列空和队列满,都满足front=(rear+1)%size的关系,那么如何区分这两种截然不同的状态呢?
下面我们直接给出解决方案:对于n大小的队列,只存(n-1)个元素即可。如下图:
虽然浪费了一个元素存储空间,但是相比于带状队列(第一、二副图)已经节省了很多空间了,而且在实际应用中,队列往往很大,相对于一个很大的队列来说,一个单位的存储空间开销是可以忽略的。
下面给出队列的代码实现(C++):
1:基于数组:
2:基于链表:
点击这里下载线性表数据结构源码,包括:链表、队列、栈。均封装常用操作到c++类。
我们用这样一个现实生活中的例子来引出队列,以及其和列表的区别:
现实生活中,我们以排队买票为例,假设把买票时人们排的队伍想象成一个容器,那么我们可以得到这样的结论:先排队的人总是先买到票。抽象出来,就可以得到队列的基本思想:FIFO即 First in First out。
定义:A restricted form of list - Insert at one end, remove from the other.
有了上面的思想,就很容易可以得到对于队列的两种操作:
插入:我们把这个操作过程称为入队(enqueue);
删除:称之为出队(dequeue)
我们先考虑在一个数组中来实现上述两种操作。要实现从数组一端插入,从另一端删除,有这样两个关键的问题:第一就是如何标记第一个元素和最后一个元素(因为队列总是处于动态变化中的);第二个就是标记了之后如何动态的维护第一元素位置和最后元素位置。为此,我们引入两个变量,front标记第一个元素,rear标记最后一个元素。从rear端入队,从front端出队。
很自然的,我们可以想到用下面这种形式来表示:
但是随着不断的入队和出对操作,很快又会产生另外一个问题:如下图示,这个时候队列空间明明还有空位,那么如何再插入一个元素呢?
为了解决这个问题,我们引入如下环形队列来表示:
这样就可以解决上述空间有冗余但是无法插入新元素的问题。但是很快的,一个新的问题就产生了:
如上图所示,对于队列空和队列满,都满足front=(rear+1)%size的关系,那么如何区分这两种截然不同的状态呢?
下面我们直接给出解决方案:对于n大小的队列,只存(n-1)个元素即可。如下图:
虽然浪费了一个元素存储空间,但是相比于带状队列(第一、二副图)已经节省了很多空间了,而且在实际应用中,队列往往很大,相对于一个很大的队列来说,一个单位的存储空间开销是可以忽略的。
下面给出队列的代码实现(C++):
1:基于数组:
class AQueue { private: int size; int front; int rear; int* queueArray; public: AQueue(int sz) { size = sz; front = 0; rear = -1; queueArray = new int[size]; } ~AQueue() { delete[] queueArray; } int getLength() const { return (rear + size - front + 1) % size; } bool frontValue(int& it) const { if (getLength() == 0) return false; it = queueArray[front]; return true; } void clear() { front = (rear + 1) % size; } //入队 bool enqueue(const int& it) { if ((rear + 2) % size == front) return false; rear = (rear + 1) % size; queueArray[rear] = it; return true; } //出队 bool dequeue(int& it) { if (getLength() == 0) return false; it = queueArray[front]; front = (front + 1) % size; return true; } };
2:基于链表:
//Linked queue class QueueNode { public: int element; //Value of this node QueueNode* next; //Pointer to next node QueueNode(const int & elementValue, QueueNode* nextNode) { element = elementValue; next = nextNode; } }; class LQueue { private: int length; QueueNode* head; QueueNode* tail; public: LQueue() { length = 0; head = tail = NULL; } ~LQueue() { clear(); } void clear() { while (head != NULL) { QueueNode* temp = head; head = head->next; delete temp; } length = 0; } bool frontValue(int& it) { if (getLength() == 0) return false; it = head->element; return true; } bool enqueue(const int& it) { QueueNode* temp = new QueueNode(it, NULL); if (getLength() == 0) head = tail = temp; else { tail->next = temp; tail = temp; } length++; return true; } bool dequeue(int& it) { if (length == 0) return false; it = head->element; QueueNode* temp = head; head = head->next; delete temp; length--; return true; } int getLength() { return length; } };
点击这里下载线性表数据结构源码,包括:链表、队列、栈。均封装常用操作到c++类。
相关文章推荐
- 【算法和数据结构】_4_线性结构_队列
- 第12周 数据结构和算法 线性表-8 单链表的定义及初始化
- 数据结构类型定义及基本操作汇总(一)--线性表,单链表,栈和队列
- 【郝斌数据结构自学笔记】35-46_队列的定义、分类_链式队列伪算法的讲解_循环队列伪算法的讲解
- 【算法和数据结构】_4_线性结构_队列
- 【算法和数据结构】二叉树的定义和封装(C++实现)
- 第12周 数据结构和算法 线性表-7 队列 插入、删除
- 数据结构和算法学习(一)线性表、栈和队列
- 【算法和数据结构】图(一)图的定义和封装(C++实现)
- 【算法和数据结构】线性表(三)栈的定义和封装
- 【算法和数据结构】_9_线性结构_队列_续_1
- 【算法和数据结构】_9_线性结构_队列_续_1
- 队列的数据结构定义及算法
- 一步一步复习数据结构和算法基础-链式队列
- 数据结构和算法设计(迷宫求解问题的栈和队列的实现)
- 一步一步复习数据结构和算法基础-栈和队列(1)
- 算法与数据结构--实现线性表的插入操作--算法2.3
- 数据结构与算法之—两个栈实现一个队列
- 严蔚敏版《数据结构》第二章线性表的算法C语言实现
- 数据结构C语言实现之链式队列的6种算法代码