面向数据c++数据结构之基本数据结构(队列)--【美】Jan Harrington 陈博译

队列是一种先进后出的数据结构(见书)。元素从尾部进入队列,然后从头部离开。因此,队列是

一种等候列表,类似于我们在银行或者商店等候服务或者缴款时所排的队伍,人则像对列中的元素

,按照他们到达队伍的顺序接受服务。


4.2.1 队列的使用

  在多任务操作系统中,对列被用来保存等待CPU访问的进程,最常见的一种用法被称为round-

robin调度,它经常用在诸如LINUX这样的操作系统中。

  新近创建的进程进入队列的尾部。在CPU可用时,操作系统将进程发送到队列的头部并执行进程

。进程会一直进行,直到出现下列情形之一:分配给它的CPU时间(quantum)用完;等待I/O操作,

或者发生一个中断。

  如果进程由于分配给它的时间用完或者发生中断而交出CPU的控制权,它会重新进入队列末尾,

但是如果是由于等待I/O操作而停止执行,那么它会被阻塞,在I/O操作完成之后,它才能重新进入

队列,只有那些准备就绪听候CPU访问的进程才能进入队列。

  使用队列调度进程对于每个进程的CPU时间分配来说是一种相对公平的做法,短进程无需因为等

待长进程而受到不公平的待遇。最终的吞吐量和最终用户相应时间都是可以接受的。

  虽然如此,较长的进程需要多次通过队列才能完成作业。某些操作系统试图通过为程序赋予优先

级来解决长进程遭受到的不公平待遇,进程在队列中等待的时间越长,它的优先级就越高。操作系

统会首先发送拥有优先级的进程。在这种情况下,操作系统需要直接访问对列中的元素。

  注意:为所有长度的进程提供一个绝对公平的进程调度算法,或者在所有用户得到相同相应时间

的同时提高吞吐量是一件不可能的事情。在设计进程调度方案时,必须综合多种因素的影响。


4.2.2  使用数组实现队列

   和堆栈一样,队列的实现既可以使用数组也可以使用链表。采用数组的实现方式体现了操作系

统由主内存维护进程队列的操作方式,而且能够直接访问对列中的各个元素,但是由于数组的大小

在分配之时就已经确定,所以在可供使用的空间上存在限制。

   队列的节点类和堆栈的节点类完全相同(见程序4-1和程序4-2)。队列也通过元素在暑假数据

结构中的位置来访问元素,而不是使用关键字,因此,不需要编写一个Mix-In类来强制实现getKey

函数。


注意:同堆栈一样,队列不需要使用节点,因为队列的成员关系不要求指向成员对象的指针。所以

,队列可以将指向对象的指针保存在队列中,我们在这些列子中使用节点是为了与本书的其他例子

保持一致。


队列类(见程序4-12和程序4-13)包含这样一些函数:可以向对列中添加元素(元素的入列),从

对列中删除元素(出列),根据元素在对列中的位置取得元素,确定对列是否为空,以及取得队列

元素的当前数量。


[程序4-12]使用数组时队列类的声明


#ifndef  QUEUEMGR
#define  QUEUEMGR

#include "Thing.h"
#include "node.h"
#define MAX_ELEMENTS 10

class QueueMgr
{
  private:
    int queue_end;
    Node*theQueue(MAX_ELEMENTS);
   
  public:
     QueueMgr();
     bool enqueue(Thing*);//pass in a single element
     //pass in ordinal position of element
     bool getElement(int,Thing*&);
     bool dequeue(Thing*&);
     bool is_empty();//true if queue is empty
     int getSize();//return total elements in the array
};

#endif


[程序4-13]使用数组时对列类的具体实现

#include "QueueMgr.h"

QueueMgr::QueueMgr()
{
 queue_end=o;
}

bool QueueMgr::enqueue(Thing*newObject)
{
  bool result;
  Node*theNode=new Node(newObject);
  if (queue_end<MAX_ELEMENTS)
  {
   theQueue[queue_end]=theNode;
   queue_end++;
   result=true;
  }


 else
  result=false;
  return  result;
}

bool QueueMgr::getElement(int position,Thing*&element)
{
 int result=true;
 if(position>queue_end||queue_end==0)
  result=false;
 else
 {
  Node*theNode=theQueue[position];
  element=theNode->getThing();
 }
 return result;
}

bool QueueMgr::dequeue(Thing*&element)
{
  bool result =true;
  if(queue_end==0)
  result=false;
  else
  {
   Node*theNode=theQueue[0]; 
   element=theNode->getThing();
   for(int i=0;i<queue_end-1;i++)
    theQueue[i]=theQueue[i+1];
    queue_end--;
   }
  return result;
}

bool QueueMgr::is_empty()
{
 return (queue_end==0);
}

int QueueMgr::getSize90
{
 return queue_end==0;
}

int QueueMgr::getSize()
{ return  queue_end;)

从理论上说,队列管理器类应该有两个指针,一个指向队列的头部,一个指向队列的尾部。但是,

在使用数组实现队列的时候,如果能够保证对列的第一个元素总是保存在数组元素0中,那么只需

要对队列的尾部保持跟踪即可。

为了将一个元素放入队列,队列管理器需要执行以下操作:
(1)创建一个新的节点,以便将对象链接到队列
(2)如果对列中有空间可用,将新节点插入到队列的尾部,并增加指向对列尾部的指针,返回

true
(3)否则,返回fasle

将一个元素出列要稍微复杂一些,因为需要将数组中的所有元素向前移动一个位置,以保证队列的

第一个元素始终保存在数组元素0中。
(1)确定队列是否为空,如果为空,则返回false并退出函数
(2)否则,取得对列顶部的节点
(3)取得队列顶部的节点所指向的对象
(4)删除节点对象
(5)执行下一个循环,从数组元素1开始,将所有后续元素向前移动一个为位置,
(6)减小指向对列尾部的指针
(7)返回true

4.2.3 使用链表实现对列

   在采用链表实现队列时,队列类看上去就和期望中的更加相似了。它有头和尾两个指针,提供

了对队列两端的访问(见程序4-14和程序4-15)。该队列类使用的节点类与我们前面实现堆栈时所

使用的节点类完全相同(见程序4-8和程序4-9)。


【程序4-14】使用链表时队列类的声明

#ifndef  QUEUE
#define  QUEUE

#include "Thing.h"
#include "node.h"

class Queue

{
  private:
    Node*head,*tail;
  public:
    Queue();
    int is_empty();
    bool enqueue (Thing*)
    Thing*dequeue();
    Node*getHead();
};

#endif

[程序4-15]使用链表事队列类的具体实现。

#include "queque.h"


Queue::Queue()
{
 head=0;
}

int Queue::is_empty()
{return (head==0);}

bool Queue ::enqueue (Thing*theThing)
{
 Node*theNode=new Node(theThing):
 if(!theNode)
 {
  cout<<"/nCannot creat node."
  return;
 }
 if(is_empty)
{
  head=theNode;
  tail=theNode;
}

else
{
  tail->setNext(theNode);
  tail=theNode;
}

return true;

Thing*Queue::dequeue()
{
  Node*theNode=head;
  head=theNode->getNext90;
  Thing*theThing=theNode->getThing90;
  delete theNode;
  return theThing;
}

Node*Queue::getHead()
{
 Node*theNode=head;
 return theNode;
}

  为了将一个对象放进队列,使用链表实现的队列类需要完成如下操作:

(1)创建一个节点,将对象链接到队列
(2)如果队列为空,则将队列的头指针和尾指针均指向新节点,然后跳到步骤5.
(3)否则,将尾节点的next指针指向新节点
(4)设置队列管理器的tail变量,使其指向新节点
(5)返回true

注意:对链表的插入操作应该不会失败,除非程序用尽了内存,通过检查新节点是否返回成功关键

,可以得知是否发生了错误。

在使用链表实现队列时,将对象从队列冲删除的过程比使用数据时要简单一些
(1)取得位于队列头部的节点
(2)设置队列管理器的head变量,使其指向队列当前就节点的后继节点。
(3)取得队列当前的头节点所指向的对象
(4)删除节点
(5)返回队列节点所指向的对象。

  4.3 小结

   堆栈是一种后入先出式的数据结构,可以使用数组或链表实现。在程序执行期间,操作系统一

般使用堆栈保存函数返回地址和传递参数。其他数据结构(例如二叉树)也使用堆栈使用遍历操作

  队列是一种先入后出式的数据结构,也可以使用数组或链表实现。例如,在操作系统可以使用队

列保存等待CPU访问的进程

***********************以上资料来源于《面向对象c++数据结构》--【美】Jan Harrington
                                                               陈博译

***********************************************************************************

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值