本篇介绍基于顺序表的队列和基于单链表的队列的原理和实现。
最后介绍一下C++ STL 模板库 queue的使用。
一、什么是队列
有些应用,处理的对象是线性关系,用线性表存储,
但这些应用又有自己的特点,在一端进行插入操作,在另一端进行删除操作,
中间不允许插入删除
就像生活中的队列一样。
插入数据的一端称为队头,删除数据的一端称为队尾。
有两种存储方式,顺序的和链式的,那么队列也有两类实现方式,
一类是基于顺序表的,一类是基于链表的。
我们下面介绍基于顺序表的循环队列,基于单链表的队列。
二、基于顺序表的循环队列
我们知道,对于顺序表,在低下标处插入和删除数据,需要移动大量元素,效率低,在高下标处插入和删除数据,效率高。
这样一来,让高下标方向作为队尾非常自然,插入数据很简便;
而在低下标处删除数据,按照顺序表常规做法需要把后面的数据前移,效率低。
改进的方法,
设立队头、队尾两个指针,
队头和队尾之间是数据。
插入数据时,队尾指针处插入数据,指针后移
删除数据时,队头指针后移,这样就把队头数据排除在范围之外,相当于删除了。
#include <iostream>
using namespace std;
template<typename T>class queue
{
T* elem;//连续空间首地址
int listsize;//空间大小
int length;//存储的实际元素个数
int head;//队头下标
int rear;//队尾元素下标
public:
queue()
{
int L = 1;
elem = new T[L];
listsize = L;
length = 0;
head = 0;
rear = -1;
}
void enlarge()
{
T* newbase = new T[listsize * 2];
int i=head, j=0;
int count = 1;//计数器
while (count<=length)//每个元素都要拷贝
{
newbase[j] = elem[i];
i = (i + 1) % listsize;
j++;
count++;
}
delete elem;
listsize *= 2;
elem = newbase;
head = 0;
rear = length-1;
}
void push(T x)
{//入队,在队尾插入元素
if (length == listsize)
{
enlarge();
}
rear = (rear + 1) % listsize;
elem[rear] = x;
length++;
}
void pop()
{//出队
head =(head +1)%listsize;
length--;
}
T front()
{//得到队头元素
return elem[head];
}
void print()
{//从前到后打印队列元素
int i=head;
int count;
for (count = 1; count <= length; count++)
{
cout << elem[i] << " ";
i = (i + 1) % listsize;
}
cout << endl;
}
int size()
{//得到队列长度
return length;
}
~queue()
{
delete elem;
}
};
int main()
{
queue<int> q;
q.push(1);
q.print();
q.push(2);
q.print();
q.push(3);
q.print();
q.push(4);
q.print();
cout << q.front() << endl;//打印队头元素
q.pop();
q.print();
}
三、基于单链表的队列
对于一般单链表而言,在表头结点后面插入和删除数据都很简便,
而在表尾插入数据需要先找到表尾,遍历整个链表。
在表尾删除数据需要先找到表尾前一个结点,遍历整个链表。
即在表尾插入和删除数据都是O(n).
改造的方法,设置一个指向表尾结点的指针,这样在表尾插入数据就很方便了。
这样,表头就是队头,表尾就是队尾。
// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
using namespace std;
template<typename T>class queue
{//单链表表示队列
struct node
{
T data;
node* next;
};
node* head;//头指针
node* tail;//尾指针
int length;//存储的实际元素个数
public:
queue()
{
head = tail = new node;
head->next = 0;
length = 0;
}
void push(T x)
{//入队,在队尾插入元素
node* t = new node;
t->data = x;
t->next = 0;
tail->next = t;
tail = t;
length++;
}
void pop()
{//出队
if (length == 1)
{//删除尾结点时要注意
delete tail;
tail = head;
}
else
{
node* t = head->next;
head->next = t->next;
delete t;
}
length--;
}
T front()
{//得到队头元素
return head->next->data;
}
void print()
{//从前到后打印队列元素
node* p = head->next;
while (p)
{
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
int size()
{//得到队列长度
return length;
}
~queue()
{
node* p;
while (head->next)
{
p = head->next;
head->next = p->next;
delete p;
}
delete head;
}
};
int main()
{
queue<int> q;
q.push(1);
q.print();
q.push(2);
q.print();
q.push(3);
q.print();
q.push(4);
q.print();
cout << q.front() << endl;//打印队头元素
q.pop();
q.print();
}
四、C++ STL 模板queue
// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include<queue>
#include <iostream>
using namespace std;
template<typename T>
void print(queue<T> q)
{
T x;
while (q.size())
{
x = q.front();
cout << x << " ";
q.pop();
}
cout << endl;
}
int main()
{
queue<int> q;
q.push(1);
print(q);
q.push(2);
print(q);
q.push(3);
print(q);
q.push(4);
print(q);
cout << q.front() << endl;//打印队头元素
q.pop();
print(q);
}