[PTA]:R7-6 队列操作 思路分享 [数据结构] [队列及其链式存储] [c++]

目录

一.队列以及其链式存储的介绍

二. 题目复现及分析

三. 代码展示(c++)

一.队列以及其链式存储的介绍

1. 队列:

属于线性表的一种,它的特殊点在于具有先进先出的特点(只允许在表头删除元素,表尾进行插入元素)。

同样的,它也有两种存储方式:顺序存储和链式存储。今天我们所完成的这道题就是使用队列的链式存储。如下图1所示:

图1

  (1)front、next、rear 为队列结点类型的指针,指向队列节点。

   (2)front、next分别为(一直)指向这一队列链表的头结点和尾节点。

   (3)一般的,我们会多设置一个不存放data头结点。让front指针指向它,它指向下一个存放data的结点(首元结点),如图2,本题便用这种形式。  

图2

2.学习中难理解点:

(1)为什么要设头指针front和尾指针rear?

         因为队列要具有先进先出的特点,先入队的元素越靠近头部,因此可以直接利用头指针删除第一个结点;同样的可以直接利用尾指针添加结点。

(2)每个结点包括了什么?

         一个存放数据data元素的数据域;一个存放该结点类型的指针next(指向下一个结点),用于联系每个结点的关系用以组成整个链表。

3.具体入队出队初始化操作在代码展示那注释

[PTA]:R7-6 队列操作 思路分享 [数据结构] [队列及其链式存储] [c++]_第1张图片

二. 题目复现及分析

R7-6 队列操作 (20 分)

请实现一个MyQueue类,实现出队,入队,求队列长度.

实现入队函数 void push(int x); 实现出队函数 int pop(); 实现求队列长度函数 int size();

输入格式:

每个输入包含1个测试用例。每个测试用例第一行给出一个正整数 n (n <= 10^6) ,接下去n行每行一个数字,表示一种操作: 1 x : 表示从队尾插入x,0<=x<=2^31-1。 2 : 表示队首元素出队。 3 : 表示求队列长度。

输出格式:

对于操作2,若队列为空,则输出 “Invalid”,否则请输出队首元素。 对于操作3,请输出队列长度。 每个输出项最后换行。

输入样例:

5
3
2
1 100
3
2
  • 第一个输入的n控制所做操作的次数,可以用循环控制。
  • 接下来是3或1或2表示不同操作,用if语句控制。
  • 用Queue类实例化一个队列对象来进行这些方法操作。

题目中还要求结尾无空行,但是我试过有空行还是会通过,所有我的代码没有考虑结尾无空行。如果要考虑进去,可以从它的操作次数n下手,当n==0时输出不带空格。)

输出样例:

0
Invalid
1
100

三. 代码展示(c++)

#include
using namespace std;
/*
队列Queue类,封装了队列结点、指向队头和队尾的指针以及队列的一些操作;
*/
class Queue {
    private:
    //队列结点
        typedef struct QNode{
            int data;
            struct QNode*next;
        }QNode,*Qpointer;
//指向队头和队尾的指针结构体
        typedef struct {
            Qpointer front;
            Qpointer rear;
            int size;
        }LinkQueue;
    
    private:
    //声明一个队列指针结构体
        LinkQueue linkq;
    
    public:
    //构造队列(初始化)
        Queue() {
            linkq.front=new QNode;//开辟一个队列结点(此时为头结点)类型内存,让linkq的头指针指向该内存
            linkq.rear=linkq.front;//让尾指针暂时指向头指针
            linkq.front->next=NULL;//头节点next置NULL
            linkq.size=0;//初始化队列长度为0;
        }
        
    //入队
        void push(int x) {
            //以下三行为开辟一个新队列结点,存放入队元素,同时next置NULL
            QNode* p=new QNode;
            p->data=x;
            p->next=NULL;
            //以下三行为将这个新结点接入队列链的尾部(此时这个新节点和队列链没有 任何关系)
            linkq.rear->next=p;/*因为rear指针总指向最后一个结点,因此rear.next为最后一个结点的next指针。
               这一步目的是将队列链尾结点指向新的结点,让新结点成为尾结点。*/
            //另外,判断队空的条件就是rear是否指向front指针(front始终不动,指向第一个结点)
            linkq.rear=p;//因为新结点成为了尾结点,rear指针自然的要更新其指向的结点,去指向这个新结点
            linkq.size++;//每没入队一个结点,则长度加一;
        }
     //出队
        int pop(bool& status) {
            status=true;//这个status引用为了检查是否队空
            int elem;
            if(linkq.front==linkq.rear)//队空,status为false
            {
                status=false;
                return -1;//结束
            }
            //若非空
            QNode *q;//声明一个结点指针
            q=linkq.front->next;/*让q指针指向该队链第一个存放data的结点,目的是方便取这个出队结点的data及判别该节点是否是
            尾结点(front指向第一个结点即头结点,头节点的下一个元素才是存放data的结点)*/
            
            //因为出队第一个存放data的结点,因此只要将front头指针指向该结点,而指向出队结点的下一个结点就行了
            linkq.front->next=linkq.front->next->next;
            if(linkq.rear==q)//队空
            {
                /*若要删除的结点恰好是尾结点,删除之后队链便没有了存放data的结点,为队空。因此我们
             要让队尾rear指针重新指向front指向的存储位置(回到初始化时的状态)*/
                linkq.rear=linkq.front;
            }
            elem=q->data;//返回出队结点的data
            delete q;//释放出队结点的内存
            linkq.size--;//队长度减一
            
            return elem;
        }
    
        int getSize()//返回队列长度
        {
            return linkq.size;
        }
};

int main()
{
    Queue Q;//实例化一个Queue对象,并初始化Q
    bool status;
    int N;//控制操作次数
    int frontelem;
    int elem;
    int choice;
    cin>>N;
    while(N--)
    {
        cin>>choice;
        if(choice==1)
        {
            cin>>elem;
            Q.push(elem);
        }
        else if(choice==2)
        {
            frontelem=Q.pop(status);
            if(status)//判断是否队空
                cout<

你可能感兴趣的:(链表,数据结构)