使用队列实现栈和使用栈实现队列

在数据结构中,栈和队列是两种非常基础且重要的数据结构。栈遵循后进先出(LIFO)的原则,而队列遵循先进先出(FIFO)的原则。本文将介绍如何使用队列来实现栈,以及如何使用栈来实现队列,并给出相应的代码实现。

使用队列实现栈

相关OJ题 225. 用队列实现栈 - 力扣(LeetCode)

思路

为了使用队列实现栈,我们可以使用两个队列 q1 和 q2。在入栈操作时,我们将元素插入到非空的队列中;在出栈操作时,我们将非空队列中的元素除了最后一个元素外,全部移动到另一个空队列中,然后弹出最后一个元素。

代码实现

以下是使用队列实现栈的代码:

#include 
#include 
#include 
#include 

typedef int QDataType;

typedef struct QueueNode
{
    struct QueueNode* next;
    QDataType val;
}QNode;

typedef struct Queue
{
    QNode* phead;
    QNode* ptail;
    int size;
}Queue;

// 初始化与销毁队列
void QueueInit(Queue* pq);
void QueueDestory(Queue* pq);

// 队尾插入
void QueuePush(Queue* pq, QDataType x);
// 队头删除
void QueuePop(Queue* pq);

// 取队头和队尾的数据
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);

// 队列大小
int QueueSize(Queue* pq);

// 判空
bool QueueEmpty(Queue* pq);

// 初始化与销毁队列
void QueueInit(Queue* pq)
{
    assert(pq);
    pq->phead = NULL;
    pq->ptail = NULL;
    pq->size = 0;
}

void QueueDestory(Queue* pq)
{
    assert(pq);
    QNode* cur = pq->phead;
    while(cur)
    {
        QNode* next = cur->next;
        free(cur);
        cur = next;
    }
    pq->phead = pq->ptail = NULL;
    pq->size = 0;
}

// 队尾插入
void QueuePush(Queue* pq, QDataType x)
{
    assert(pq);
    QNode* newnode = (QNode*)malloc(sizeof(QNode));
    if(newnode == NULL)
    {
        perror("malloc fail!");
        return;
    }
    newnode->next = NULL;
    newnode->val = x;

    if(pq->ptail == NULL)
    {
        pq->phead = pq->ptail = newnode;
    }
    else
    {
        pq->ptail->next = newnode;
        pq->ptail = newnode;
    }
    pq->size++;
}

// 队头删除
void QueuePop(Queue* pq)
{
    assert(pq);
    assert(pq->size != 0);

    // 一个节点
    if(pq->phead->next == NULL)
    {
        free(pq->phead);
        pq->phead = pq->ptail = NULL;
    }
    else // 多个节点
    {
        QNode* next =  pq->phead->next;
        free(pq->phead);
        pq->phead = next;
    }
    pq->size--;
}

// 取队头和队尾的数据
QDataType QueueFront(Queue* pq)
{
    assert(pq);
    assert(pq->phead);
    return pq->phead->val;
}

QDataType QueueBack(Queue* pq)
{
    assert(pq);
    assert(pq->ptail);
    return pq->ptail->val;
}

// 队列大小
int QueueSize(Queue* pq)
{
    assert(pq);
    return pq->size;
}

// 判空
bool QueueEmpty(Queue* pq)
{
    assert(pq);
    return pq->size == 0;
}

typedef struct 
{
    Queue q1;
    Queue q2;    
} MyStack;

MyStack* myStackCreate() 
{
    MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
    QueueInit(&pst->q1);
    QueueInit(&pst->q2);
    return pst;
}

void myStackPush(MyStack* obj, int x) 
{
    if(!QueueEmpty(&obj->q1))
    {
        QueuePush(&obj->q1, x);
    }
    else
    {
        QueuePush(&obj->q2, x);
    }
}

int myStackPop(MyStack* obj) 
{
    Queue* Empty = &obj->q1;
    Queue* nonEmpty = &obj->q2;
    if(!QueueEmpty(&obj->q1))
    {
        Empty = &obj->q2;
        nonEmpty = &obj->q1;
    }
    while(QueueSize(nonEmpty)>1)
    {
        QueuePush(Empty, QueueFront(nonEmpty));
        QueuePop(nonEmpty);
    }
    int top = QueueFront(nonEmpty);
    QueuePop(nonEmpty);
    return top;
}

int myStackTop(MyStack* obj) 
{
    if(!QueueEmpty(&obj->q1))
    {
        return QueueBack(&obj->q1);
    }
    else
    {
        return QueueBack(&obj->q2);
    }
}

bool myStackEmpty(MyStack* obj) 
{
    return (QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2));
}

void myStackFree(MyStack* obj) 
{
    QueueDestory(&obj->q1);
    QueueDestory(&obj->q2);
    free(obj);
    obj = NULL;
}

复杂度分析

  • 入栈操作:时间复杂度为 O(1),因为只需要将元素插入到队列的尾部。
  • 出栈操作:时间复杂度为 O(n),因为需要将 n−1 个元素从一个队列移动到另一个队列。

使用栈实现队列

相关OJ题 232. 用栈实现队列 - 力扣(LeetCode)

思路

为了使用栈实现队列,我们可以使用两个栈 s1 和 s2。在入队操作时,我们将元素压入栈 s1;在出队操作时,如果栈 s2 为空,我们将栈 s1 中的元素全部弹出并压入栈 s2,然后从栈 s2 中弹出元素。

代码实现

以下是使用栈实现队列的代码:

#include 
#include 
#include 
#include 

typedef int STDataType;

typedef struct Stack
{
    STDataType* a;
    int top;
    int capacity;
}ST;

// 初始化与销毁
void STInit(ST* pst);
void STDestory(ST* pst);

// 入栈 出栈
void STPush(ST* pst, STDataType x);
void STPop(ST* pst);

// 取栈顶数据
STDataType STTop(ST* pst);

// 判空
bool STEmpty(ST* pst);

// 获取数据的个数
int STSize(ST* pst);

// 初始化与销毁
void STInit(ST* pst)
{
    assert(pst);
    pst->a = NULL;
    pst->top = 0;
    pst->capacity = 0;
}

void STDestory(ST* pst)
{
    assert(pst);
    free(pst->a);
    pst->a = NULL;
    pst->top = pst->capacity = 0;
}

// 入栈 出栈
void STPush(ST* pst, STDataType x)
{
    assert(pst);
    // 扩容
    if(pst->top == pst->capacity)
    {
        int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
        STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity* sizeof(STDataType));
        if(tmp == NULL)
        {
            perror("realloc fail");
            exit(1);
        }
        pst->a = tmp;
        pst->capacity = newcapacity;
    }    

    // 入栈
    pst->a[pst->top] = x;
    pst->top++;
}

void STPop(ST* pst)
{
    assert(pst);
    assert(pst->top > 0);
    pst->top--;
}

// 取栈顶数据
STDataType STTop(ST* pst)
{
    assert(pst);
    assert(pst->top > 0);
    return pst->a[pst->top - 1];
}

// 判空
bool STEmpty(ST* pst)
{
    assert(pst);
    return pst->top == 0;
}

// 获取数据的个数
int STSize(ST* pst)
{
    assert(pst);
    return pst->top;
}

typedef struct 
{
    ST s1;
    ST s2;    
} MyQueue;

MyQueue* myQueueCreate() 
{
    MyQueue* pst = (MyQueue*)malloc(sizeof(MyQueue));
    STInit(&pst->s1);
    STInit(&pst->s2);
    return pst;    
}

void myQueuePush(MyQueue* obj, int x) 
{
    if(!STEmpty(&obj->s1))
    {
        STPush(&obj->s1, x);
    }    
    else
    {
        STPush(&obj->s2, x);
    }
}

int myQueuePop(MyQueue* obj) 
{
    ST* Empty = &obj->s1;
    ST* nonEmpty = &obj->s2;
    if(!STEmpty(&obj->s1))
    {
        Empty = &obj->s2;
        nonEmpty = &obj->s1;
    }
    while(STSize(nonEmpty) > 1)
    {
        STPush(Empty, STTop(nonEmpty));
        STPop(nonEmpty);
    }
    int top = STTop(nonEmpty);
    STPop(nonEmpty);
    while(!STEmpty(Empty))
    {
        STPush(nonEmpty, STTop(Empty));
        STPop(Empty);
    }
    return top;
}

int myQueuePeek(MyQueue* obj) 
{
    ST* Empty = &obj->s1;
    ST* nonEmpty = &obj->s2;
    if(!STEmpty(&obj->s1))
    {
        Empty = &obj->s2;
        nonEmpty = &obj->s1;
    }
    while(STSize(nonEmpty) > 1)
    {
        STPush(Empty, STTop(nonEmpty));
        STPop(nonEmpty);
    }
    int top = STTop(nonEmpty);
    STPush(Empty, STTop(nonEmpty));
    STPop(nonEmpty);
    while(!STEmpty(Empty))
    {
        STPush(nonEmpty, STTop(Empty));
        STPop(Empty);
    }
    return top;
}

bool myQueueEmpty(MyQueue* obj) 
{
    return (STEmpty(&obj->s1) && (STEmpty(&obj->s2)));    
}

void myQueueFree(MyQueue* obj) 
{
    STDestory(&obj->s1);
    STDestory(&obj->s2);
    free(obj);
    obj = NULL;   
}

复杂度分析

  • 入队操作:时间复杂度为 O(1),因为只需要将元素压入栈 s1
  • 出队操作:平均时间复杂度为 O(1),因为每个元素最多只会从栈 s1 移动到栈 s2 一次。

总结

通过使用队列实现栈和使用栈实现队列,我们可以更好地理解栈和队列的特性,以及它们之间的转换关系。在实际应用中,我们可以根据具体的需求选择合适的数据结构来实现相应的功能。

你可能感兴趣的:(开发语言,c语言,数据结构,栈和队列)