C/C++顺序与链式队列详解(附代码)(二)

简介: C/C++顺序与链式队列详解(附代码)

二、链式队列(队列子系统课设)

1:链队列入队

  链式队列的实现思想同顺序队列类似,只需创建两个指针(命名为 top 和 rear)分别指向链表中队列的队头元素和队尾元素

  上图所示为链式队列的初始状态,此时队列中没有存储任何数据元素,因此 top 和 rear 指针都同时指向头节点。

  链队队列中,当有新的数据元素入队,只需进行以下 3 步操作:
1:将该数据元素用节点包裹,例如新节点名称为 elem;
2:与 rear 指针指向的节点建立逻辑关系,即执行 rear->next=elem;
3:最后移动 rear 指针指向该新节点,即 rear=elem;

  由此,新节点就入队成功了。
  例如,在上图的基础上,我们依次将 {1,2,3} 依次入队,各个数据元素入队的过程如下图所示:

2:链队列出队

  当链式队列中,有数据元素需要出队时,按照 “先进先出” 的原则,只需将存储该数据的节点以及它之前入队的元素节点按照原则依次出队即可。这里,我们先学习如何将队头元素出队。

  链式队列中队头元素出队,需要做以下 3 步操作:
1:通过 top 指针直接找到队头节点,创建一个新指针 p 指向此即将出队的节点;
2:将 p 节点(即要出队的队头节点)从链表中摘除;
3:释放节点 p,回收其所占的内存空间;

  例如,在上图的基础上,我们将元素 1 和 2 出队,则操作过程如下图所示:

3:完整代码

  本人自己感觉c++的cout和cin比c语言的scanf和printf更加好用,因此代码中的printf和scanf都被我用cout和cin代替了,如果需要纯c语言的代码,可以自行将代码中的cout和cin改换成printf和scanf即可。代码部分并没有出现只有c++特有的函数,因此不需要担心修改问题

#pragma once
#include<iostream>//cout和cin需要这个头文件
#include <cstdio>//引入c语言库函数
#include<cstdlib>///引入c语言库函数
typedef int Status;
typedef int ElemType;
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define MAXSIZE 5
#define make (struct student*)malloc(sizeof(struct student));
using namespace std;
int num = 0;
int status = 0;
typedef struct QueueList 
{
    ElemType data;
    struct QueueList* next;
}QueueList;    
void menu(void)
{
    cout << "********************" << endl;
    cout << "*1 ……入队        *" << endl;
    cout << "*2 ……出队        *" << endl;
    cout << "*3 ……读队首元素  *" << endl;
    cout << "*4 ……显示        *" << endl;
    cout << "*5 ……排队    *" << endl;
    cout << "*0 ……退出        *" << endl;
    cout << "********************" << endl;
}
QueueList* InitQueue()  //创建链式队列的函数
{
    if (status == 1)//进行过5操作后,数据全部被free了,强制退出程序
    {
        cout << "队列已被删除" << endl;
        exit(-1);
    }
    QueueList* head = (QueueList*)malloc(sizeof(QueueList));    //创建一个头节点
    head->next = NULL; //对头节点进行初始化
    return head; 
}
QueueList* EndQueue(QueueList* rear, ElemType e)
{
    if (status == 1)//进行过5操作后,数据全部被free了,强制退出程序
    {
        cout << "队列已被删除" << endl;
        exit(-1);
    }
    QueueList* p = (QueueList*)malloc(sizeof(QueueList));//构造新节点
    p->data = e; //数据赋值
    p->next = NULL;//封闭队列
    rear->next = p;//让队尾指向p
    rear = p;//新队尾为p
    num++;
    cout << "当前数量" << num << endl;
    return rear;//返回新队尾
}
QueueList* DeQueue(QueueList* front, QueueList* rear)
{
    if (status == 1)//进行过5操作后,数据全部被free了,强制退出程序
    {
        cout << "队列已被删除" << endl;
        exit(-1);
    }
    if ((front->next == NULL)||(front==rear))
    {
        cout << "队列为空" << endl;
        return rear;
    }
    QueueList* p = (QueueList*)malloc(sizeof(QueueList));
    p = front->next;//此时p为要删除的数据
    cout << "待删除的数据是" << p->data << endl;
    front->next = p->next;
    if (p == rear)//此时要删除的数据就已经是最后一个数据
        rear = front;//此时队列已空,返回原有头指针即可
    free(p);
    num--;
    cout << "当前数量" << num << endl;
    return rear; 
}
Status ShowQueue(QueueList* front)
{
    if (status == 1)//进行过5操作后,数据全部被free了,强制退出程序
    {
        cout << "队列已被删除" << endl;
        exit(-1);
    }
    int i = 0;
    if (front->next == NULL)
    {
        cout << "队列为空" << endl;
        return ERROR;
    }
    do
    {
        cout << "第" << i++ << "个数据是" << front->next->data << endl;
        front = front->next;//显示数据的代码
    } while (front->next != NULL);
    return OK;
}
Status GetHead(const QueueList* front)
{
    if (front->next == NULL)
    {
        cout << "队列为空" << endl;
        return ERROR;
    }
    cout << "队列头元素为" << front->next->data << endl;
    return OK;
}
//出列顺序为1 2 4 5 7 8 10 3 9 6。
Status LeaveQueue(QueueList* front, QueueList* rear)
{
    status = 1;
    QueueList* p, * p1;
    if (front == rear)
    {
        cout << "队列为空" << endl;
        return ERROR;
    }
    p = front->next;
    while (num != 0)
    {
        for (int i = 1; i <= 2; i++)
        {
            p1 = p;
            cout << p->data << endl;
            if (p->next != NULL)
            {
                p = p->next;
                free(p1);
                num = num - 1;
            }
            else
            {
                free(p1);
                num = num - 1;
                break;
            }
        }
        p1 = p;
        if (p->next == NULL)
        {
            cout << p->data << endl;
            free(p);
            num = num - 1;
        }
        else
        {
            rear->next = p;
            p1 = p1->next;
            p->next = NULL;
            rear = p;
            p = p1;
        }
    }
}
int main()
{
    int choose;
    ElemType e;
    menu();
    QueueList* front, * rear, * p;
    front = rear = p = InitQueue();
    while (1)
    {
        cout << "请选择" << endl;
        cin >> choose;
        switch (choose)
        {
        case 1:
        {
            cout << "输入要插入的数据" << endl;
            cin >> e;
            rear = EndQueue(rear, e);
            break;
        }
        case 2:
        {
            rear = DeQueue(front, rear);
            break; 
        }
        case 3:
        {
            GetHead(front);
            break;
        }
        case 4:
        {
            ShowQueue(front);
            break;
        }
        case 5:
        {
             LeaveQueue(front,rear);
             break;
        }
        case 0:
        {
            cout << "退出" << endl;
            exit(0);
        }
        default:
            break;
        }
    }
}

4:运行结果

  可以发现,我输入了10个数据之后,选择5功能后,队列内的数据按照1,2出列,3插到最后的要求实现了。这也就是队列的排队。

总结

  只能说早期的鸟儿有虫吃,昨天写了一个晚上没把5功能实现,结果今天写了半小时写出来了T-T

相关文章
|
存储 C++
C/C++顺序与链式队列详解(附代码)(一)
C/C++顺序与链式队列详解(附代码)
185 0
|
15天前
|
编译器 C++
C++ 类构造函数初始化列表
构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。
60 30
|
4天前
|
并行计算 Unix Linux
超级好用的C++实用库之线程基类
超级好用的C++实用库之线程基类
12 4
|
4天前
|
C++ Windows
HTML+JavaScript构建C++类代码一键转换MASM32代码平台
HTML+JavaScript构建C++类代码一键转换MASM32代码平台
|
4天前
|
C++
2合1,整合C++类(Class)代码转换为MASM32代码的平台
2合1,整合C++类(Class)代码转换为MASM32代码的平台
|
4天前
|
存储 运维 监控
超级好用的C++实用库之日志类
超级好用的C++实用库之日志类
10 0
|
29天前
|
存储 编译器 C++
C ++初阶:类和对象(中)
C ++初阶:类和对象(中)
|
2月前
|
存储 安全 编译器
【C++】类和对象(下)
【C++】类和对象(下)
【C++】类和对象(下)
|
29天前
|
C++
C++(十六)类之间转化
在C++中,类之间的转换可以通过转换构造函数和操作符函数实现。转换构造函数是一种单参数构造函数,用于将其他类型转换为本类类型。为了防止不必要的隐式转换,可以使用`explicit`关键字来禁止这种自动转换。此外,还可以通过定义`operator`函数来进行类型转换,该函数无参数且无返回值。下面展示了如何使用这两种方式实现自定义类型的相互转换,并通过示例代码说明了`explicit`关键字的作用。
|
29天前
|
存储 设计模式 编译器
C++(十三) 类的扩展
本文详细介绍了C++中类的各种扩展特性,包括类成员存储、`sizeof`操作符的应用、类成员函数的存储方式及其背后的`this`指针机制。此外,还探讨了`const`修饰符在成员变量和函数中的作用,以及如何通过`static`关键字实现类中的资源共享。文章还介绍了单例模式的设计思路,并讨论了指向类成员(数据成员和函数成员)的指针的使用方法。最后,还讲解了指向静态成员的指针的相关概念和应用示例。通过这些内容,帮助读者更好地理解和掌握C++面向对象编程的核心概念和技术细节。