【C++数据结构与程序设计】学习笔记——队列

队列定义

  • 队列:也称先进先出(FIFO)表,所有的增加都在表的一端进行,队列里准备被服务的元素也就是第一个将从队列中删除的元素称为队头front 或 head);所有的删除在表的另一端进行,队列的最后一个元素即最近加入的一个元素称为队尾rear 或 tail)。
  • 队列的应用:在用计算机执行任务时,经常需要等待轮次才能访问某个东西,如在计算机系统里可能有任务队列在等待打印、等待磁盘访问或者是在多任务时等待使用CPU。在单个程序里,一个队列可能有多个要求,或者一个任务可能创建其他的任务,因此必须将它们保存在一个队列中一次处理。由此,队列的应用甚至会比栈的应用更加普遍。
  • (顺序)循环队列:运用循环数组的方式并使用头指针和尾指针实现的队列。
  • 双端队列:deque(double-ended queue)表示一个表,其元素可以从队列的头部或尾部加入或删除但是不改变表中的任何其他位置,因此双端队列同时是栈和队列的广义化。
  • 枚举错误代码Error_code定义,包括代码successunderflowoverflow,任何试图向一个已满的队列中增加元素或者从一个已空的队列中删除元素的操作都将产生错误代码。

C++中对类Queue的定义基于以下框架:

C++标准的模板库为queue类提供了一个模板,为了与栈进行区分,分别用emptyappendserveretrieve操作代替标准库中的 empty,push,pop 和 front 的基本操作。标准库队列的实现也提供了 back 和 size 的操作,分别用于检查队列里的最后元素和总共的元素数。

class Queue{
public:
	Queue();
	bool empty() const;
	Error_code append (const Queue_entry &x);
	Error_code serve();
	Error_code retrieve(Queue_entry &x)const;
//Additional members will represent queue data.
}

类Extended_queue的定义如下:

除了四个基本操作之外,还有另外三个队列的常用操作:clear使已经创建的队列变空,size返回队列中的元素个数,serve_and_retrieve组合了serve和retrieve的功能,能够弹出并获得队头元素。

class Extended_queue:public Queue {
public:
	bool full()const;
	int size()const;
	void clear();
	Error_code serve_and_retrieve(Queue_entry &item);
};

队列的实现

  • 派生类:派生类通过将新的方法加入到一个已存在的类中,提供了一种定义类的简单方法.C++中使用操作符:定义派生类,本章中Extended_queueQueue的派生类,则class Extended_queue:public Queue{};
  • 继承:派生类重用基类成员的能力称为继承,继承使面向对象程序设计的基本特征之一。本章中类Extended_queue继承了类Queue
  • is-a 关系:只要两个ADT AB之间关系的口头描述包含每个A是一个B,就把代表A的类的实现看作是从代表B的类派生的过程,即代表A的类是代表B的类的派生类A is-a B。本章中,每个Extended_queue对象 “是一个Queue对象,并具有其他特征,即方法 clear,full,size 和 serve_and_retrieve,因此Extended_queue类和Queue类之间为is-a关系
  • has-a 关系:如 University has-a Student 关系。在实现中通过对类进行层次化可以使has-a关系变得更清晰

顺序队列的循环实现

在考虑边界条件(空/满)的前提下,本章中介绍的顺序队列实现的所有方法:

  • 物理模型:先行数组的头总是在第一个位置,只要队头被删掉,所有的元素都要沿着数组向前移动(一般来说,在计算机中这是一种低劣的方法)
  • 具有两个指针的线性数组总是在增长,比较报废空间,如果队列能立即置空,那么这是一种好的方法
  • 循环数组带有头指针和尾指针,并且留有一个空位 以区分队空和队满
  • 循环数组带有头指针和尾指针,并且有一个标志 如布尔型变量来指示满或空
  • 循环数组带有头指针和尾指针,并且用一个整型变量对队列元素进行计数 以区分队空和队满
  • 循环数组带有头指针和尾指针,并且采用特殊的值指示 空,如将队尾指针设置成 -1 以指示空队列

队列类及其操作的实现

  • 实现拥有泛型元素的队列,并称这种类型为Queue_entry
  • 实现队列的方法:循环数组带有头指针和尾指针,用一个整型变量对队列元素进行计数以区分队空和满
  • protected:受保护的可见性。对于客户程序代码,protected受保护的可见性与private私有的可见性具有同样的意义,因此Queue仍然是被封装的,然而派生类的成员函数允许访问基类的受保护的成员。
  • 三元操作符:在C++中可以使用三元操作符?:来增加循环数组的下标ii = ((i+1)==max)?0:(i+1);或者用模操作i=(i+1)%max;其结果总是在0到max-1之间
typedef double Queue_entry;
const int maxqueue=10;		//small value for testing
class Queue{
public:
	Queue();
	bool empty()const;
	Error_code serve();
	Error_code append(const Queue_entry &item);
	Error_code retrieve(Queue_entry &item)const;
protected:
	int count;
	int front,rear;
	Queue_entry entry[Maxqueue];
};
class Extended_queue:public Queue {
public:
	bool full()const;
	int size()const;
	void clear();
	Error_code serve_and_retrieve(Queue_entry &item);
};
Queue::queue()
/*Post:	The Queue is initialized to be empty. */
{
	count = 0;
	rear = maxqueue-1;
	front = 0;
}
bool Queue::empty()const
/*Post:	Return true if the Queue is empty, otherwise return false. */
{
	return count == 0;
}
Error_code Queue::append(const Queue_entry &item)
/*Post:	Item is added to the rear of the Queue. If the Queue is full, return an Error_code of overflow and leave the Queue unchanged. */
{
	if(count>=maxqueue)return overflow;
	count++;
	rear=((rear+1)==maxqueue)?0:(rear+1);
	entry[rear]=item;
	return success;
}
Error_code Queue::serve()
/*Post:	The front of the Queue is removed. If the Queue is empty return an Error_code of underflow. */
{
	if(count<=0)return underflow;
	count--;
	front = ((front+1)==maxqueue)?0:(front+1);
	return success;
}
Error_code  Queue::retrieve(Queue_entry &item)const
/*Post:	The front of the Queue retrieved to the output parameter item. If the Queue is empty, return an Error_code of underflow. */
{
	if(count<=0)return underflow;
	item = entry[front];
	return success;
}
bool Extended_queue::full()const
/*Post:	Return true if the Queue is full, otherwise return false. */
{
	return count==maxqueue;
}
int Extended_queue::size()const
/*Post:	Return the number of the entries in the Extended_queue. */
{
	return count;
}
void Extended_queue::clear()
/*Post:	使已创建的队列变空 */
{
	count = 0;
	front = rear+1;
}
Error_code Extended_queue::serve_and_retrieve(Queue_entry &item)
/*Post:	组合了serve和retrieve的功能,能够弹出并获得队头元素 */
{
	if(count<=0)return underflow;
	item = entry[front];
	count++;
	front = ((front+1)==maxqueue)?0:(front+1);
	return success;
}

演示与测试

菜单驱动演示程序将创建数据结构并允许用户以任何希望的次序,对数据结构执行可能的操作,只要用户希望就可以立即打印出结果,可在编写了处理数据结构的方法和函数后立即测试实现以确信其每一步都能正常工作。

接下来为拓展队列设计这样的程序:在主程序每一次迭代时,演示程序会要求用户选择一种操作,(如果可能)则在数据结构上执行那个操作并打印出结果。

int main()
/*Post:	Accepts commands from user as a menu-driven demonstration program for the class Extended_queue.
  Uses:	The class Extended_queue and the functions introduction, get_command, and do_command. */
{
	Extended_queue test_queue;
	introduction();
	while(do_command(get_command(),test_queue));
}

bool do_command(char c,Extended_queue &test_queue)
/*Pre:	c represents a valid command.
  Post:	Performs the given command c on the Extended_queue test_queue. Returns false if c=='q', otherwise returns true.
  Uses:	The class Extended_queue. */
{
	bool continue_input=true;
	Queue_entry x;
	switch(c){
	case 'r':
		if(test_queue.retrieve(x)==underflow)
			cout<<"Queue is empty."<<endl;
		else
			cout<<"The first entry is:"<<x<<endl;
		break;
	case 'q':
		cout<<"Extended queue demonstration finished."<<endl;
		continue_input=false;
		break;
	//Additional cases will cover other commands.
	}
	return continue_input;
}

Airport Simulation Program

在计算机模拟中,研究的对象通常表示为数据,它经常作为由类给出的数据结构,类的成员描述了对象的特性,类的方法表示被研究的操作,描述这些操作的规则被翻译成计算机算法。通过改变数据的值或通过修改这些算法,可以在计算机模拟中观察到一些变化,然后据此得出关于实际系统行为的有价值的理论。

飞机场的模拟:

  • Plane类:其对象表示单个飞机
  • Runway类:用于存放关于飞机跑道的状态和操作的信息,该类也将维护等待着陆和起飞的飞机队列的成员
  • Random类:在模拟中需要一个Random类来封装到达或离开跑道的飞机的随即特征,Random类的单个方法poisson(泊松随机数)使用一个浮点数的参数(表示一个平均结果)并返回一个整数值,虽然其返回值是随机的,但在重复调用该方法的过程中返回值的平均值将匹配指定的参数。
  • 重载:当不同函数使用单一的名称时(参数或返回值不同),称这个名称被重载类的说明常包含两个构造函数,其中一个带参数的函数用于初始化数据,另一个不带参数的函数,它们的值是无关的或者将由其他方式确定,因此不用初始化信息。
int main()		//Airport simulation program
/*Pre: The user must supply the number of time intervals the simulation is to run, 
	the expected number of planes arriving, the expected number of planes departing per time interval,
	and the maximum allowed size for runway queues.
  Post: The program performs a random simulation of the airport, showing the status of the runway at each time interval,
	and prints out a summary of airport operation at the conclusion.
  Uses: Classrs Runway, Plane, Random and function run_dile, initialize.*/
{
	int end_time;		//time to run simulation
	int queue_limit;	//size of Runway queues
	int flight_number = 0;
	double arrival_rate, departure_rate;
	initialize(end_time, queue_limit, arrival_rate, departure_rate);
	Random variable;	//随机对象variable
	Runway small_airport(queue_limit);
	for (int current_time = 0; current_time < end_time; current_time++)	{ 		
						//loop over time intervals
		int number_arrivals = variable.poisson(arrival_rate);
						//current arrival requests
		for (int i = 0; i < number_arrivals; i++) {
			Plane current_plane(flight_number++, current_time, arriving);//current_plane的状态(status)为到达(arriving)
			if (small_airport.can_land(current_plane) != success)				//若着陆飞机没能成功加入Runway的着陆队列
				current_plane.refuse;
						//拒绝飞机着陆请求
		}
		int number_departures = variable.poisson(departure_rate);//current departure requests
		for (int j = 0; j < number_departures; j++) {
			Plane current_plane(flight_number++, current_time, departing); 
						//current_plane的状态status为离开departing
			if (small_airport.can_depart(current_plane) != success)
						//若起飞飞机没能成功加入Runway的起飞队列
				current_plane.refuse();
		}
		Plane moving_plane;
		switch (small_airport.activity(current_time, moving_plane)) { 
						//let at most one Plane onto the Runway at current_time
		case land:
			moving_plane.land(current_time);
			break;
		case takeoff:
			moving_plane.fly(current_time);
			break;
		case idle:
			run_idle(current_time);
		}
	}
	small_airport.shut_down(end_time); 
}

Runway的方法activity控制着对Runway的使用

enum Runway_activity{idle, land, takeoff}
class Runway{
public:
	Runway(int limit);
	Error_code can_land(const Plane &current);
	Error_code can_depart(const Plane &current);
	Runway_activity activity(int time, Plane &moving);
	void shut_down(int time)const;
private:
	Extended_queue landing;
	Extended_queue takeoff;
	int queue_limit;
	int num_land_requests;
	int num_takeoff_requests;
			//number of planes asking to land/takeoff
	int num_landings;
	int num_takeoffs;
			//number of planes that have landed/takenoff
	int num_land_accepted;
	int num_takeoff_accepted;
			//number of planes queued to land/takeoff
	int num_land_refused;
	int num_takeoff_refused;
			//number of planes landing/departing planes refused
	int land_wait;
	int takeoff_wait;
			//total time of planes waiting to land/takeoff
	int idle_time;
			//total time runway is idle
};

Plane的构造函数Plane有两个,函数名称Plane被重载:

enum Plane_status{null, arriving, departing};
class Plane{
public:
	Plane();
	Plane(int flt, int time,Plane_status status);
	void refuse()const;
	void land(int time)const;
	void fly(int time)const;
	int started() const;
private:
	int flt_num;
	int clock_start;
	Plane_status state;
};

方法的具体实现略.

链式队列的循环实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值