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++顺序与链式队列详解(附代码)
228 0
|
1月前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
51 2
|
1月前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
108 5
|
1月前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
100 4
|
1月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
123 4
|
2月前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
33 4
|
2月前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
33 4
|
2月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
30 1
|
2月前
|
存储 编译器 C++
【C++类和对象(下)】——我与C++的不解之缘(五)
【C++类和对象(下)】——我与C++的不解之缘(五)
|
2月前
|
编译器 C++
【C++类和对象(中)】—— 我与C++的不解之缘(四)
【C++类和对象(中)】—— 我与C++的不解之缘(四)