在编程语言中怎样定义队列及其使用(C++)

 更新时间:2020年4月25日 17:26  点击:2165

队列在编程语言中是如何定义的呢?小编与大家分享自己的经验。

队列的定义

队列是限制结点插入操作固定在一端进行,而结点的删除操作固定在另一端进行的线性表.

队列犹如一个两端开口的管道.允许插入的一端称为队头,允许删除的一端称为队尾.队头和队尾各用一个”指针”指示,称为队头指针和队尾指针.不含任何结点的队列称为”空队列”.队列的特点是结点在队列中的排队次序和出队次序按进队时间先后确定,即先进队者先出队.因此,队列又称先进先出表.简称FIFO(first in first out)表.

步骤

队列是用来存储暂未处理但需要按一定顺序处理的元素的一种数据结构。

队列是一种先进先出(First In First Out,FIFO)的线性表,特点是先进队的元素先出队。

队列只允许在表的一端进行插入,而在另一端删除元素。

队尾是队列中允许插入的一端;队首是队列中允许删除的一端。

一般用顺序表q[m]存储队列中的元素,m是队列能存储元素的最大数量。

front队首指针指向队首元素存储的位置;rear队尾指针指向队尾元素的下一个位置。

顺序队列及其操作

队列的顺序存储结构

顺序存储结构存储的队列称为顺序队列.和顺序表一样,用一个一维数组存.对头在数组的低下标端,队尾设在高下表端.队头,队尾指针值是数组元素的下标.对头指针始终指向对头结点的前一个结点位置,初始值为0.队尾指针是指向队尾结点位置,初始值也为0.

 

队列初始条件:队头指针=队尾指针=0
队列满条件:队尾指针=m(设队列当前容量为m)
队列空条件:队头指针=队尾指针

在QueueCs.c文件中定义了结构

#define DT char
#define M 100
typedef struct {

  DT data[M];
  int front,rear;
}SEQUEUE;

data[M]也为数组为队列,front为队头指针,rear为队尾指针.(注意:front和rear是整数类型,不是指针类型),当front=rear=0时,为初始队列.因为C语言中数组的第一个元素下标为0,而不是1;所以这里约定数组元素data[0]闲置不用.

顺序队列上的操作

(1)创建队列

初始化队列,队头指针和队尾指针=0.

在QueueControl.h写出方法声明

/*
 创建队列
 */
SEQUEUE initQueue();

在QueueControl.c中实现此方法

#include "QueueControl.h"
/*
 创建队列
 */
SEQUEUE initQueue(){
  SEQUEUE Q;
  //1.初始化队列,队头指针=队尾指针=0
  Q.front=Q.rear=0;
  return Q;
}

(2)插入

在QueueControl.h写出方法声明

/*
 插入
 */
SEQUEUE inQueue(SEQUEUE Q,DT x);

在QueueControl.c中实现此方法

#include "QueueControl.h"

SEQUEUE inQueue(SEQUEUE Q,DT x){
  //1.判断队列是上溢,就是队尾指针是否等于最大申请的空间
  if(Q.rear==M){
    printf("Up Overflow\n");
  }else{
     //2.从队尾插入结点
    Q.rear++;
    Q.data[Q.rear]=x;
    printf("in success\n");
  }
  return Q;
}

(3)删除

在QueueControl.h写出方法声明

/*
 删除
 */
SEQUEUE outQueue(SEQUEUE Q);

/*
 打印队列元素
 */
void printQueue(SEQUEUE Q);

在QueueControl.c中实现此方法

#include "QueueControl.h"

SEQUEUE outQueue(SEQUEUE Q){
  //1.首先判断是否是空队列
  if(Q.front==Q.rear){
    printf("queue is empty\n");
  }else{
    //2.删除结点是从队头删除
    Q.front++;
     printf("out success\n");
  }
  return Q;
}



/*
 打印队列元素
 */
void printQueue(SEQUEUE Q){
  //1.从队头开始打印数据
  SEQUEUE temp=Q;
  printf("queue={");
  while (temp.front<temp.rear) {
     temp.front++;
    if(temp.front==Q.front+1){
      printf("%c",temp.data[temp.front]);
    }else{
      printf(",%c",temp.data[temp.front]);
    }

  }
  printf("}\n");
}

在main.c中的main方法(int main(int argc, const char * argv[]) {})调用此方法,并且进行判断

#include "QueueControl.h"
int main(int argc, const char * argv[]) {
  //初始化顺序队列
  SEQUEUE queue=initQueue();
  printQueue(queue);
  //插入
  queue=inQueue(queue, 'a');
  queue=inQueue(queue, 'b');
  queue=inQueue(queue, 'c');
  queue=inQueue(queue, 'd');
  printQueue(queue);
  //删除
  queue=outQueue(queue);
  printQueue(queue);
  return 0;

}

打印结果:

queue={}
in success
in success
in success
in success
queue={a,b,c,d}
out success
queue={b,c,d}
Program ended with exit code: 0

从插入队列和删除队列操作的打印结果来看,队列的特点确实是:先进先出.

循环队列及其操作

循环队列的存储结构

根据顺序队列的操作和叙述可以看出,队尾指针=m表示队满,不能再插入结点了,当队头指针等于队尾指针表示对空.但是当队尾指针和队尾指针都等于m的时候,那么此时表示对空,那么也不能插入了其他的结点,但是此时0-m之间的结点已经空闲,这样许多空闲的结点不能被利用,浪费存储空间.

循环队列是把顺序队列的头尾相接形成一个圆环.逻辑上吧1号结点作为m号结点的后继结点处理.

 

循环队列初始条件:队头指针=队尾指针=0
循环队列队满条件:MOD(队尾指针+1,m)=队头指针
循环队列空条件:队头指针=队尾指针
队头指针推进计算:队头指针=MOD(队头指针+1,m)
队尾指针推进计算:队尾指针=MOD(队尾指针+1,m)

在QueueCycleCs.c文件中定义了结构

#define CDT char
#define CM 5
typedef struct {

  CDT data[CM];
  int front,rear;
}SECYCLEQUEUE;

循环队列上的操作

(1)创建循环队列

初始化队列,队头指针和队尾指针=0.

在QueueCycyleControl.h写出方法声明

#include "QueueCycleCs.c"

/*
 创建循环队列
 */
SECYCLEQUEUE initCycleQueue();

在QueueCycyleControl.c中实现此方法

#include "QueueCycleControl.h"
/*
 创建循环队列
 */
SECYCLEQUEUE initCycleQueue(){
  SECYCLEQUEUE Q;
  //队头指针=队尾指针=0;
  Q.front=Q.rear=0;
  return Q;
}

(2)插入

在QueueCycyleControl.h写出方法声明

#include "QueueCycleCs.c"

/*
 循环队列插入
 */
SECYCLEQUEUE inCycleQueue(SECYCLEQUEUE Q,char x);

在QueueCycyleControl.c中实现此方法

#include "QueueCycleControl.h"
SECYCLEQUEUE inCycleQueue(SECYCLEQUEUE Q,CDT x){

  //1.判断循环队列是否已经满了,MOD(队尾指针+1,m)=队头指针
  if((Q.rear+1)%CM==Q.front){
    printf("queue is full!\n");
  }else{
    //2.在队尾插入,计算队尾指针的
    Q.rear=(Q.rear+1)%CM;
    //3.设置插入结点的值数值
    Q.data[Q.rear]=x;
    printf("in Cycle queue Success!\n");
  }
  return Q;
}

(3)删除

在QueueCycyleControl.h写出方法声明

#include "QueueCycleCs.c"
/*
 循环队列删除
 */
SECYCLEQUEUE outCycleQueue(SECYCLEQUEUE Q);
/*
 打印循环队列
 */
void printCycleQueue(SECYCLEQUEUE Q);

在QueueCycyleControl.c中实现此方法

#include "QueueCycleControl.h"
SECYCLEQUEUE outCycleQueue(SECYCLEQUEUE Q){

  //1.判断循环队列是否是空
  if(Q.front==Q.rear){
    printf("Cycle queue is Empty!\n");
  }else{
    //2.删除结点从队头删除,计算队头指针:队头指针=MOD(队头指针+1,m)
    Q.front=(Q.front+1)%CM;
    printf("out cycle queue success!\n");
  }
  return Q;
}

/*
 打印循环队列
 */
void printCycleQueue(SECYCLEQUEUE Q){
  //M=5;
  //1.从队头开始打印数据
  SECYCLEQUEUE temp=Q;
  printf("queue={");
  //2.判断的条件是,队头指针!=队尾指针
  while (temp.front!=temp.rear) {
    temp.front=(temp.front+1)%CM;
    if(temp.front==((Q.front+1)%CM)){
      printf("%c",temp.data[temp.front]);
    }else{
      printf(",%c",temp.data[temp.front]);
    }

  }
  printf("}\n");
}

在main.c中的main方法(int main(int argc, const char * argv[]) {})调用此方法,并且进行判断

#include "QueueCycleControl.h"
int main(int argc, const char * argv[]) {
  //创建循环队列
  SECYCLEQUEUE CQ=initCycleQueue();
  //插入数据5个结点,但是最大是5,一个空闲,最后一个添加不进去,
  CQ=inCycleQueue(CQ, 'a');
  CQ=inCycleQueue(CQ, 'b');
  CQ=inCycleQueue(CQ, 'c');
  CQ=inCycleQueue(CQ, 'd');
  CQ=inCycleQueue(CQ, 'e');
  printCycleQueue(CQ);
  //删除节点-三个结点
  CQ=outCycleQueue(CQ);
  CQ=outCycleQueue(CQ);
  CQ=outCycleQueue(CQ);
  printCycleQueue(CQ);
  //插入-两个结点
  CQ=inCycleQueue(CQ, 'e');
  CQ=inCycleQueue(CQ, 'f');
  printCycleQueue(CQ);
  //删除节点--删除四个结点,现在此时是三个结点,最后一个删除不了
  CQ=outCycleQueue(CQ);
  CQ=outCycleQueue(CQ);
  CQ=outCycleQueue(CQ);
  CQ=outCycleQueue(CQ);
  printCycleQueue(CQ);

  return 0;
}

打印结果:

in Cycle queue Success!
in Cycle queue Success!
in Cycle queue Success!
in Cycle queue Success!
queue is full!
queue={a,b,c,d}
out cycle queue success!
out cycle queue success!
out cycle queue success!
queue={d}
in Cycle queue Success!
in Cycle queue Success!
queue={d,e,f}
out cycle queue success!
out cycle queue success!
out cycle queue success!
Cycle queue is Empty!
queue={}
Program ended with exit code: 0

链队列及其操作

队列的链存储结构

链存储结构存储的队列称为链队列.队头指针指向链队列的头结点,头结点的指针域若为空,则为空队列;若不为空,则为指向队首结点的指针.

链队列设有一个队头指针,其值指向队列的头结点.也是唯一地标示一个链队.设置一个队尾指针方便插入结点.队头指针和队尾指针都是指针型变量.

链队列没有容量的限制,所以在可用的存储空间范围内,一般不会出现上溢问题,也不存在如顺序队列的假溢出问题.

 

在QueueLinkCs.c中定义了结构

#define LDT char
//结点类型
typedef struct llnode{
  LDT data;
  struct llnode *next;
}LINKNODE;

//链队列结构
typedef struct{
  LINKNODE *front,*rear;
}LINKQUEUE;

链队列上的操作

(1)创建链队列

在QueueLinkControl.h写出方法声明

#include <stdio.h>
#include "QueueLinkCs.c"


/*
 创建链队
 */
LINKQUEUE * initLinkQueue(LINKQUEUE *LQ);

在QueueLinkControl.c中实现此方法

#include "QueueLinkControl.h"
#include <stdlib.h>
/*
 创建链队
 */
LINKQUEUE *initLinkQueue(LINKQUEUE *LQ){
  //设置队头指针
  LQ->front=(LINKNODE *)malloc(sizeof(LINKNODE));
  LQ->front->data='#';//设置队头指针,也是头结点的指针域
  LQ->front->next=NULL;
  //初始条件:队头指针和队尾指针一致
  LQ->rear=LQ->front;
  return LQ;
}

(2)插入

在QueueLinkControl.h写出方法声明

/*
 链队插入:队尾
 */
LINKQUEUE * inLinkQueue(LINKQUEUE *LQ,LDT x);

在QueueLinkControl.c中实现此方法

(3)删除

在QueueLinkControl.h写出方法声明

/*
 链队删除:队头
 */
LINKQUEUE *outLinkQueue(LINKQUEUE *LQ);

/*
 打印链表结点
 */
void printLinkQueue(LINKQUEUE *LQ);

在QueueLinkControl.c中实现此方法

#include "QueueLinkControl.h"
#include <stdlib.h>
LINKQUEUE *outLinkQueue(LINKQUEUE *LQ){
  if(LQ==NULL || LQ->rear==LQ->front){
    printf("LQ is empty!\n");
    return LQ;
  }
  //1.获取首结点
  LINKNODE *frontNextNode;
  frontNextNode=LQ->front->next;

  //2.将首节点的next指针域的值存储头结点的next域

  LQ->front->next=frontNextNode->next;

  //3.如果队尾结点等于首节点的next指针域的值,那么表示是空栈,根据空链队列的结构,还需修改队尾指针,使指向头结点.
  if(LQ->rear==frontNextNode){
    LQ->rear=LQ->front;
  }
  //4.释放删除的结点
  free(frontNextNode);

  printf("out link queue success!\n");
  return LQ;
}

/*
 打印链表结点
 */
void printLinkQueue(LINKQUEUE *Q){
  //实例化一个LQ,为了不改变原来链队Q
  LINKQUEUE *LQ;
  LQ=(LINKQUEUE *)malloc(sizeof(LINKQUEUE));
  LQ->front=Q->front;
  LQ->rear=Q->rear;
  printf("queue={");
  //1.判断不是空链表
  if(LQ!=NULL && LQ->rear!=LQ->front){
    int flag=0;

    do{
      //2.输出数据
      if(flag==0){
        printf("%c",LQ->front->data);
        flag=1;
      }else{
        printf(",%c",LQ->front->data);
      }
      //3.链头指针向后移动
      LQ->front=LQ->front->next;

    }while (LQ->front!=LQ->rear) ;

   printf(",%c",LQ->front->data);
  }

  printf("}\n");
}

在main.c中的main方法(int main(int argc, const char * argv[]) {})调用此方法,并且进行判断

#include "QueueLinkControl.h"
int main(int argc, const char * argv[]) {

  //创建链队列
  LINKQUEUE *LQ=(LINKQUEUE *)malloc(sizeof(LINKQUEUE));
  LQ=initLinkQueue(LQ);
  //向链队插入结点
  LQ=inLinkQueue(LQ,'a');
  LQ=inLinkQueue(LQ,'b');
  LQ=inLinkQueue(LQ,'c');
  LQ=inLinkQueue(LQ,'d');
  printLinkQueue(LQ);
  //删除结点--从队头
  LQ=outLinkQueue(LQ);
  LQ=outLinkQueue(LQ);
  printLinkQueue(LQ);
  return 0;
}

打印结果:

in link queue success!
in link queue success!
in link queue success!
in link queue success!
queue={#,a,b,c,d}
out link queue success!
out link queue success!
queue={#,c,d}
Program ended with exit code: 0

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持猪先飞。

[!--infotagslink--]

相关文章

  • C++ STL标准库std::vector的使用详解

    vector是表示可以改变大小的数组的序列容器,本文主要介绍了C++STL标准库std::vector的使用详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2022-03-06
  • C++中取余运算的实现

    这篇文章主要介绍了C++中取余运算的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • 详解C++ string常用截取字符串方法

    这篇文章主要介绍了C++ string常用截取字符串方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • C++调用C#的DLL程序实现方法

    本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
  • C++中四种加密算法之AES源代码

    本篇文章主要介绍了C++中四种加密算法之AES源代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。...2020-04-25
  • C++ 整数拆分方法详解

    整数拆分,指把一个整数分解成若干个整数的和。本文重点给大家介绍C++ 整数拆分方法详解,非常不错,感兴趣的朋友一起学习吧...2020-04-25
  • C++中 Sort函数详细解析

    这篇文章主要介绍了C++中Sort函数详细解析,sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变...2022-08-18
  • C#队列的简单使用

    队列的特性很简答,就是先进先出,一般利用数组来实现,本文就介绍了C#队列的简单使用,文中根据实例编码详细介绍的十分详尽,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2022-03-17
  • C++万能库头文件在vs中的安装步骤(图文)

    这篇文章主要介绍了C++万能库头文件在vs中的安装步骤(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • SpringBoot集成Redis实现消息队列的方法

    这篇文章主要介绍了SpringBoot集成Redis实现消息队列的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-10
  • 详解C++ bitset用法

    这篇文章主要介绍了C++ bitset用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • 浅谈C++中的string 类型占几个字节

    本篇文章小编并不是为大家讲解string类型的用法,而是讲解我个人比较好奇的问题,就是string 类型占几个字节...2020-04-25
  • C++ Eigen库计算矩阵特征值及特征向量

    这篇文章主要为大家详细介绍了C++ Eigen库计算矩阵特征值及特征向量,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-04-25
  • C++ pair的用法实例详解

    这篇文章主要介绍了C++ pair的用法实例详解的相关资料,需要的朋友可以参考下...2020-04-25
  • VSCode C++多文件编译的简单使用方法

    这篇文章主要介绍了VSCode C++多文件编译的简单使用方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-29
  • C++中的循环引用

    虽然C++11引入了智能指针的,但是开发人员在与内存的斗争问题上并没有解放,如果我门实用不当仍然有内存泄漏问题,其中智能指针的循环引用缺陷是最大的问题。下面通过实例代码给大家介绍c++中的循环引用,一起看看吧...2020-04-25
  • C++随机点名生成器实例代码(老师们的福音!)

    这篇文章主要给大家介绍了关于C++随机点名生成器的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • C++如何删除map容器中指定值的元素详解

    map容器是C++ STL中的重要一员,删除map容器中value为指定元素的问题是我们经常与遇到的一个问题,下面这篇文章主要给大家介绍了关于利用C++如何删除map容器中指定值的元素的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。...2020-04-25
  • C++ 约瑟夫环问题案例详解

    这篇文章主要介绍了C++ 约瑟夫环问题案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...2021-08-15
  • C++中cin的用法详细

    这篇文章主要介绍了C++中cin的用法详细,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25