三.栈和队列

目录

(一)栈

(1)概念与结构

(2)栈的实现

①初始化栈等

②入栈/出栈

函数STPush

函数STPop

③获取栈顶元素

④获取栈元素数量

⑤判断栈是否为空

(二)队列

(1)概念与结构

(2)队列的实现

①初始化队列等

②入队/出队

函数QueuePush

函数QueuePop

③取队头/队尾元素

函数QueueFront

函数QueueBack

④队列判空

函数QueueEmpty

⑤队列有效元素

函数QueueSize

(三)栈和队列算法题

(1)有效的括号

(2)用队列实现栈

①初始化栈

②入栈

③出栈

函数OneQueuePop

函数myStackPop

④取栈顶元素

⑤判断栈是否为空

⑥栈的销毁

(3)用栈实现队列

①初始化

②入队

③出队

④获取栈顶元素

⑤判断栈是否为空

⑥销毁栈


(一)栈

(1)概念与结构

  1. 特殊的线性表,只允许在固定的一端插入和删除。

  2. 数据插入删除的一端为栈顶,另一端为栈底。

  3. 栈中元素遵循 先进后出(Last In First Out) 原则。

  4. ++压栈++:或称 进栈/入栈,插入数据。

  5. ++出栈++:删除数据。

  6. 底层结构:推荐数组。

(2)栈的实现

①初始化栈等

cpp 复制代码
void STInit(ST* ps) 
{
    ps->a = (STDataType*)malloc(10 * sizeof(STDataType));
    ps->top = 0;
    ps->capacity = 10;
}

②入栈/出栈

函数STPush
cpp 复制代码
void STPush(ST* ps, STDataType x) 
{
    checkbefore(ps);
    if (ps->top == 10)
    {
        printf("full stack,operation invalid\n");
        return;
    }
    ps->a[ps->top++] = x;
}
函数STPop
cpp 复制代码
void STPop(ST* ps) 
{
	checkbefore(ps);
	if (STEmpty(ps))
	{
		printf("empty stack,the operation is invalid\n");
		return;
	}
	ps->top--;
}

③获取栈顶元素

cpp 复制代码
STDataType STTop(ST* ps) 
{
    if (STEmpty(ps))
    {
        printf("empty stack,the operation is invalid\n");
        return;
    }
    return ps->a[ps->top - 1];
}

④获取栈元素数量

cpp 复制代码
int STSize(ST* ps) 
{
    checkbefore(ps);
    if (STEmpty(ps))
    {
        return 0;
    }
    return ps->top;
}

⑤判断栈是否为空

cpp 复制代码
bool STEmpty(ST* ps) 
{
    checkbefore(ps);
    if (ps->top == 0) 
    {
        return true;
    }
    return false;
}

(二)队列

(1)概念与结构

  • 特殊线性表。

  • 只允许在一端插入,另一端删除数据。

  • 遵循 先进先出(First In First Out)原则。

  • 底层结构:推荐链表。

(2)队列的实现

①初始化队列等

cpp 复制代码
void QueueInit(Queue* pq) 
{
    assert(pq);
    pq->phead = NULL;
    pq->ptail = NULL;
    pq->size = 0;
}

②入队/出队

函数QueuePush
cpp 复制代码
void QueuePush(Queue* pq, QDataType x) 
{
    checkBefore(pq);
    QNode* newNode = buyNode(x);
    if (pq->size == 0) 
    {
        pq->phead = newNode;
        pq->ptail = newNode;
    }
    else 
    {
        pq->ptail->next = newNode;
        pq->ptail = newNode;
    }
    pq->size++;
}
函数QueuePop
cpp 复制代码
void QueuePop(Queue* pq) 
{
    assert(!QueueEmpty(pq));
    QNode* phead = pq->phead;
    pq->phead = phead->next;
    if (pq->ptail == phead) 
    {
        pq->ptail = NULL;
    }
    free(phead);
    phead = NULL;
    pq->size--;
}

③取队头/队尾元素

函数QueueFront
cpp 复制代码
QDataType QueueFront(Queue* pq) 
{
    if (QueueEmpty(pq))
    {
        perror("the queue is empty\n");
        exit(1);
    }
    return pq->phead->val;
}
函数QueueBack
cpp 复制代码
QDataType QueueBack(Queue* pq) 
{
    if (QueueEmpty(pq))
    {
        perror("the queue is empty\n");
        exit(1);
    }
    return pq->ptail->val;
}

④队列判空

函数QueueEmpty
cpp 复制代码
bool QueueEmpty(Queue* pq)
{
    checkBefore(pq);
    if (pq->size == 0)
    {
        return true;
    }
    return false;
}

⑤队列有效元素

函数QueueSize
cpp 复制代码
int QueueSize(Queue* pq) 
{
    checkBefore(pq);
    return pq->size;    
}

(三)栈和队列算法题

(1)有效的括号

20. 有效的括号 - 力扣(LeetCode)

栈的结构上面已经实现过,以下是函数isValid的实现:

cpp 复制代码
bool isValid(char* s) {
    ST st;
    STInit(&st);
    char* pc = s;
    while(*pc != '\0')
    {
        if(*pc == '('||*pc == '['||*pc == '{')
        {
            STPush(&st,*pc);
        }else
        {
            if(STEmpty(&st))
            {
                STDestroy(&st);
                return false;
            }
            char topVal = STTop(&st);
            if((*pc == ')' && topVal != '(')
                || (*pc == ']' && topVal != '[')
                || (*pc == '}' && topVal != '{'))
            {
                STDestroy(&st);
                return false;
            }
            STPop(&st);
        }
        pc++;
    }
    bool ret = STEmpty(&st);
    STDestroy(&st);
    return ret;
}

(2)用队列实现栈

225. 用队列实现栈 - 力扣(LeetCode)

队列的结构我们已经实现过,以下是新的栈结构设计:

cpp 复制代码
typedef struct {
    Queue A;
    Queue B;
} MyStack;

①初始化栈

cpp 复制代码
MyStack* myStackCreate() {
    MyStack* ps = (MyStack*)malloc(sizeof(MyStack));
    QueueInit(&ps->A);
    QueueInit(&ps->B);
    return ps;
}

②入栈

cpp 复制代码
void myStackPush(MyStack* obj, int x) {
    if (QueueEmpty(&obj->A))
    {
        QueuePush(&obj->B, x);
    }
    else
    {
        QueuePush(&obj->A, x);
    }
}

③出栈

函数OneQueuePop
cpp 复制代码
int OneQueuePop(Queue** A, Queue** B)
{
    while (QueueSize(*B) != 1)
    {
        QueuePush(*A, QueueFront(*B));
        QueuePop(*B);
    }
    int val = QueueFront(*B);
    QueuePop(*B);
    return val;
}

这里第一次写的时候没用二级指针传址,报错了。

函数myStackPop
cpp 复制代码
int myStackPop(MyStack* obj) {
    Queue* A = &obj->A;
    Queue* B = &obj->B;
    if (QueueEmpty(&obj->A))
    {
        return OneQueuePop(&A, &B);
    }
    else
    {
        return OneQueuePop(&B, &A);
    }
}

④取栈顶元素

cpp 复制代码
int myStackTop(MyStack* obj) {
    if (QueueEmpty(&obj->A))
    {
        return QueueBack(&obj->B);
    }
    else
    {
        return QueueBack(&obj->A);
    }
}

⑤判断栈是否为空

cpp 复制代码
bool myStackEmpty(MyStack* obj) {
    return QueueEmpty(&obj->A) && QueueEmpty(&obj->B);
}

⑥栈的销毁

cpp 复制代码
void myStackFree(MyStack* obj) {
    QueueDestroy(&obj->A);
    QueueDestroy(&obj->B);
    free(obj);
    obj = NULL;
}

(3)用栈实现队列

232. 用栈实现队列 - 力扣(LeetCode)

cpp 复制代码
typedef struct MyQueue{
    ST pushS;
    ST popS;
}MyQueue;

①初始化

cpp 复制代码
MyQueue* myQueueCreate() {
    MyQueue* pq = (MyQueue*)malloc(sizeof(MyQueue));
    STInit(&pq->pushS);
    STInit(&pq->popS);
    return pq;
}

②入队

cpp 复制代码
void myQueuePush(MyQueue* obj, int x) {
    assert(obj);
    STPush(&obj->pushS,x);
}

③出队

cpp 复制代码
int myQueuePop(MyQueue* obj) {
    assert(obj);
    if(STEmpty(&obj->popS)&&STEmpty(&obj->pushS))
    {
        perror("these two stacks are empty");
        exit(1);
    }
    if(STEmpty(&obj->popS))
    {
        while(!STEmpty(&obj->pushS))
        {
            STPush(&obj->popS,STTop(&obj->pushS));
            STPop(&obj->pushS);
        }     
    }
    int topVal = STTop(&obj->popS);
    STPop(&obj->popS);
    return topVal;
}

④获取栈顶元素

cpp 复制代码
int myQueuePeek(MyQueue* obj) {
    assert(obj);
    if(STEmpty(&obj->popS)&&STEmpty(&obj->pushS))
    {
        perror("these two stacks are empty");
        exit(1);
    }
    if(STEmpty(&obj->popS))
    {
        while(!STEmpty(&obj->pushS))
        {
            STPush(&obj->popS,STTop(&obj->pushS));
            STPop(&obj->pushS);
        }     
    }
    return STTop(&obj->popS);
}

⑤判断栈是否为空

cpp 复制代码
bool myQueueEmpty(MyQueue* obj) {
    assert(obj);
    return STEmpty(&obj->popS) && STEmpty(&obj->pushS);
}

⑥销毁栈

cpp 复制代码
void myQueueFree(MyQueue* obj) {
    assert(obj);
    STDestroy(&obj->popS);
    STDestroy(&obj->pushS);
    free(obj);
    obj = NULL;
}
相关推荐
爆打维c1 小时前
01BFS算法(例题:网格传送门旅游)
c语言·c++·python·算法·leetcode·广度优先
像素猎人2 小时前
力扣:面试题16.01.交换数字
c++·算法·leetcode·面试
小O的算法实验室2 小时前
2024年ASOC SCI2区TOP,异构 pbest 引导的综合学习粒子群算法,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
Python_Study20252 小时前
工程材料企业如何通过智慧获客软件破解市场困局:方法论、架构与实践
大数据·网络·数据结构·人工智能·架构
咚为2 小时前
Rust 错误处理的工程化演进:从 Result 到系统级边界设计
开发语言·后端·rust
qq_406176142 小时前
深入剖析JS中的XSS与CSRF漏洞:原理、攻击与防御全指南
服务器·开发语言·前端·javascript
AI科技星2 小时前
从质能关系到时空几何:光速飞行理论的框架对比与逻辑验证
服务器·人工智能·线性代数·算法·矩阵
CSDN_RTKLIB2 小时前
C++仿函数
c++·算法·stl
qq_12498707532 小时前
基于Java的心理测试系统的设计与实现(源码+论文+部署+安装)
java·开发语言·vue.js·spring boot·计算机毕设·计算机毕业设计