嵌入式学习一阶段——C语言:数据结构(4)

队列

队列是一个先进先出(FIFO:first in first out)的线性表。
它允许在表的一端进行插入操作,而在另外一端进行删除
​
队尾(rear): 允许插入元素的一端
队头(front):允许删除元素的一端
​
“队列的思想”:先进先出  “排队论”
​
队列的实现:
    (1)、队列的数据类型的表述
        顺序结构:顺序队列
            用一组地址连续的空间,来保存队列的每一个元素。 “数组”
        链式结构:
            链表(带头节点的)
    (2)、队列操作
        InitQueue        初始化一个队列
        DestoryQueue     销毁一个队列
        ClearQueue       清空一个队列
        QueueEmpty       判断一个队列是否为空
        QueueLength      返回队列中的元素的个数,也就是队列的长度
        EnQueue          元素入队,把一个元素加入到队中
        DeQueue          出队,把队尾元素给干掉
        GetHead          返回一个队头元素,但是不出队

顺序队列: 用一组地址连续的存储空间来存储队列中的每一个元素。

“循环队列”
​
将顺序队列臆造为一个环状的空间,即把存储队列元素的表从逻辑上视为一个环,称为循环队列。当队头指针Q.front == max_len-1 后,再前进一个位置就自动到0 , 这可以利用除法取余运算符(%)来实现。
    初始的时候: Q->front = Q->rear = 0;
    队头指针进1 : Q->front = (Q->front + 1) % max_len
    队尾指针进1 : Q->rear = (Q->rear + 1) % max_len
    队列的长度 : (Q->rear - Q->front + max_len) % max_len
​
那么,循环队列队空和队满的判断条件是什么???显然,队空的条件是 Q->rear == Q->front
若入队元素的速度快于出队元素的速度,则队尾指针很快就会追上队头指针,如图下:!
此时也可以看出队满的时候,也有Q->rear == Q->front
为了区分是队空还是队满的情况,有如下三种处理方式:
​
1、牺牲一份单元来区分队满还是队空,入队的时候少用一个队列单元,这是一种最普遍的做法,
        约定以“队头指针在队尾指针的下一个位置作为队满的标志”!
​
队满的条件:(Q->rear+1) % man_len == Q->front
        队空的条件:Q->rear == Q->front
        队列中的元素个数:(Q->rear - Q->front + max_len) % max_len
​
2、类型中增设表示元素个数的数据成员。这样,队空的条件为 Q.size == 0;
        队满的条件为Q.size == max_len
​
3、类型中增设一个tag数据成员,以区分是队满还是队空。
        tag 等于0 的时候,若是因为删除导致 Q->front == Q->rear
        tag 等于1 的时候,若是因为插入导致 Q->front == Q->rear

链式队列

带头结点的单链表/带头节点的双链表

#include<stdio.h>
#include<stdlib.h>
#include"listqueue.h"

//@InitQueue 初始化一个链式队列
//@return 返回一个链式队列的队列
listQueue* InitQueue(void)
{
    listQueue* l=(listQueue*)malloc(sizeof(listQueue));
    l->rear=NULL;
    l->front=NULL;
    l->nodenum=0;
    return l;
}

//@EnQueue:入队
//@listQueue* l:队列的头节点
//@QElemtype x:入队的元素
int EnQueue(listQueue* l,QElemtype x)
{
    if(l==NULL)
    return 0;//失败
    l->nodenum+=1;
    Qnode* p=malloc(sizeof(Qnode));
    p->data=x;
    p->next=NULL;
    if(l->front==NULL)
    {
        l->front=p;
        l->rear=p;      
    }
    else
    {
        l->rear->next=p;
        l->rear=p;
    }
    return 1;//入队成功
}

/*
@DeQueue:出队
@listQueue* s:队头
@QElemtype* e:要出队的元素的存放地址
*/
int DeQueue(listQueue* l,QElemtype *e)
{
    if(l==NULL||l->nodenum==0)
    {
        return 0;//出栈失败
    } 
    *e=l->front->data; 
    Qnode* px=l->front;  
    l->front=px->next;
    px->next=NULL;
    free(px);
    if(l->front==NULL)
    {
        l->rear=NULL;
    }    
    l->nodenum-=1;
    return 1;
}

//返回一个队头元素,但是不出队
int GetHead(listQueue* l,QElemtype* e)
{
    if(l==NULL||l->nodenum==0)
    return 0;//队列为空
    *e=l->front->data;
    return 1;//队列不为空
}


//@ClearQueue 清空一个链式队列
void ClearQueue(listQueue* l)
{
    if(l==NULL||l->front==NULL)
    return;
   Qnode* px=l->front;
   while (px!=NULL)
   {
        l->front=px->next;
        px->next=NULL;
        free(px);
        px=l->front;
        
   }
    l->rear=NULL;
    l->nodenum=0;
   
}
//DestoryQueue 销毁一个链式队列
void DestoryQueue(listQueue* l)
{
    if(l==NULL)
    return;
    ClearQueue(l);
    free(l);
}

//判断一个队列是否为空
int QueueEmpty(listQueue* l)
{
    if(l==NULL||l->nodenum==0)
    return 0;//队列为空
    else
    return 1;//栈=队列不为空
}
//返回一个队列的元素个数
int Queuelength(listQueue* l)
{
    if(l==NULL||l->nodenum==0)
    return 0;
    return l->nodenum;//队列的元素个数
}

作业

利用两个栈S1 和 S2 来模拟一个队列,已知栈的四个运算定义如下:
    Push(S,x);          //元素x入栈
    Pop(S,&x);          //s出栈并将出栈元素赋值给x
    StackEmpty(s);      //判断栈是否为空
    StackOverflow(s);   //判断栈是否满了
    如何利用栈的运算来实现这个队列的三个运算
    EnQueue
    DeQuene
    QueneEmpty
    这个三个运算的形参由用户自己定义
​
    
    基本思想:
        利用两个栈s1ands2来模拟一个队列,当需要想队列中插入一个元素的时候,用s1来存放已输入的元素,即s1执行入栈的操作。当需要出队的时候,则对s2执行出栈的操作。
        由于从栈中取出元素的顺序是原顺序的逆序,所以必须先将s1的所有元素,全部出栈并且入栈到s2中,再从s2中执行出栈操作,就完成了出队操作,
        而再执行此操作的时候你要判断s2是否为空,否则就会导致顺序混乱。
    总结一下:
        1)、对s1的出栈操作 用作 出队,若s2为空,则先将s1的所有的元素送入s2
        2)、对s1的入栈操作 用作 入队,若s1满了,必须先保证s2为空,才能将s1中的元素全部插入s2
        入队的算法:
            int EnQueue(seqstack *S1,seqstack *S2,int e)
        出队的算法:
            int DeQueue(seqstack *S1,seqstack *S2,int *e)
        判断队列算法为空的代码:
            int QueueEmpty(seqstack *S1,seqstack *S2)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值