队列操作--附两个队列实现栈操作

// 队列---------------------------------------------------------------------------------
// 只允许一端插入数据,另一端删除数据的特殊线性表
// 先进先出规则,FIFO
// 入队列:进行插入操作的称为队尾
// 出队列:进行删除操作的称为队头
// 
// 数组队列:出栈需要遍历挪动数据,不推荐
// 链式队列:
//

typedef int QDatetype;

//创建一个结点
typedef struct QuequeNode
{
    struct QuequeNode* next;
    QDatetype val;
}QuequeNode;
//定义有头结点,有尾结点的结构体
typedef struct Queque
{
    QuequeNode* head;
    QuequeNode* tail;
}Queque;

//初始化
void QuequeInit(Queque* pq)
{
    assert(pq);
    pq->head = NULL;
    pq->tail = NULL;
}
//销毁
void QuequeDestroy(Queque* pq)
{
    assert(pq);
    //从队头开始销毁,直到队尾遇到NULL
    QuequeNode* cur = pq->head;
    while (cur)
    {
        //记录下一个结点的位置
        QuequeNode* next = cur->next;
        //销毁当前结点
        free(cur);
        //cur往后迭代遍历
        cur = next;
    }
    //队头队尾置空
    pq->head = pq->tail = NULL;

}
//队尾入队列-插入
void QuequePush(Queque* pq, QDatetype x)
{
    assert(pq);
    //创建一个新结点,将x数据存入
    QuequeNode* newNode = (QuequeNode*)malloc(sizeof(QuequeNode));
    newNode->val = x;
    newNode->next = NULL;
    //队列内数据结点为空时,将队头队尾指向newNode
    if (pq->head == NULL)
    {
        pq->head = pq->tail = newNode;
    }
    else
    {
        //将队尾的结点链接上newNode
        pq->tail->next = newNode;
        //将队尾指向newNode
        pq->tail = newNode;
    }
}
//队头出队列-删除
void QuequePop(Queque* pq)
{
    assert(pq);
    //断言QuequeEmpty(队列是否为空)的真假,非真则报错,非假继续
    assert(!QuequeEmpty(pq));
    //记录队头结点的下一个结点
    QuequeNode* next = pq->head->next;
    //释放队头结点空间
    free(pq->head);
    //头结点指向next
    pq->head = next;
    //遇到队尾,释放队尾结点,并将队尾置空,避免tail称为野指针
    if (!next)//pq->head == NULL
    {
        pq->tail = NULL;
    }
}
//取队头数据
QDatetype QuequeFront(Queque* pq)
{
    assert(pq);
    //断言QuequeEmpty(队列是否为空)的真假,非真则报错,非假继续
    assert(!QuequeEmpty(pq));
    return pq->head->val;
}
//取队尾数据
QDatetype QuequeBack(Queque* pq)
{
    assert(pq);
    //断言QuequeEmpty(队列是否为空)的真假,非真则报错,非假继续
    assert(!QuequeEmpty);
    return pq->tail->val;
}
//队列长度
size_t QuequeSize(Queque* pq)
{
    assert(pq);
    size_t count = 0;//计数
    //从队头开始计数,遇到NULL结束
    QuequeNode* cur = pq->head;
    while (cur)
    {
        ++count;
        //cur往后迭代
        cur = cur->next;
    }
    //返回计数
    return count;
}
//判断是否为空
bool QuequeEmpty(Queque* pq)
{
    assert(pq);
    //不为空返回假(即返回判断不成立),为空返回真(队列为空)
    return pq->head == NULL;
}

 

//两个队列实现栈----------------
//创建两个队列
typedef struct 
{
    Queque q1;
    Queque q2;
}Mystack;
//开辟一个栈,包含两个队列,调用队列函数接口
Mystack* MystackCreate()
{
    Mystack* st = (Mystack*)malloc(sizeof(Mystack));
    //调用队列初始化函数
    QuequeInit(&st->q1);
    QuequeInit(&st->q2);

    return st;
}
//压栈操作
void MystackPush(Mystack* obj, int x)
{
    //如果q1不为空,调用入队列函数
    if (!QuequeEmpty(&obj->q1))
    {
        QuequePush(&obj->q1, x);
    }
    else//否则入队列q2
    {
        QuequePush(&obj->q2, x);
    }
}
//出栈操作
int MystackPop(Mystack* obj, int x)
{
    //先找出空队列
    //假设q1为空,q2不为空
    Queque* emptyQ = &obj->q1;
    Queque* noneEmptyQ = &obj->q2;
    //纠错,如果q1不为空,则q2为空
    if (!QuequeEmpty(&obj->q1))
    {
        Queque* emptyQ = &obj->q2;
        Queque* noneEmptyQ = &obj->q1;
    }
    
    while(QuequeSize(noneEmptyQ)>1)//出队列直到留下最后一个数据
    {
        //取队头数据操作入空队列
        QuequePush(emptyQ, QuequeFront(noneEmptyQ));
        //队头出列
        QuequePop(noneEmptyQ);
    }
    //取出最后一个数据
    int top = QuequeFront(noneEmptyQ);
    //出列,非空队列为空
    QuequePop(noneEmptyQ);
    //返回top实现后进先出
}
//取栈顶数据
int MystackTop(Mystack* obj)
{
    //如果q1不为空
    if (!QuequeEmpty(&obj->q1))
    {
        return QuequeBack(&obj->q1);//返回q1的队尾
    }
    else
    {
        return QuequeBack(&obj->q2);//返回q2的队尾
    }
}
//判断是否为空
bool MystackEmpty(Mystack* obj)
{
    //两个队列都为空,则为空
    return QuequeEmpty(&obj->q1) && QuequeEmpty(&obj->q2);
}
//销毁
void MystackFree(Mystack* obj)
{
    //先销毁两个队列
    QuequeDestroy(&obj->q1);
    QuequeDestroy(&obj->q2);
    //再销毁obj
    free(obj);
}

  • 24
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值