新手笔记——数据结构队列c++

目录

前言

一、队列是什么?

二,两种形式的实现

  1.关于队列的一些基本操作

2.链队的实现

 A.定义结构体部分

B.初始化操作

C.判空操作,链式存储不需要判满

D.获取队列长度和队首数据

E.入队操作,因为是链式存储,不需要考虑空间的问题,不需要判满。

F.出队操作

main函数

3、循环队列的实现

  A.结构体的定义

  B.初始化操作

  C.判空、判满以及获取队列长度

  D.入队

  E.出队

  main函数

总结


个人的数据结构笔记,仅供参考,同时希望有大佬可以纠正我的错误


前言

数据结构中关于队列的基本认识以及队列的实现,当然这里只是我的个人见解,有不对的可以补充!!!


一、队列是什么?

定义:队列是一种“先进先出”的线性表。

         a.队列只允许在队首删除数据元素,队尾添加数据元素。

         b.基本分为 基于链表的队列(链队)和 基于数组的循环队列

二,两种形式的实现

  1.关于队列的一些基本操作

initQueue(&Q)//初始化操作

QueueEmtype(Q)//判空

QueueLength(Q)//获取队列的长度

getHead(Q)//获取队首元素

EnQueue(&Q)//入队操作

DeQueue(&Q)//出队操作

2.链队的实现

     A.定义结构体部分

          a.定义Node来作为链表的存储节点,包含数据域指针域

         b.定义LinkQueue,功能相当于锁定队列的头和尾,front指针来存储队列的首地址(头节点地址),rear指针来存储对尾结点。

   


typedef int QueueElemenType;

struct Node{

    QueueElemenType data;//结点的数据域;
    Node *next;//结点的指针域;
};
//构造一个Node类型的指针来锁定队的元素
   //我的理解:
     //将队列的头节点的地址保存在front指针中,存储的数据元素在front的的下一个结点中;
     //将队列的尾结点的地址保存在rear指针中;
struct LinkQueue{
     
     Node *front;//锁定队列的头部
     Node *rear;//锁定队列的尾部;
};

 B.初始化操作

//队的初始化操作;
    //链式结构存储
void initQueue(LinkQueue &q){

    q.front = new Node;//向存储系统申请一个空间
    if(!q.front)
    {
        cout<<"error!"<<endl;
        exit(0);
    }
    q.rear = q.front;//并将头指针和尾指针指向这一空间;
    q.front->next = NULL;//此时对首结点为q,使其指针域指向NULL;
}

C.判空操作,链式存储不需要判满

bool QueueEmpty(LinkQueue q){
      
    //队首队尾指向同一个空间,且头节点指向NULL
    return q.front == q.rear && q.front->next==NULL;
}

D.获取队列长度和队首数据

int QueueLength(LinkQueue q){

    Node *p = q.front->next;//类似于带头节点的链表从头结点的下一号位置开始遍历;
    int length = 0;
    while(p)
    {
        p = p->next;
        length++;
    }
    return length;
}
//获取队首的值
QueueElemenType getHead(LinkQueue q,QueueElemenType &e){

    if(QueueEmpty(q))
    {
        cout<<"Emtype!"<<endl;
        exit(0);
    }
    e = q.front->next->data;//将q.front看作头节点;
    return e;
}

 E.入队操作,因为是链式存储,不需要考虑空间的问题,不需要判满。

//入队操作
   //队列依循“先进先出”的定律,只在队尾增添元素;
void EnQueue(LinkQueue &q,QueueElemenType e){

    Node *p;
    p = new Node;
    p->data = e;
    p->next = NULL;
    q.rear->next = p;//将新节点插入尾部
    q.rear = p;//设立新的尾结点
}

F.出队操作

  //出队操作

     //队列的出队操作只在队首进行

      1、判空;

      2、申请新的节点,将对首数据赋给新的节点存储;

      3、原来的队首退一步;

      4、判断改变后队列中是否有元素,若无将首尾指向同一个节点

      此时就会形成空间的浪费,引入循环链表解决该问题;

QueueElemenType DeQueue(LinkQueue &q)
{
    QueueElemenType e;
    if(QueueEmpty(q))//判空
    {
        cout<<"Emtype!"<<endl;
        exit(0);
    } 
     Node *p;
    p = new Node;

    p = q.front->next;//存储出队的结点
    e = p->data;

    q.front->next = p->next;//队首结点后退

    if(p == q.rear)//若原有队列只含一个元素,则删除后队列为空
     q.front = q.rear;
    delete p;
    return e;
}

main函数

个人的简单测试

int main()
{
    LinkQueue Q;
    initQueue(Q);
    for(int i=1;i<6;i++)
    {
        EnQueue(Q,i);
    }
    int e=0;
    cout<<getHead(Q,e)<<endl;
    for(int i=0;i<5;i++)
    {
        cout<<DeQueue(Q)<<" ";
    }
}

3、循环队列的实现

         这里先介绍一下循环队列。

         定义:为充分利用向量空间,克服"假溢出"现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列(Circular Queue)。循环队列是把顺序队列首尾相连,把存储队列元素的表从逻辑上看成一个环,成为循环队列。

         这里的实现代码是基于数组实现的哦~

       A.结构体的定义

           基于数组实现,*base 是一个指向存储数组的指针,相当于Arry[n]中的Arry(个人愚见,便于理解),由于队列的插入与删除,分别只在队尾和队首进行,我们也只需要通过front,rear来记录队首和队尾的下标。

#define Maxsize 10
typedef int QElemetype;

struct SqQueue{
      
      QElemetype *base;//存储数组的指针,base指针指向存储数组,可以通过front,rear来访问元素
      int front;//数组第一个元素的下标
      int rear;//数组最后一个元素的下标
};

       B.初始化操作

void initQueue(SqQueue &q){

    q.base = (QElemetype *)malloc(sizeof(QElemetype)*Maxsize);//引用malloc函数来实现,向系统申请连续空间的任务;
    if(!q.base)//若空间申请失败
    {
        cout<<"error!!!"<<endl;
        exit(0);
    }
    q.front = 0;//空间申请成功,front和rear标记同一个单元格
    q.rear = 0;
}

        C.判空、判满以及获取队列长度(这里的判空和判满我采取了tips里的第二种方法)

          tips:判别空间满和空有种方式:一是设立一个标记来区别满还是空二是舍弃了一个空间格防止“满”时front和rear也指向同一空间,约定队首指针在队尾指针的下一个位置时为“队列满”

//判空
bool QueueEmpty(SqQueue q){

    return q.front == q.rear;//front 与 rear 相同时 数组为空
}
//判满
bool QueueFull(SqQueue q){

    return (q.rear+1)% Maxsize == q.front;//循环数组最后一位元素的下一位为循环数组的头时,数组空间满了 
}
//获取队列长度
int getLength(SqQueue q){

    return (q.rear - q.front + Maxsize)%Maxsize;//rear不一定大于front
}

        D.入队

void EnQueue(SqQueue &q,QElemetype e){

  if(QueueFull(q)) 
  exit(0);

  q.base[q.rear] = e;//通过数组base[]来存储,依循队列只在最后一位元素后添加数据的原则,我们可以通过标记的q.rear来访问队尾
  q.rear = (q.rear + 1)%Maxsize;//*同时注意base[q.rear]位置上始终为空,所以这里表示q.rear向后退了一步

}

        E.出队

QElemetype DeQueue(SqQueue &q)
{
    QElemetype e;
    if(QueueEmpty(q))
     exit(0);

    e = q.base[q.front]; //通过数组base[]来存储,依循队列只在最后一位元素后添加数据的原则,我们可以通过标记的q.front来访问队首
    q.front = (q.front+1)%Maxsize; // 释放掉一个数据后,队首不再是原来的的队首,向后退一格

    return e;
}

     个人测试代码

int main()
{
    SqQueue s;
    initQueue(s);
    for(int i=0;i<5;i++)
    {
        EnQueue(s,i);
    }
    cout<<getLength(s)<<endl;
    for(int i=0;i<10;i++)
    {
         cout<<DeQueue(s)<<" ";
    }
}

总结

队列的两种基本形式差不多就是这样了哦~~~,写完跑路,溜了溜了~~~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值