队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出(FIFO—first in first out)线性表。队列的实现有顺序队列、循环队列和链表队列。这里我用了循环队列和链表队列两种。
顺序队列:
与顺序表一样,顺序队列需要分配一块连续的区域来存储队列的元素,需事先定义数据大小。当队列满入队是会出现上溢的现象,队列空出队会产生下溢的想象。这是后要想继续操作,需要对数据进行移动,效率不佳。
循环队列:
循环队列多使用一个数据大小的空间用来表示队列空或者队列满。也就是说循环队列的存储空间中最大数据个数加一(倘若不牺牲着一个数据大小的空间,就需要额外声明一个标志位flag。初始情况下flag=0,front=rear表示队列空。第二次front=rear,flag=1,表示队列满)。循环队列中中有三种状态:
- front==rear ( 队列为空状态 )
- front!=(rear+1)%maxSize ( 队列的一般状态 )
- front==(rear+1)%maxSize ( 队列为满的状态 )
如下图所示,循环队列中能存取的最大数据个数为7个,但需要申请8个数据大小的空间。第一种情况中:队列中没有数据,此时front=rear=0,队列为空;第二种情况中:队列中有一个数据,front=0、rear=1,队列处于一般状态,既能进队也能出队;第三种情况:队列满,front=0,rear=7,此时满足front=(rear+1)%maxSize。在队列常用的操作:打印、入队、出队、获取队头、队尾数据值中。打印、入队、出队、获取队尾数据值中要注意该队列是循环队列,可能出现rear>front的情况,需要处理一下。
代码:
#include<iostream>
using namespace std;
class arrayQueue
{
int front;
int rear;
int* queue;
int maxSize;
public:
arrayQueue() {}
arrayQueue(int maxS)
{
front = rear = 0;
queue = new int[maxS+1];
maxSize = maxS+1;
}
~arrayQueue()
{
del();
}
void dis();//打印队列元素
void del();//删除
void push(int item);//item入队
void pop();//出队
void creat(int num);//创建num个元素的测试队列
bool isEmpty();//是否空
bool isFull();//是否空
bool getFront(int &val);//读取队头元素
bool getRear(int &val);//读取队尾元素
};
void arrayQueue::dis()
{
if (!isEmpty())
{
for (int i = front;i != rear;i=(i+1)%maxSize)
{
if ((i + 1) % maxSize != rear)
{
cout << queue[i] << "->";
}
else
cout << queue[i] << endl;
}
}
else
cout << "队列空。" << endl;
}
void arrayQueue::del()
{
delete[] queue;
front = rear = maxSize = 0;
}
void arrayQueue::push(int item)
{
if (!isFull())
{
queue[rear] = item;
rear =(rear+1)%maxSize;
}
else
{
cout << "队列满。" << endl;
}
}
void arrayQueue::pop()
{
if (!isEmpty())
{
front = (front +1) % maxSize;
}
else
{
cout << "队列空。" << endl;
}
}
void arrayQueue::creat(int num)
{
for (int i = 0;i < num;i++)
push(i+1);
}
bool arrayQueue::isEmpty()
{
return front == rear;
}
bool arrayQueue::isFull()
{
return (rear + 1) % maxSize == front;
}
bool arrayQueue::getFront(int& val)
{
if (!isEmpty())
{
val = queue[front];
return true;
}
else
{
cout << "队列空。" << endl;
return false;
}
}
bool arrayQueue::getRear(int& val)
{
if (!isEmpty())
{
val = queue[(rear-1+maxSize)%maxSize];
cout << val << endl;
return true;
}
else
{
cout << "队列空。" << endl;
return false;
}
}
int main()
{
int a;
arrayQueue t(20);
t.creat(20);
t.dis();
return 0;
}
链表队列:
链式队列是基于单链表的存储表示,队头指针front指向队头结点,队尾指针rear指向队尾结点。链表中所有的结点都必须通过这两个指针访问到,并且队头端只能用来删除结点,队尾端用来插入结点。如下图所示:n个元素的队列中,队头指针指向链表中第一个数据、队尾指针指向链表中最后一个数据,其中出、入队方向就是箭头描述的方向。
代码:
#include<iostream>
using namespace std;
class queNode
{
public:
int element;
queNode* next;
queNode() {}
queNode(int e, queNode* n) :element(e), next(n) {}
};
class queList
{
public:
queNode* front;
queNode* rear;
int length;
queList() {}
~queList()
{
del();
}
void dis();//打印队列元素
void del();//删除
void push(int item);//item入队
void pop();//出队
void creat(int num);//创建测试队列
bool isEmpty();//是否空
bool getFront(int &val);//读取队头元素
bool getRear(int &val);//读取队尾元素
};
void queList::dis()
{
if (!isEmpty())
{
queNode* t = front;
while (t != NULL)
{
if (t->next != NULL)
{
cout << t->element<< "<-";
}
else
{
cout << t->element << endl;
}
t = t->next;
}
}
else
{
cout << "队列空。" << endl;
}
}
void queList::del()
{
if (!isEmpty())
{
while (front != NULL)//每轮循环开始时,t与front的值相等,不存在访问空指针内容
{
rear = front;
front = front->next;
delete(rear);
}
rear = NULL;
length = 0;
}
}
void queList::push(int item)
{
queNode* newNode = new queNode(item, NULL);
if (length != 0)
{
rear->next = newNode;
rear = newNode;
}
else
{
front = rear = newNode;
}
length += 1;
}
void queList::pop()
{
if (!isEmpty())
{
queNode* t = front;
front = front->next;
length -= 1;
if (length == 0)
rear = NULL;
delete(t);
}
}
void queList::creat(int num)
{
if (num > 0)
{
for (int i = 1;i <= num;i++)
push(i);
}
}
bool queList::isEmpty()
{
return (length == 0);
}
bool queList::getFront(int& val)
{
if (!isEmpty())
{
val = front->element;
return true;
}
else
return false;
}
bool queList::getRear(int& val)
{
if (!isEmpty())
{
val = rear->element;
return true;
}
else
return false;
}
int main()
{
queList t;
t.creat(10);
t.dis();
return 0;
}
链式队列中发现了一个以前一直没发现的问题。当一个指针指向的空间已经被释放后,它的值是什么?访问它会怎么样?它的值还是被释放掉的那块空间的地址,访问它程序会崩溃。