说在前面:本人只是一位普通的菜菜,文章更多是整理之前的知识,有错误欢迎大家指正。
队列的性质
队列跟堆栈的区别是数据弹出的顺序不同,队列是先进先出,后进后出,类似于排队办理业务,新客户(新数据)接在队伍的尾部,办理完业务的客户(老数据)从队伍前面离开。
基于队列的性质,队列可以解决银行排队模拟等问题。
循环队列
1.用数组储存数据
优点:简单易理解(不要用到指针,大家可能更喜欢)
缺点:由于数组的大小一开始就确定,所以队列的最大大小确定了无法改变,不灵活。
2.一般循环队列的定义
const int MAX_SIZE = 100;
class CirQueue
{
private:
char* data; //指向队列存储空间
int front; //队首下标
int rear; //队尾下标
int mSize;
int sum; // 存放队列的数组的大小
public:
CirQueue(); //建立缺省长度的队列
CirQueue(int s); //建立长度为size的队列
~CirQueue(); //清空队列,释放内存
bool enQueue(char item); //入队
bool deQueue(); //出队
char getFront(); //读取队头元素,但不删除
bool isEmpty(); //判断队列是否为空
bool isFull(); //判断队列是否为满
void clearQueue(); //清空队列
void displayQueue(); //显示队列内容
int queueLength(); //获取队列元素个数
};
3.函数的实现
构造函数 :成员变量设初值,注意front和rear初值设为0不是-1,要保证front和rear的值在数组下标范围之内。
这里提一嘴,因为要实现循环的效果,所以front和rear超过最大值后,要归零,那么这么实现这个效果呢。
有一个神奇的公式 front=(front+1)/msize,这里的msize是数组的大小,通过这个公式,我们就可以实现下标循环的效果。
还有一件事,front指向的是有数据前的位置,也就是说front这个位置没数据,front后一个位置才有数据,rear就不一样,它指向的位置就是最后一个数据。(这些其实是习惯问题,可能每个人的定义都不一样,但自己一定要清楚,自己数据的含义)
下面是函数的具体实现
CirQueue::CirQueue()
{
mSize = MAX_SIZE;
data = new char[mSize];
front = 0;
rear = 0;
sum = 0;
}
CirQueue::CirQueue(int s)
{
mSize = s;
data = new char[mSize];
front = 0;
rear = 0;
sum = 0;
}
CirQueue::~CirQueue()
{
delete[] data;
}
bool CirQueue::enQueue(char item)
{
if (isFull())
{
return false;
}
rear = (rear + 1) % mSize;
data[rear] = item;
sum++;
return true;
}
bool CirQueue::deQueue()
{
if (isEmpty())
{
return false;
}
front = (front + 1) % mSize;
sum--;
return true;
}
char CirQueue::getFront()
{
int i;
if (isEmpty())
{
return 0;
}
i = (front + 1) % mSize;
return data[i];
}
bool CirQueue::isFull()
{
if (sum == mSize)
{
return true;
}
return false;
}
bool CirQueue::isEmpty()
{
if (sum == 0)
{
return true;
}
return false;
}
void CirQueue::clearQueue()
{
sum = 0;
front = rear;
}
void CirQueue::displayQueue()
{
if (isEmpty())
{
cout << "队列为空";
return;
}
int i;
for (i = (front + 1) % mSize; i != rear; i = (i + 1) % mSize)
{
cout << data[i] << ' ';
}
cout << data[i] << endl;
}
int CirQueue::queueLength()
{
return sum;
//return (rear+mSize-front)%mSize; 也可以写这个
}
链式队列
1.用指针将一个个数据串起来
结构体定义为一个数据域一个指针域
struct Node
{
char data;
struct Node* next;
};
2.各种函数的实现
class LinkQueue
{
private:
Node* front, * rear; //队列的头和尾
int length; //队列元素个数
public:
LinkQueue(); //建立头结点,初始化属性
~LinkQueue(); //释放队列空间
void enQueue(char x); //入队
bool deQueue();//出队
char getFront();//获取队头元素
bool isEmpty(); //判断队列是否为空
void clearQueue(); //清空队列
void displayQueue(); //显示队列内容
int queueLength(); //获取队列元素个数
};
LinkQueue::LinkQueue()
{
front = new Node;
front->next = NULL;
rear = front;
length = 0;
}
LinkQueue::~LinkQueue()
{
Node* p;
Node* q;
p = front;
q = p->next;
while (q != NULL)
{
delete p;
p = q;
q = q->next;
}
delete p;
}
void LinkQueue::enQueue(char x)
{
Node* s = new Node;
s->data = x;
s->next = NULL;
rear->next = s;
rear = s;
length++;
return;
}
bool LinkQueue::deQueue()
{
if (isEmpty())
{
return false;
}
Node* p;
p = front->next;
front->next = p->next;
delete p;
length--;
if (isEmpty())
{
rear = front;
}
return true;
}
char LinkQueue::getFront()
{
if (isEmpty())
{
return 0;
}
return front->next->data;
}
bool LinkQueue::isEmpty()
{
if (length == 0)
{
return true;
}
return false;
}
void LinkQueue::clearQueue()
{
Node* p;
p = front->next;
while (front->next != NULL)
{
front->next = p->next;
delete p;
p = front->next;
}
rear = front;
length = 0;
return;
}
void LinkQueue::displayQueue()
{
cout << '[' << length << ']' << ' ';
if (isEmpty())
{
cout << "队列为空。" << endl;
return;
}
Node* p, * q;
p = front;
q = front->next;
while (q != NULL)
{
cout << q->data << ' ';
p = q;
q = p->next;
}
cout << endl;
return;
}
int LinkQueue::queueLength()
{
return length;
}
其中front和rear的定义基本和循环队列相同。
其他函数也不难理解,我就不多讲解了(其实是太懒)
STL
我们平时可以使用现成的队列类
只需要加上头文件
#include<queue>
即可。