数据结构(寒假小结)——3.2队列

来源:互联网 发布:网络视听节目内容审核 编辑:程序博客网 时间:2024/06/10 17:38

1.本节学习要点:

2.基本定义与相关名词:

队列:限定一端插入、另一端删除的线性表。

空队:队列中没有元素时

队头(front):允许删除的一端

队尾(rear) :允许插入的一端

PS:在队列中依次加入元素a1,a2,…,an之后,a1是队头元素,an是队尾元素。退出队列的次序只能是a1,a2,…,an。

4.基本运算:

1)初始化INITIATE(Q):构造一个空队列Q。
2)判队空EMPTY(Q):若队列Q空,返回1,否则返回0。
3)入队ENQUEUE(Q, x):在队尾插入元素x,x 成为新的队尾
4)出队DEQUEUE (Q):将队头元素删除,并返 回该元素。
5)取队头GETHEAD(Q):取队头元素,但不 删除它。

5.顺序队列:

顺序队列:队列的顺序存储结构。

1.用数组来实现。
2. 队头、队尾都变化,需要两个指针分别指示队头和队尾当前位置,front:队头指针rear:队尾指针
3. 约定:队头指针队头前一位置尾指针指向队尾。

PS:

              1.当队满时再入队必定产生空间溢出,简称“上溢”;上溢是一种出错状态,应该设法避免。

              2.当队空时再出队也将产生溢出,简称“下溢”;下溢则可能是正常现象,因为队列初态或终态都是空,下溢常作程序控制转移的条件。

              3.队列并不满,若尾指针已到数组上界,再入队也会溢出,称为“假上溢”

              4.假溢出:当元素被插入到数组中下标最大的位置上之后,队列的空间就用尽了,尽管此时数组的低端还有空闲空间,这种现象叫做假溢出。

              5.出队后原队头元素仍存在,但不作有效队元素,可直接覆盖

1.循环队列(解决假溢出):

循环队列:将存储队列的数组头尾相接;设想向量空间是一个首尾相接的圆环,称为循环向量,其中的队列称为循环队列(Circular Queue)。

1.空队时:front=rear;
2.入队时尾指针向前追赶头指针:
3.出队时头指针向前追赶尾指针,
4.队满时:front=rear。

如何判断队满队空?方法:

1)另设长度计数器n:入队n++,出队n--,当n为0时队空,n为maxsize时队满。
2)另设标志位flag以区分队空、队满:若入队后出现rear=front,则置flag=1,表明队满;其他情况flag=0.
3)空置一单元法:当循环响亮中只剩下1个元素空间,即已经存放maxsiza-1个元素时,就认为队满。
      即队满条件为:ront=(rear+1)%maxsize; 队空条件为:rear=front
     此时少用一个存储单元,且front所指处总为空。

2.基本运算(循环队列,方法(3)判队空队满):

typedef int datatype; //队列元素类型,假设为整型const int maxsize=100; //队列容量typedef struct {   datatype data[maxsize];   int front,rear;} sqqueue;//初始化void init_sqqueue(sqqueue *sq) {   sq−>front=sq−>rear=0; //不能为-1,0~maxsize-1}//判空int empty_sqqueue(sqqueue *sq) {   if(sq−>rear==sq−>front) return 1;   else return 0;}//取队列int gethead_sqqueue(sqqueue *sq,datatype *x) {  if(sq−>rear==sq−>front){   cout<<”队空,无队头可取!\n”;return 0;   }else    //头指针的下一个位置才是队头   {*x=sq−>data[(sq−>front+1)%maxsize];    return 1;} }//入队int en_sqqueue(sqqueue *sq,datatype x) {  if((sq−>rear+1)%maxsize==sq−>front)    {prinf(”队满,不能入队!\n”);return 0;} //上溢  else    {sq−>rear=(sq−>rear+1)%maxsize;     sq−>data[sq−>rear]=x;     return 1;} }//出队int de_sqqueue(sqqueue *sq,datatype *x) {  if(sq−>rear==sq−>front)    {cout<<”队空,不能出队!\n”;return 0;}    //下溢  else    {sq−>front=(sq−>front+1)%maxsize;     *x=sq−>data[sq−>front];     return 1;} }

5.链队列:

链队列:队列的链式存储结构,运算受限的单链表。

1.尾插法,取链表的头部作队头,尾部作队尾。
2.队列没有元素移动问题,链式存储是为了动态利用存储空间。
3.为运算方便,增加头结点。

typedef struct node * pointer; //结点指针类型struct node { //链队列结点结构   datatype data;   pointer next;}; typedef struct {   pointer front,rear;} lkqueue;//初始化void init_lkqueue(lkqueue *lq) {  pointer p;  p=new node;        //申请头结点空间  p−>next=NULL;        //头结点next指针为空  lq−>front=p;         //头指针指向头结点  lq−>rear=p;         //尾指针也指向头结点}//判空int empty_lkqueue(lkqueue *lq) {  if(lq−>rear==lq−>front) return 1;  else return 0;}//取队头int gethead_lkqueue(lkqueue *lq,datatype *x) {  pointer p;  if(lq−>rear==lq−>front)    {cout<<”队空,无队头可取!\n”;return 0;}  else    {p=lq−>front−>next;    //front是头结点,                    //front−>next才是队头     *x=p−>data;        //取出队头元素值     return 1;    }}//入队void en_lkqueue(lkqueue *lq,datatype x) {  pointer p;  p=new node;            //申请新结点空间  p−>data=x;            //给新结点赋值  lq−>rear−>next=p;        //原尾指针指向新结点  lq−>rear=p;            //新结点成为新尾结点  p−>next=NULL;            //新尾结点next指针为空}//出队int de_lkqueue(lkqueue *lq,datatype *x) {  pointer s;  if(lq−>rear==lq−>front)    {cout<<”队空,不能出队!\n”;return 0;}    //下溢  else    {s=lq−>front−>next;     *x=s−>data;     lq−>front−>next=s−>next;     if(s−>next==NULL)         lq−>rear=lq−>front;//尾指针也要修改     delete s; return 1;}}//等效出队:int de_lkqueue2(lkqueue *lq,datatype *x) {  pointer s;  if(lq−>rear==lq−>front)    {cout<<”队空,不能出队!\n”;return 0;}    //下溢  else    {s=lq−>front;     *x=s−>next−>data;     lq−>front=s−>next;     delete s; return 1;}}

6.顺序队列与链表的比较:

时间性能:
循环队列和链队列的基本操作都需要常数时间O (1)。

空间性能:
循环队列:必须预先确定一个固定的长度,所以有存储元素个数的限制和空间浪费的问题。
链队列:没有队列满的问题,只有当内存没有可用空间时才会出现队列满,但是每个元素都需要一个指针域,从而产生了结构性开销。

如果有错误请大家指出,共同学习共同进步!更多百度百科奋斗奋斗




1 0
原创粉丝点击