当前位置: 首页 > 编程笔记 >

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

袁琪
2023-03-14
本文向大家介绍在编程语言中怎样定义队列及其使用(C++),包括了在编程语言中怎样定义队列及其使用(C++)的使用技巧和注意事项,需要的朋友参考一下

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

队列的定义

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

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。

 类似资料:
  • 问题内容: 我正在学习Go语言,碰巧看到这种类型的变量声明: 但是它说Go具有静态变量。即变量应该以这种方式定义 那么这两种方法有什么区别?在第一个中,我们不需要指示数据类型。为什么会这样呢? 问题答案: 第一个称为短变量声明。这是带有初始值设定项表达式但没有类型的常规变量声明的简写: 您没有指定的类型,但是会根据某些规则指定类型。它的类型将被自动推断。在这种情况下,它将是类型,因为初始化器表达式

  • 为什么这个数组是一个对象类型,因为我们没有在这里使用new关键字。请解释一下。

  • 主要内容:godoc 工具注释在程序中的作用是对程序进行注解和说明,便于对源码的阅读。编译系统在对源代码进行编译时会自动忽略注释的部分,因此注释对于程序的功能实现不起任何作用。在源码中适当地添加注释,能够提高源码的可读性。 Go语言的注释主要分成两类,分别是单行注释和多行注释。 单行注释简称行注释,是最常见的注释形式,可以在任何地方使用以开头的单行注释; 多行注释简称块注释,以开头,并以结尾,且不可以嵌套使用,多行注释一般

  • 本文向大家介绍C语言中函数的声明、定义及使用的入门教程,包括了C语言中函数的声明、定义及使用的入门教程的使用技巧和注意事项,需要的朋友参考一下 对函数的“定义”和“声明”不是一回事。函数的定义是指对函数功能的确立,包括指定函数名,函数值类型、形参及其类型以及函数体等,它是一个完整的、独立的函数单位。而函数的声明的作用则是把函数的名字,函数类型以及形参的类型、个数和顺序通知编译系统,以便在调用该函数

  • 为了描述Gradle构建脚本,我们可以通过< code>build.gradle.kts文件使用Kotlin。在< code>dependencies和build 部分全局定义要使用的Kotlin版本是一个常见的问题(在给定的情况下使用不同的版本是相当罕见的)。 请考虑以下代码 (Gradle 4.3.1): 如您所见,kotlin(在本例中为1.2.30)定义了两次:和,它们通常没有区别。由于D