您的位置:首页 > 理论基础 > 数据结构算法

【算法和数据结构】线性表(二)队列的定义和封装

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:基于数组:

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++类。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: