循环队列+卡片游戏

                        
    假设有这样一道题目,桌面上有一堆牌(n),从上往下依次记录为1~n,每次从牌顶取一次放出来,然后从剩下的牌的牌顶中取一张牌拿出来放在牌的末尾,问放出去的牌的顺序是?  
    
    这个题目显然就是用队列的思想来解决的一个问题,首先依次从队列中取出2个元素,把第一个元素从队列中放出去,第二个元素放在队列的末尾,依次这样循环下去,直到队列中没有元素为止,所以首先想到的代码如下:

 
  #include<stdio.h>
    #define max 100;
    int queue[max];
    int main(void){
        int num,front,rear;
        scanf("%d",&num);
        for(int i=0;i<num;i++){
            queue[i] = i + 1; //向队列中添加元素
        }
        front = 0;   //front指向第一个元素
        rear = n;     //rear指向最后一个元素的下一个元素
        while(front < rear){
            printf("%d",queue[front++]); //输出第一个元素,并且让当前的front+1
            queue[rear++] = queue[front++]; //把当前的队列元素放在队尾,并且front和rear的值都+1
        }    
        return 0;
    }



    如果把这段代码拿进去做测试的话,可以看到我们希望得到的结果,但是程序有一定的问题,那就是当输入的值比较大的时候,程序可能访问非法内存。很显然的是最后的rear不会等于n,如果输入的数字比较大的时候,我们必须开辟大量的内存才能满足程序的合法性,那么有没办法,让空间被重复利用呢?解下来就是循环队列上场了

#include <stdio.h>
#include <string.h>
#define max 100

typedef struct NODE{
    int data[max];
    int rear;
    int front;
}queue,*QUEUE;

void init(queue *q){
    q->rear=0;        //rear指向第一个元素,front指向最后一个元素的下一个元素,初始化的时候让他们都设置为0
    q->front = 0;
}

int isEmpty(queue *q){
    //当rear和front相等的时候,说明队列已经为空了
    if(q->rear == q->front){
        return 1;
    }
    return 0;
}

int isFull(queue *q){
    //rear+1的值对数组的最大元素取余与front的值相等的时候,说明队列已经满了
    if((q->rear+1)%max == q->front){
        return 1;
    }
    return 0;
}

void inQueue(queue *q,int num){
    if(isFull(q)){
        return;
    }else{
        //入队后,我们让当前的rear值走一步,因为是循环队列,所以完全有可能最后rear从数组的末尾走到数组的开始,所以对(rear+1)%max;
        q->data[q->rear]= num;
        q->rear = (q->rear+1)%max;
    }
}


void outQueue(queue *q,int *number){
    if(isEmpty(q)){
        return;
    }else{
        *number = q->data[q->front];
        //出队是让当前面的front进一,这里的意思给入队时候的rear差不多
        q->front = (q->front+1)%max;
    }
}

int main(void){
    int i,n;
    scanf("%d",&n);
    int num1,num2;
    queue q;
    init(&q);    //初始化队列
    for(i=0;i<n;i++){
        inQueue(&q,i+1);  //向队列中添加元素
    }
    while(q.front!=q.rear){        //当front不等于rear的时候,说明队列中还有元素
        outQueue(&q,&num1);    //出队,并且记录当前的值
        printf("%d",num1);    //打印出当前的值
        if(isEmpty(&q)){        //注意:因为我们用循环队列的话,这里很有可能出现队列中只有一个元素的情况,这时上面的代码已经把这个元素给出队了,所以我们这里要判断如果没有队列的时候就把这个程序给终止了
            break;
        }
        outQueue(&q,&num2);    //当前元素出队
        inQueue(&q,num2);        //把上面出队的元素放在队尾
        
    }
    return 0;
}


    
    这段代码比上面的好处就是队列中的空间可以反复利用,不需要浪费更多的内存空间。循环队列的一个主要思想就是用一个front指向队列的首元素,rear指向队尾元素的下一个元素,然后不停的这样周期下去。
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值