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

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

前言

  队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表**。队列是一种先进先出(First Input First Ouput),的线性表,简称FIFO。允许插入的一端称为队尾,允许删除的一端称为队头。**

既然是线性表,那么就可以分为顺序存储结构和链式存储结构。
队列存储结构的实现有以下两种方式:
顺序队列:在顺序表的基础上实现的队列结构;
链队列:在链表的基础上实现的队列结构;

本文将在链队列的基础上实现队列子系统,题目如下:
1.设计一个选择式菜单。
2.设计一个整型数据元素的链队列。
3.编写入队、出队、读队首元素、显示队列中全部元素的程序。
4.编写求解报数问题的应用程序,要求给出他们的出列顺序。
注:所谓报数问题,设n个人站成一排,从左到右的编号分别为1~n,从左到右报数“1,2,3,1,2,3”,数到“1”和“2”的人出列,数到“3”的人立即站到队伍的最右端。报数过程反复进行,直到n个人都出列为止。
如:n=10时,初始序列为1 2 3 4 5 6 7 8 9 10,
出列顺序为1 2 4 5 7 8 10 3 9 6。

一、顺序队列

  由于顺序队列的底层使用的是数组,因此需预先申请一块足够大的内存空间初始化顺序队列。除此之外,为了满足顺序队列中数据从队尾进,队头出且先进先出的要求,我们还需要定义两个指针(top 和 rear)分别用于指向顺序队列中的队头元素和队尾元素,如图所示

1:顺序队列入队

  由于顺序队列初始状态没有存储任何元素,因此 top 指针和 rear 指针重合,且由于顺序队列底层实现靠的是数组,因此 top 和 rear 实际上是两个变量,它的值分别是队头元素(首先出队数据的位置)和队尾(最后出队数据的后一个位置)元素所在数组位置的下标。
  在上图的基础上,当有数据元素进队列时,对应的实现操作是将其存储在指针 rear 指向的数组位置,然后 rear+1;当需要队头元素出队时,仅需做 top+1 操作。
例如,在上图的基础上将 {1,2,3,4} 用顺序队列存储的实现操作如下图所示:

在上图的基础上,我们知道出队其实就是top指针指向下一个数据,如下图所示:

  当然,如果接着插入数据5,6,那么假设这个数组只能容纳5个数据,那么数据6就溢出了,但是明明数组下标0,1,2的空间都还没存放元素,因此由于头铁而直接把数据插入在数组后面造成的溢出称为“假溢出”,因为我们可以把数据6放在a[0]位置,这样就解决了假溢出的问题,那么应该如何做到才可以解决这个问题呢,没错,让数组尾和数组头连接,也就是后面满了,再从头开始。这样的顺序存储结构称为循环队列。

紧接着入队a6,将它放置再下标为0处,此时rear指针指向下标为1处,如下图所示:

但是发现如果我们继续填充数据,那么就会出现下图的情况:

  但是rear=front的条件是队列为空时设定的,那么我们可以修改队列为满时的条件,我们可以保留一个元素空间,也就是说,队列满的时候,数组中还有一个空闲单元,如下图:

  由于rear可能比front大,也可能比front小,所以尽管他们只相差一个位置时就是满的情况,但也可能是相差整整一圈。所以若队列的最大尺寸为Size,那么队列满的条件就是(rear+1)%Size==front,(取模"%"的目的就是为了整合rear和front大小为一个问题)。比如上左图,(4+1)%5==0成立,如上右图,(1+1)%5==2成立,因此队列满,如果不符合这个条件,那么队列不满(可以自己实验)。
  另外,当rear>front时,此时队列长度为rear-front,但是如果rear<front,队列长度应该分为两段,一段是Size-front(据图可以计算处下标2到下标5是3个元素),另一段是rear-0(rear下标减去0下标,就可以知道rear到0有多少个元素了,如下图可以得出是1个),因此通用的计算队列长度的公式为:
(rear-front+Size)&Size。

  介绍完了基本概念以及基本写法,接下来就是如何写出顺序队列的代码。
  我们可以将顺序队列的代码分为几个实现:
  1:队列初始化  2:队列插入数据  3:队列删除数据  4:队列求长  
  5:返回队列头元素  6:显示队列全部元素

2:顺序队列出队

  出队较为简单,这是由于出队的一定是队首指向的元素,因此只需将队首指向的元素指向下一个要出队的元素即可。直接看代码中的DeQueue()函数即可

3:完整代码

#pragma once
#include<iostream>
#include <cstdio>
#include<cstdlib>
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 status = 0;//全局状态标志位 如果执行了销毁队列操作则置1
typedef struct queue
{
  ElemType data[MAXSIZE];
  int front;
  int rear;
}Queue;
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;
}
Queue* InitQueue(Queue* q) //队列初始化
{
  q->front = 0;
  q->rear = 0;
  return q;
}
Status DestoryQueue(Queue* q)//销毁队列
{
  if (q)
  {
    free(q);
    cout << "删除成功" << endl;
    status = 1;
    return OK;
  }
  else
  {
    cout << "队列未创建" << endl;
    return ERROR;
  }
}
Queue* ClearQueue(Queue* q) //清空队列
{
  if (q)
  {
    free(q);
    cout << "清空成功" << endl;
    Queue* head = (Queue*)malloc(sizeof(Queue));
    return head;
  }
  else
  {
    cout << "未存在队列" << endl;
    cout << "请先创建一个队列" << endl;
    exit(0);
  }
}
Status GetHead(const Queue* q, ElemType* e)//返回队列头
{
  if ((q) && (q->front != q->rear))//队列非空
  {
    cout << "队头元素是" << q->data[q->front] << endl;
    *e = q->data[q->front];
    return OK;
  }
  else
  {
    cout << "队列为空或队列不存在" << endl;
    return ERROR;
  }
}
Status EndQueue(Queue* q, ElemType e)//队尾插入元素 最多能插入MAXSIZE-1个数据
{
  if ((q->rear + 1) % MAXSIZE == q->front)//队列满
  {
    cout << "队列已满" << endl;
    return ERROR;
  }
  q->data[q->rear] = e;
  q->rear = (q->rear + 1) % MAXSIZE;//指针后移
  cout << "插入成功" << endl;
  return OK;
}
Status DeQueue(Queue* q, ElemType* e)//删除队头元素
{
  if (q && (q->front == q->rear))
  {
    cout << "队列为空" << endl;
    return ERROR;
  }
  *e = q->data[q->front];
  cout << "队头元素为" << *e << endl;
  q->front = (q->front + 1) % MAXSIZE; //头指向下一个数据
  return OK;
}
int QueueLength(const Queue q)//获得队列长
{
  return (MAXSIZE - q.front + q.rear) % MAXSIZE;
  cout << "长度为" << (MAXSIZE - q.front + q.rear) % MAXSIZE << endl;
}
void ShowQueue(Queue q)//显示所有数据
{
  if (status==0)//还未执行销毁操作
  {
    int i = 0;
    cout << "长度" << (MAXSIZE - q.front + q.rear) % MAXSIZE << endl;
    while ((q.front) % MAXSIZE != q.rear)
    {
      cout << "第" << i++ << "个数据是" << q.data[q.front++] << endl;
    }
  }
  else
  {
    cout << "队列不存在" << endl;
    exit(-1);
  }
}
int main()
{
  int choose;
  ElemType e;
  menu();
  Queue* head = (Queue*)malloc(sizeof(Queue));
  InitQueue(head);
  while (1)
  {
    cout << "请选择功能" << endl;
    cin >> choose;
    switch (choose)
    {
    case 1:
    {
      cout << "输入要入队的数据" << endl;
      cin >> e;
      EndQueue(head, e);
      break;
    }
    case 2:
    {
      DeQueue(head, &e);
      break;
    }
    case 3:
    {
      GetHead(head, &e);
      break;
    }
    case 4:
    {
      ShowQueue(*head);
      break;
    }
    case 5:
    {
      DestoryQueue(head);
      break;
    }
    case 0:
    {
      cout << "感谢使用,bye!" << endl;
      exit(0);
      break;
    }
    default:
      break;
    }
  }
}

4:运行结果


相关文章
|
存储 C语言 C++
C/C++顺序与链式队列详解(附代码)(二)
C/C++顺序与链式队列详解(附代码)
158 0
|
4天前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
1天前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
1天前
|
安全 编译器 C语言
【C++篇】深度解析类与对象(中)
在上一篇博客中,我们学习了C++类与对象的基础内容。这一次,我们将深入探讨C++类的关键特性,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载、以及取地址运算符的重载。这些内容是理解面向对象编程的关键,也帮助我们更好地掌握C++内存管理的细节和编码的高级技巧。
|
1天前
|
存储 程序员 C语言
【C++篇】深度解析类与对象(上)
在C++中,类和对象是面向对象编程的基础组成部分。通过类,程序员可以对现实世界的实体进行模拟和抽象。类的基本概念包括成员变量、成员函数、访问控制等。本篇博客将介绍C++类与对象的基础知识,为后续学习打下良好的基础。
|
1月前
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
70 19
|
1月前
|
存储 编译器 数据安全/隐私保护
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
52 13
|
1月前
|
编译器 数据安全/隐私保护 C++
【C++面向对象——继承与派生】派生类的应用(头歌实践教学平台习题)【合集】
本实验旨在学习类的继承关系、不同继承方式下的访问控制及利用虚基类解决二义性问题。主要内容包括: 1. **类的继承关系基础概念**:介绍继承的定义及声明派生类的语法。 2. **不同继承方式下对基类成员的访问控制**:详细说明`public`、`private`和`protected`继承方式对基类成员的访问权限影响。 3. **利用虚基类解决二义性问题**:解释多继承中可能出现的二义性及其解决方案——虚基类。 实验任务要求从`people`类派生出`student`、`teacher`、`graduate`和`TA`类,添加特定属性并测试这些类的功能。最终通过创建教师和助教实例,验证代码
54 5
|
1月前
|
存储 算法 搜索推荐
【C++面向对象——群体类和群体数据的组织】实现含排序功能的数组类(头歌实践教学平台习题)【合集】
1. **相关排序和查找算法的原理**:介绍直接插入排序、直接选择排序、冒泡排序和顺序查找的基本原理及其实现代码。 2. **C++ 类与成员函数的定义**:讲解如何定义`Array`类,包括类的声明和实现,以及成员函数的定义与调用。 3. **数组作为类的成员变量的处理**:探讨内存管理和正确访问数组元素的方法,确保在类中正确使用动态分配的数组。 4. **函数参数传递与返回值处理**:解释排序和查找函数的参数传递方式及返回值处理,确保函数功能正确实现。 通过掌握这些知识,可以顺利地将排序和查找算法封装到`Array`类中,并进行测试验证。编程要求是在右侧编辑器补充代码以实现三种排序算法
42 5
|
1月前
|
Serverless 编译器 C++
【C++面向对象——类的多态性与虚函数】计算图像面积(头歌实践教学平台习题)【合集】
本任务要求设计一个矩形类、圆形类和图形基类,计算并输出相应图形面积。相关知识点包括纯虚函数和抽象类的使用。 **目录:** - 任务描述 - 相关知识 - 纯虚函数 - 特点 - 使用场景 - 作用 - 注意事项 - 相关概念对比 - 抽象类的使用 - 定义与概念 - 使用场景 - 编程要求 - 测试说明 - 通关代码 - 测试结果 **任务概述:** 1. **图形基类(Shape)**:包含纯虚函数 `void PrintArea()`。 2. **矩形类(Rectangle)**:继承 Shape 类,重写 `Print
48 4