数据结构与算法笔记(七):队列

本文详细介绍了数据结构中的队列,包括队列的定义、设计、初始化、基本操作如入队、出队和遍历。此外,还重点探讨了循环队列的概念,解释了如何避免假溢出,并给出了使用余数法优化循环队列的入队和判断队列满的方法。循环队列通过巧妙地利用空间,提高了队列操作的效率。
摘要由CSDN通过智能技术生成

一、定义

  1. 队列(queue)是限定在表的一端进行插入,表的另一端进行删除的数据结构。先进先出

二、队列设计

//结点定义
typedef struct node{
    int data;
    struct node *next;
}node;

//队列定义,队首指针和队尾指针
typedef struct queue{
    node *front;    //头指针
    node *rear;     //尾指针
}queue;

三、初始化

初始化将头尾两个结点指向空,表示是一个空队列

//初始化结点
node *init_node(){
    node *n=(node*)malloc(sizeof(node));
    if(n==NULL){    //建立失败,退出
        exit(0);
    }
    return n;
}
  
//初始化队列
queue *init_queue(){
    queue *q=(queue*)malloc(sizeof(queue));
    if(q==NULL){    //建立失败,退出
        exit(0);
    }
    //头尾结点均赋值NULL
    q->front=NULL;  
    q->rear=NULL;
    return q;
}

四、基本操作

  1. 判空: (直接就是判断队列头指针是否是空值即可)
    q->front==NULL;
  2. 入队
    需要特判一下队列是否为空。
    如果队列为空的话,需要将头指针和尾指针一同指向第一个结点,即front=n;rear=n。
    不为空的时候,我们只需要将尾结点向后移动,通过不断移动next指针指向新的结点构成队列即可。
//入队操作
void push(queue *q,int data){
    node *n =init_node();
    n->data=data;
    n->next=NULL;   //采用尾插入法
    //if(q->rear==NULL){     //使用此方法也可以
    if(empty(q)){
        q->front=n;
        q->rear=n;
    }else{
        q->rear->next=n;    //n成为当前尾结点的下一结点
        q->rear=n;  //让尾指针指向n
    }
}
  1. 出队
    队列为空,直接结束;
    在队列不为空的情况下, 将队列的头指针指向头指针当前指向的下一个元素并释放掉当前元素;
    队列只有一个元素了(即头尾指针均指向了同一个结点),直接将头尾两指针制空(NULL)并释放这一个结点。
void pop(queue *q){
    node *n=q->front;
    if(empty(q)){
        return ;    //此时队列为空,直接返回函数结束
    }
    if(q->front==q->rear){
        q->front=NULL;  //只有一个元素时直接将两端指向制空即可
        q->rear=NULL;
        free(n);        //记得归还内存空间
    }else{
        q->front=q->front->next;
        free(n);
    }
}
  1. 遍历
    队列不为空的情况下,通过结点的next指向依次遍历并输出元素
printf("%d\t",n->data);
n=n->next;

五、循环队列

"假溢出": 队列用的存储区还没有满,但队列却发生了溢出。
(出队操作头指针后移,入队尾指针后移,头部存储空置)

优化给定队列的大小范围,在原有队列的基础上,只要队列的后方满了,就从这个队列的前面开始进行插入,以达到重复利用空间的效果。

由于循环队列的设计思维更像一个环,因此常使用一个环图来表示,但注意其不是一个真正的环,循环队列依旧是单线性的。

  1. 数据结构设计
#define maxsize 10      //表示循环队列的最大容量
  
//循环队列的结构设计
typedef struct cir_queue{
    int data[maxsize];
    int rear;
    int front;
}cir_queue;
  1. 初始化
//初始化
cir_queue *init(){
    cir_queue *q = (cir_queue*)malloc(sizeof(cir_queue));
    if(q==NULL){
        exit(0);   //申请内存失败,退出程序
    }
    q->front=0;
    q->rear=0;
    return q;
}
  1. 入队

这里推荐使用余数法,即无论如何求余都是在这片空间内进行操作。
新入队位置:(q->rear+1)%maxsize

队列已满的判断:当我们rear指针的下一个位置就是front的位置的时候,即已满。

#define maxsize 10      //表示循环队列的最大容量

//入队操作push
void push(cir_queue *q,int data){
    if((q->rear+1)%maxsize==q->front){
        printf("溢出,无法入队\n");
        return;
    }else{
        q->rear=(q->rear+1)%maxsize;
        q->data[q->rear]=data;
    }
}
  1. 出队

将front指针后移一位

//出队操作pop
void pop(cir_queue *q){
    if(q->rear==q->front){
        printf("队列为空,无法出队\n");
        return;
    }else{
        q->data[q->front]=0;
        q->front=(q->front+1)%maxsize;
    }
}
  1. 遍历
    借助一个临时变量储存位置front的位置信息,利用i逐步向后移动,直到i到达了rear的位置,遍历结束。
//遍历队列
void print(cir_queue *q){
    int i=q->front;
    while(i!=q->rear){
        i=(i+1)%maxsize;
        printf("%d\t",q->data[i]);   
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值