队列模拟
队列是一种抽象的数据类型,可以储存有序的数据序列,新数据被添加到队列尾,
并可以删除队列首的数据,队列有点像栈,但栈在同一端进行进行添加和删除
数组中第一个元素出队列了,后面的元素都要往前移动,工作量非常大。使用链表的思想来解决
链表
链表在内存中不是连续分布的,数组在内存中是连续分布的。把不同的内存空间通过链条连接
所以每个节点需要保存两个内容:一个是链表成员,一个是指向下一个节点的指针,即单向链表
链表节点:
struct Node
{
Item item;
// 结构体嵌套
struct Node* next;
}
成员初始化列表:
这种格式只能用于构造函数
必须使用这种格式来初始化非静态const类成员
const int a;
必须用这种格式来初始化被声明为引用的类成员
private:
Agency& belong;// 必须要使用初始化列表来初始化
Agent::Agent(Agency & a) : belong(a)
↓_p_front
[item1|p_next] null
↑_p_rear ↓_↑
↓_p_front ↓_p_rear
[item1|p_next] [item2|p_next] null
↓_↑ ↓_↑
↓_p_front ↓_p_rear
[item1|p_next] [item2|p_next] [item3|p_next] null
↓_↑ ↓_↑ ↓_↑
----------------------------------------------
↓_p_front ↓_p_rear
[item2|p_next] [item3|p_next] null
↓_↑ ↓_↑
↓_p_front = ↓_p_rear
[item3|p_next] null
↓_↑
↓_p_front = ↓_p_rear
null
#include <iostream>
#include "ATM.h"
using namespace std;
// 入队列,队列满了之后再出队列
int main()
{
int qs;
int time = 0;
int num_customers = 0;
// 类对象客户
Item temp;
cout << "输入队列的最大尺寸:";
cin >> qs;
Queue line(qs);
// 入队列直到队列满
while(!line.isfull())
{
temp.set(time++);
// 顾客入队列
line.enqueue(temp);
num_customers++;
}
cout << "入队列后顾客的数量 = " << num_customers << endl;
// -----------------------------------
while(!line.isempty())
{
line.dequeue();
num_customers--;
}
cout << "出队列后现在顾客的数量 = " << num_customers << endl;
return 0;
}
ATM.cpp
#include "ATM.h"
#include <stdlib.h>
// notice: 函数体{}中的代码执行前,对象就会被创建,编译器就会为成员变量分布内存空间(就相当于初始化)
// 对于const成员,必须在执行到函数体之前,进行对象成员的初始化
Queue::Queue(int qs):qsize(qs)
{
p_front = p_rear = NULL;
// 当前排队人数
num_items = 0;
// 最大排队人数,如果不适用成员初始化列表,创建对象时已经初始化了,现在相当于改变qsize的值了
// qsize = qs;
}
Queue::~Queue()
{
cout << "调用析构函数!" << endl;
Node* temp;
while(p_front != NULL)
{
temp = p_front;
p_front = p_front->p_next;
delete temp;
}
}
bool Queue::isempty() const
{
return num_items == 0;
}
bool Queue::isfull() const
{
return num_items == qsize;
}
int Queue::queuecount() const
{
return num_items;
}
// 引用传递,从队列尾部入队列
bool Queue::enqueue(const Item& item)
{
if(isfull())
return false;
// 创建存放新队列的节点
Node* add_new = new Node;
// 拷贝构造函数,初始化数据域
add_new->item = item;
// 每一次添加新节点的p_next都是空
add_new->p_next = NULL;
num_items++;
// 如果是第一次添加节点,链表头指针为空
if(p_front == NULL)
p_front = add_new;
else// 如果不是第一次
// 上一个节点(之前队列的最后一个节点)的p_next指向当前的新节点
p_rear->p_next = add_new;
// 更新,新加入的节点作为尾节点
p_rear = add_new;
return true;
}
// 引用传递,从队列头部出队列
bool Queue::dequeue()
{
if(p_front == NULL)
return false;
num_items--;
// 先临时保留第一个节点
Node* temp = p_front;
// notice: 头指针下移:删除头节点之前,先让二号节点成为(代替)头节点
p_front = p_front->p_next;
// 头指针下移之后才能删除原来第一个节点指向的内存
delete temp;
if(num_items == 0)
p_rear = NULL;
return true;
}
// 输入开始取款的时间
void Customer::set(long when)
{
arrive = when;
// 1~3分钟
processtime = rand() % 3 + 1;
}
ATM.h
#ifndef __ATM_H__
#define __ATM_H__
#include <iostream>
using namespace std;
class Customer
{
private:
// 开始取钱的时间
long arrive;
// 取钱过程花费的时间
int processtime;
public:
Customer(){arrive = processtime = 0;}
void set(long when);
long when() const {return arrive;};
int ptime() const {return processtime;}
};
typedef Customer Item;
class Queue
{
private:
// 队列默认长度,类中定义常量:枚举、静态常量
enum{Q_SIZE = 10};
// 链表节点
struct Node
{
// 类对象
Item item;
struct Node* p_next;
};
// 链表头
Node* p_front;
// 链表尾
Node* p_rear;
// 当前排队的人数,节点个数
int num_items;
// 队列最大值,最大排队人数不能改变
// 函数体{}中的代码执行前,对象就会被创建,编译器就会为成员变量分布内存空间(就相当于初始化)
// notice: 对于const成员,必须在执行到函数体之前,进行对象成员的初始化
const int qsize;
public:
// 成员初始化列表
Queue(int qs = Q_SIZE);
~Queue();
bool isempty() const;
bool isfull() const;
// 节点个数,当前排队人数
int queuecount() const;
// 引用传递
bool enqueue(const Item& item);
bool dequeue();
};
#endif