栈与队列及其应用C语言实现(数据结构复习最全笔记)

版权声明:欢迎转载,但转载时请注明原文地址 https://blog.csdn.net/weixin_42110638/article/details/83106209

一.栈的表示与实现(顺序栈)

1.栈的顺序结构定义

typedef struct
{
    SElemType *base;//栈底指针
    SElemType *top;//栈顶指针
    int stacksize;//当前最大容量
} SqStack;

2.栈的初始化(构建空栈)

Status InitStack(SqStack &S)
{
    S.base=(SElemType *)malloc(sizeof(SElemType)*STACK_INIT_SIZE);//申请空间
    if(!S.base)
        exit(OVERFLOW);
    S.top=S.base;//头尾指针相等,代表空栈
    S.stacksize=STACK_INIT_SIZE;//当前容量为初始最大容量
    return OK;
}

 3.栈的插入操作

Status Push(SqStack &S,SElemType e)
{
    if(S.top-S.base>=S.stacksize)//空间不够的话要考虑扩容
    {
        S.base=(SElemType*)malloc(sizeof(SElemType)*(S.stacksize+STACKINCREMENT));
        if(!S.base)
            exit(OVERFLOW);
        S.top=S.base+S.stacksize;
        S.stacksize+=STACKINCREMENT;
    }
    //把e插入栈顶
    *S.top++=e;//相当于S.top = e;top++;
    return OK;

}

4.栈的删除操作

Status Pop(SqStack &S,SElemType &e)
{
    if(S.top==S.base)
        return ERROR;
    e = *S.top--;
    return OK;
}

5.返回栈顶元素

Status GetTop(SqStack &S,SElemType &e)
{
    if(S.base==S.top)
        return ERROR;
    e=*(S.top-1);//当栈不空时,栈顶指针总是指在栈顶元素的下一个位置
    return OK;
}

6.栈的判空

bool JudgeEmpty(SqStack &S)
{
    if(S.top == S.base)
        return true;
    else
        return false;
}

二.栈的应用举例

1.数值转换

所以这个转换过程符合栈的原理

这里有一道例题,我写的应该算很详细了,看懂的话这块应该就ok了

https://blog.csdn.net/weixin_42110638/article/details/83030406

关于其他进制转换的原理,想了解的话大家也可以看这个

https://jingyan.baidu.com/article/495ba84109665338b30ede98.html

2.括号匹配检验

基本原理:

思路:1.在算法中设置一个栈

2.每读入一个括号,若是右括号,则要看是否匹配。当栈不空时,如果匹配,则栈顶元素出栈,如果不匹配(即不合法),说明缺少右括号,输出左符号-?(因为如果是右括号,说明之前已经读入左括号,但是两个括号不匹配)。当栈为空时,说明缺少左括号,输出?-右括号。若是左括号,则压入栈中。

3.对于/*符号,可用“<”代替,读到/时记得先i++;

4.算法的开始于结束,栈都应该为空
举两个例题,会了应该就差不多了

例题一:习题3.8 符号配对 (20 分)

pta原题链接:https://pintia.cn/problem-sets/434/problems/5869

该题答案与解析https://blog.csdn.net/weixin_42110638/article/details/83054360

例题二:练习题 10:括号画家

该题解析与答案:https://blog.csdn.net/weixin_42110638/article/details/83119150

3.行编辑程序

这里还没仔细研究,思路日后补充

具体的例题日后补充

4.迷宫求解(回溯算法)

 

这里还没仔细研究,思路日后补充

具体的例题日后补充

5.表达式转换(非常重要,也比较难)

思路:

从头到尾读取中缀表达式的每个对象,对不同对象按不同的情况处理。

1.运算数:直接输出

2.左括号:压入栈中

3.右括号:将栈顶的运算符弹出并输出,直到遇到左括号(出栈,不输出)

4.运算符:

若优先级大于栈顶运算符时,则把它压栈;

若优先级小于等于栈顶运算符时,将栈顶运算符弹出并输出;再比较新的栈顶运算符,直到该运算符大于栈顶运算符优先级为止,然后将该运算符压栈

5.若各对象处理完毕,则把堆栈中存留的运算符一并输出

这里会这道例题就可以了,不太好做

pta原题链接:习题3.11 表达式转换 (25 分)https://pintia.cn/problem-sets/434/problems/5893

该题超详细答案与解析:https://blog.csdn.net/weixin_42110638/article/details/83089498

6.其他应用:

a:函数调用及递归实现

b:图的深度优先搜索

二.链队列的表示与实现

1.链队列的结构定义

typedef struct QNode
{
    QElemType data;
    struct QNode *next;
} QNode,*QueuePtr;

typedef struct
{
    QueuePtr front;
    QueuePtr rear;
} LinkQueue;

2.链队列的初始化(构建空队列)

Status InitQueue(LinkQueue &Q)
{
    Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));
    if(!Q.front)
        exit(OVERFLOW);
    Q.front->next = NULL;
    return OK;
}

3.链队列的入队操作

Status EnQueue(LinkQueue &Q,QElemType e)
{
    QueuePtr p;
    p = (QueuePtr)malloc(sizeof(QNode));
    if(!p)
        exit(OVERFLOW);
    p->data = e;
        p->next = NULL;
    Q.rear->next = p;//尾部插入
    Q.rear = p;
    return 1;
}

4.链队列的出队操作

Status DeQueue(LinkQueue &Q,QElemType &e)
{
    if(Q.front == Q.rear)
        return 0;
    QueuePtr p = Q.front->next;//指向队头
    e = p->data;
    Q.front->next = p->next;
    //如果队头是队尾,删除后将rear指向头结点
    if(Q.rear == p)
        Q.rear = Q.front;
    free(p);
    return 1;
}

5.链队列的判空操作

bool JudgeEmpty(LinkQueue &Q)
{
    if(Q.front == Q.rear)
        return true;
    else
        return false;
}

 6.链队列的销毁操作

Status DestroyQueue(LinkQueue &Q) {
    while(Q.front) {
        Q.rear = Q.front->next;
        free(Q.front);
        Q.front = Q.rear;
    }
    return true;
}

三.循环队列的表示与实现(顺序队列)

1.循环队列的结构定义

typedef struct{
    QElemType *base;
    int front;
    int rear;
}SqQueue;

2.循环队列的初始化

SqQueue InitQueue(SqQueue &Q)
{
    Q.base=(QElemType *)malloc(MAXQSIZE*sizeof(QElemType));//为队列的数据存储空间分配内存
    if(!Q.base)
       exit(OVERFLOW);
    Q.front = Q.rear = 0;
    return OK;
}

3.循环队列的入队操作

Status EnQueue(SqQueue &Q,QElemType e)
{
    if((Q.rear + 1)% MAXQSIZE == Q.front)//队列满的判断
        return 0;
    Q.base[Q.rear] = e;//将e赋值给队尾
    Q.rear = (Q.rear + 1) % MAXQSIZE;//rear指针向后移一位,若到最后则转到数组头部
    return 1;
}

4.循环队列的出队操作

Status DeQueue(SqQueue &Q,QElemType &e)
{
    if(Q.front == Q.base)//队列空的判断
        return 0;
    e = Q.base[Q.front];//将队头元素赋值给e
    Q.front = (Q.front + 1) % MAXQSIZE;//front指针向后移一位,若到最后则转到数组头部
    return 1;
}

5.循环队列返回队列元素个数

Status QueueLength(SqQueue Q)//返回队列长度
{
    return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
}

后续还会更新例题以及栈与队列的总结

猜你喜欢

转载自blog.csdn.net/weixin_42110638/article/details/83106209