第三章 栈和队列

第三章 栈和队列

栈和队列是两个重要的线性数据结构,是操作受限的线性表

3.1栈和队列的定义和特点

3.1.1栈的定义和特点

  • 栈是限定仅在表尾进行插入或者删除操作的线性表,操作受限的线性表,先进后出的线性表
  • 栈顶是表尾端,栈底是表顶端
  • 不含元素的空表是空栈
  • 进栈和出栈的顺序是先进后出,进栈的时候如下图a1先进,其次a2,出栈的时候先出an,a(n-1)
  • 如果需要按照保存数据时相反的顺序来使用数据, 则可以利用栈来实现。
  • 栈跟线性表很像,有顺序栈链栈

3.1.2队列的定义和特点

  • 队列是先进先出的线性表
  • 进队(插入)叫队尾,出队(删除)的叫队头
  • 进队a1,a2,出队也是a1,a2这个顺序

3.3栈的表示和操作的实现

3.3.2顺序栈的表示和实现

顺序栈的定义

typedef struct
{
    SElernType *base;  //栈底指针
    SElernType *top;   //栈顶指针
    int stacksize;     //栈可用的最大容量
}Sqstack;

注意点

  1. 初始化完成后,栈底指针始终指向栈底元素,初始化完成前栈顶指针指向栈底元素,每入栈(插入)一个元素,栈顶指针自增1,出栈(删除)一个元素的时候栈顶指针自减1,当初始化完成后栈顶指针等于栈底指针则为空表
  2. 当栈底指针为NULL的时候表不存在,栈非空的时候,栈顶指针始终指向栈顶元素的上一位置

顺序栈的初始化

#include<iostream>
using namespace std;
#define MAXSIZE 100
#define OK "OK"
typedef string Status;
typedef int SElernType;
using namespace std;
typedef struct
{
    SElernType *base;  //栈底指针
    SElernType *top;   //栈顶指针
    int stacksize;     //栈可用的最大容量
}Sqstack;
int main()
{
    Sqstack S;
    Status InitStack(Sqstack &S);//初始化
    cout << InitStack(S) << endl;
}
Status InitStack(Sqstack &S)
{
    S.base=new SElernType[MAXSIZE];//申请空间
    if(!S.base) exit(0);//空间分配失败
    S.top=S.base;//栈顶和栈尾指针都指向栈尾
    S.stacksize=MAXSIZE;//栈容量变量设置为MAXSIZE
    return OK;
}

注意点

  1. 顺序表不是链表,直接在一个Sqstack类型的变量里面的栈底指针申请需要的内存,申请的类型则是自己需要的类型,这里我设置的是int类型
  2. 把栈顶指针和栈底指针都指向栈尾就可以了

顺序栈的入栈

Status Push(SqStack &s,SElemType e)
{
    if(s.top-s.base==s.stacksize) return ERROR;
    *s.top++=e;//入栈
    return OK;
}

注意点

  1. 栈顶指针-栈尾指针的那个位移量把,就等于栈的元素个数,就算是栈满

顺序栈的出栈

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

注意点

  1. 先指针减一,再赋值,因为第栈顶元素在栈顶指针指向的下一位

顺序栈的取栈顶元素

SElemType GetTop(SqStack S)
{
    if(S.top!=S.base)
    return *(S.top-1);
}

原理差不多

附本节实现代码

#include<iostream>
using namespace std;
#define MAXSIZE 100
#define OK "OK"
#define ERROR "ERROR"
typedef string Status;
typedef int SElemType;
using namespace std;
typedef struct
{
    SElemType *base;  //栈底指针
    SElemType *top;   //栈顶指针
    int stacksize;    //栈可用的最大容量
}SqStack;
int main()
{
    SqStack S;
    int e;
    Status InitStack(SqStack &S);//初始化
    Status Push(SqStack &s,SElemType e);//入栈
    Status Pop(SqStack &s,SElemType &e);//出栈,每次出栈删除其栈顶元素
    SElemType GetTop(SqStack S);//取栈顶元素,栈顶指针不变
    cout << "初始化新栈:\n" <<InitStack(S) << endl;
    cout << "入栈:\n" <<Push(S,20) << endl;
    cout << "出栈:\n" <<Pop(S,e) << endl;
    cout << "e:" << e << endl;
    cout << "入栈:\n" <<Push(S,30) << endl;
    cout << "取栈顶元素:\n" <<GetTop(S) << endl;
    return 0;
}
Status InitStack(SqStack &S)
{
    S.base=new SElemType[MAXSIZE];//申请空间
    if(!S.base) exit(0);//空间分配失败
    S.top=S.base;//栈顶和栈尾指针都指向栈尾
    S.stacksize=MAXSIZE;//栈容量变量设置为MAXSIZE
    return OK;
}
Status Push(SqStack &s,SElemType e)
{
    if(s.top-s.base==s.stacksize) return ERROR;
    *s.top++=e;//入栈
    return OK;
}
Status Pop(SqStack &s,SElemType &e)
{
    if(s.base==s.top) return ERROR;
    e=*(--s.top);
    return OK;
}
SElemType GetTop(SqStack S)
{
    if(S.top!=S.base)
    return *(S.top-1);
}

3.3.3栈链的表示与实现

定义

typedef struct StackNode
{
    Elemtype data;
    StackNode *next;
}StackNode, *LinkStack;

初始化

以链表的头部为栈顶,且不需要设置头结点,初始化空链表的时候只需要直接置空即可,操作栈的时候只需要在栈顶插入或者是删除,这样做也十分的方便

Status InitStack(LinkStack &L)
{
    L= nullptr;//构造空栈,栈顶指针置空即可
    return OK;
}

入栈

与顺序表不同,链式表在入栈的时候不需要考虑是否存满,只需分配一个结点空间即可,在栈顶插入,即将上一个元素往下挤

Status Push(LinkStack &L,int e)
{
    auto p=new StackNode;//创建新结点
    p->data=e;//结点赋值
    p->next=L;//将之前一结点往下压
    L=p;//设置栈顶
    return OK;
}

出栈

出栈需要判断链表是否为空,同时释放后栈顶指针应该指向下一结点

Status Pop(LinkStack &L,Elemtype &e)
{
    if(!L) return ERROR;//判断栈顶是否为空
    LinkStack p;
    e=L->data;//输出栈顶元素值
    p=L;//存放栈顶指针,以便释放内存
    L=L->next;//栈顶指针指向下一结点
    delete p;//释放内存
    return OK;
}

取栈顶元素

这个很简单,上面那个套过来

Status GetTop(LinkStack &L,Elemtype &e)
{
    if(!L) return ERROR;
    e=L->data;
    return OK;
}

附完整代码

#include<iostream>
#define OK "OK"
#define ERROR "ERROR"
using namespace std;
typedef string Status;
typedef int Elemtype;
typedef struct StackNode
{
    Elemtype data;
    StackNode *next;
}StackNode, *LinkStack;
int main()
{
    LinkStack L;
    Elemtype e;
    Status InitStack(LinkStack &L);//初始化操作
    Status Push(LinkStack &L,Elemtype e);//入栈操作
    Status Pop(LinkStack &L,Elemtype &e);//出栈操作
    Status GetTop(LinkStack &L,Elemtype &e);//取栈顶元素
    Status ClearStack(LinkStack &L);//清空栈,变为空栈
    bool StackEmpty(LinkStack L);//判断栈是否为空
    int StackLength(LinkStack L);//输出栈的长度
    Status StackTraverse(LinkStack L);//遍历栈
    Status DestroyStack(LinkStack &L);//破坏栈
    cout << InitStack(L) << endl;
    cout << Push(L,20) << endl;
    cout << Push(L,30) << endl;
    cout << Pop(L,e) << endl;
    cout << e << endl;
    cout << GetTop(L,e);
    cout << e;
    return 0;
}
Status InitStack(LinkStack &L)
{
    L= nullptr;//构造空栈,栈顶指针置空即可
    return OK;
}
Status Push(LinkStack &L,int e)
{
    auto p=new StackNode;//创建新结点
    p->data=e;//结点赋值
    p->next=L;//将之前一结点往下压
    L=p;//设置栈顶
    return OK;
}
Status Pop(LinkStack &L,Elemtype &e)
{
    if(!L) return ERROR;//判断栈顶是否为空
    LinkStack p;
    e=L->data;//输出栈顶元素值
    p=L;//存放栈顶指针,以便释放内存
    L=L->next;//栈顶指针指向下一结点
    delete p;//释放内存
    return OK;
}
Status GetTop(LinkStack &L,Elemtype &e)
{
    if(!L) return ERROR;
    e=L->data;
    return OK;
}
Status ClearStack(LinkStack &L)
{
    if(!L) return ERROR;
    LinkStack p=L;
    LinkStack q;
    while(p)
    {
        q=p;
        p=p->next;
        delete q;
    }
    L= nullptr;
    return OK;
}
bool StackEmpty(LinkStack L)
{
    if(!L) return true;
    else
        return false;
}
int StackLength(LinkStack L)
{
    LinkStack p=L;
    int n=0;
    while(p)
    {
        n++;
        p=p->next;
    }
    return n;
}
Status StackTraverse(LinkStack L)
{
    if(StackEmpty(L)) return ERROR;
    LinkStack p=L;
    while(p)
    {
        cout << p->data << endl;
        p=p->next;
    }
    return OK;
}
Status DestroyStack(LinkStack &L)
{
    if(!L) return ERROR;
    LinkStack p=L;
    LinkStack q;
    while(p)
    {
        q=p;
        p=p->next;
        delete q;
    }
    return OK;
}

3.4栈与递归

3.4.1采用递归算法解决的问题

定义是递归的

分治法:对于某种复杂的问题,能够分解为几个简单的类似解法的子问题来求解,就程=称这种方法为递归求解,这种分解-求解的方法就叫做分治法

采用分治法求解递归需要满足三个条件:

  1. 能够将一个问题转换成一个新问题,新问题和原问题的解法类似或者相同,不同仅仅是处理对象不相同,并且吹处理对象更小或者是变化有规律
  2. 可以通过上述转换将问题简单化
  3. 必须有一个明确的递归出口,或者是一个递归的边界

viod p(参数表)

{

if(递归结束条件成立)可直接求解   //递归终止的条件

else p(较小的参数)  //递归步骤

}

数据结构是递归的

链表是一种递归的数据结构

//遍历输出链表中各个结点的递归算法

void Display(LinkList L)  

{  
  if(L)  
  {  
  cout << L->data << endl;  
  Display(L->next);  
  }  
}  

问题的解法是递归的

比如汉诺塔

0无标题

3.4.2递归过程与递归工作栈

当有多个函数在嵌套调用的时候,采用先调用后返回的原则,上述函数之间的信息传递和控制转移通过栈来实现,整个系统运行时所需要的数据空间被安排在一个栈中,每调用一个函数,就在栈顶分配一个存储空间,当前运行的函数的数据区必须在栈顶

3.5队列的表示和操作的实现

3.5.1队列的类型定义

队列和栈不太一样,队列的删除在队列头部进行

下面是队列的基本操作,抽象数据类型定义

3.5.2 循环队列——队列的顺序表示和实现

队列顺序结构定义

#define MAXQSIZE 100//最大容量
typedef struct
{
    QElemType *base;//存储空间基地址
    int front;//头指针
    int rear;//尾指针
};

队列插入删除操作图示

如图

  1. 初始化时,头指针和尾指针都在0的位置
  2. 入队时,尾指针增加一,且尾指针始终指向队尾元素的上一位
  3. 出队时,头指针增加一

注意:但是当出现图d这种情况时,再入队就会造成溢出,称为假溢出

循环队列——假溢出的解决方法

如图当第六个元素入队时,通过模运算,Q.rear=(Q.rear-1)%6,得到Q.rear=0,此时J6存到最上面,而尾指针在最下面,达到循环队列解决假溢出的目的

弊端和解决办法

循环列表当头尾指针相同的时候,可能存在全空和全满两种状态,所以不能用头尾指针是否相同来判断队列是否满,

解决方法是少用一个元素空间, 即队列空间大小为m时,有m-1个元素就认为是队满。这样判断队
空的条件不变, 即当头、 尾指针的值相同时, 则认为队空;而当尾指针在循环意义上加1后是等
千头指针, 则认为队满。 因此, 在循环队列中队空和队满的条件是

Q.front=Q.rear//判断队空
(Q.rear+1)%MAXQSIZE=Q.front//判断队满

下面是具体的操作

初始化

Status InitQueue(SqQueue &Q)
{
    Q.base=new QElemType [MAXQSIZE];//为队列分配足够的空间
    if(!Q.base) exit(0);//分配失败
    Q.front=Q.rear=0;//初始化置零
    return OK;
}

Q.base存放用于队列的数据、

计算队列长度

int QueueLenth(SqQueue Q)
{
    return (Q.rear-Q.front+MAXQSIZE)%MAXQSIZE;
}

对于非循环队列。其长度就是尾指针和头指针的差值,而对于循环队列,其长度等于尾指针和头指针的差值加上最大容量并取模长

入队

从队尾插入元素

Status EnQueue(SqQueue &Q,QElemType e)
{
    if((Q.rear+1)%MAXQSIZE==Q.front)//判断是否队满
        return ERROR;
    Q.base[Q.rear]=e;//新元素插入队尾
    Q.rear=(Q.rear+1)%MAXQSIZE;//作为循环队列,尾指针+1
    return OK;
}

特殊方法尾指针+1,要记住

出队

出队从对头出,还要删除对应元素

Status DeQueue(SqQueue &Q,QElemType &e)
{
    if(Q.rear==Q.front) return ERROR;//队空
    e=Q.front;
    Q.front=(Q.front+1)%MAXQSIZE;
    return OK;
}

和入队相似

取队头元素

QElemType GetHead(SqQueue &Q)
{
    if(Q.front!=Q.rear)
        return Q.base[Q.front];
}

和出队相似,不改变队头指针

销毁

Status DestroyQueue(SqQueue &Q)//破坏队列
{
    if(Q.base!= nullptr) //要判断是否为空
    {
        delete Q.base;
        Q.base = nullptr;
    }
    Q.front=Q.rear=0;
    return OK;
}

清除

Status ClearQueue(SqQueue &Q)//清除队列
{
    delete Q.base;
    Q.base=new QElemType[MAXQSIZE];
    Q.front=Q.rear=0;
    return OK;
}

判断是否为空

bool QueueEmpty(SqQueue Q)//判断是否为空
{
    if(Q.rear==Q.front)
        return true;
    else return false;
}

遍历

Status QueueTraverse(SqQueue Q)//遍历
{
    int i=Q.front;
    while(i!=Q.rear)
    {
        cout << Q.base[i] << endl;
        i=(i+1)%MAXQSIZE;
    }
    return OK;
}

附完整代码

#include<iostream>
#define OK "OK"
#define ERROR "ERROR"
#define MAXQSIZE 100
using namespace std;
typedef int QElemType;
typedef string Status;
typedef struct
{
    QElemType *base;//存储空间基地址
    int front;//头指针
    int rear;//尾指针
}SqQueue;
Status InitQueue(SqQueue &Q)
{
    Q.base=new QElemType [MAXQSIZE];//为队列分配足够的空间
    if(!Q.base) exit(0);//分配失败
    Q.front=Q.rear=0;//初始化置零
    return OK;
}
int QueueLenth(SqQueue Q)
{
    return (Q.rear-Q.front+MAXQSIZE)%MAXQSIZE;
}
Status EnQueue(SqQueue &Q,QElemType e)
{
    if((Q.rear+1)%MAXQSIZE==Q.front)//判断是否队满
        return ERROR;
    Q.base[Q.rear]=e;//新元素插入队尾
    Q.rear=(Q.rear+1)%MAXQSIZE;//作为循环队列,尾指针+1
    return OK;
}
Status DeQueue(SqQueue &Q,QElemType &e)
{
    if(Q.rear==Q.front) return ERROR;//队空
    e=Q.base[Q.front];
    Q.front=(Q.front+1)%MAXQSIZE;
    return OK;
}
QElemType GetHead(SqQueue &Q)
{
    if(Q.front!=Q.rear)
        return Q.base[Q.front];
}
Status DestroyQueue(SqQueue &Q)//破坏队列
{
    if(Q.base!= nullptr)
    {
        delete Q.base;
        Q.base = nullptr;
    }
    Q.front=Q.rear=0;
    return OK;
}
Status ClearQueue(SqQueue &Q)//清除队列
{
    delete Q.base;
    Q.base=new QElemType[MAXQSIZE];
    Q.front=Q.rear=0;
    return OK;
}
bool QueueEmpty(SqQueue Q)//判断是否为空
{
    if(Q.rear==Q.front)
        return true;
    else return false;
}
Status QueueTraverse(SqQueue Q)//遍历
{
    int i=Q.front;
    while(i!=Q.rear)
    {
        cout << Q.base[i] << endl;
        i=(i+1)%MAXQSIZE;
    }
    return OK;
}
int main()
{
    SqQueue Q;
    int e;
    cout
    << InitQueue(Q) << endl
    << EnQueue(Q,4) << endl
    << EnQueue(Q,5) << endl
    << QueueTraverse(Q) << endl
    << QueueEmpty(Q) << endl
    << DeQueue(Q,e) <<endl
    << e << endl
    << ClearQueue(Q) << endl
    << QueueTraverse(Q) << endl;
    return 0;
}

3.5.3链队——队列的链式表示与实现

链队的表示一般使用单链表,单链表的链式存储结构表示如下

结构定义

typedef struct QNode
{
    QElemType data;
    struct QNode *next;
}QNode,*QueuePtr;
typedef struct  //这个结构体里面的每个变量都装上面的数据
{
    QueuePtr front;//队头
    QueuePtr rear;//队尾
}LinkQueue;

初始化

Status InitQueue(LinkQueue &Q)//初始化
{
    Q.front=Q.rear=new QNode;//头尾结点指向相同的结点
    Q.front->next= nullptr;//头结点指针域指针域
    return OK;
}

入队

链表和顺序表一样,从尾部插入数据,头部输出

Status EnQueue(LinkQueue &Q,QElemType e)//入队
{
    auto p=new QNode;//分配的新结点
    p->data=e;//录入数据
    p->next= nullptr;//指针域置空
    Q.rear->next=p;//添加结点到链表
    Q.rear=p;//尾指针指向最后一个结点,也就是新建的结点
    return OK;
}

出队

注意出队的时候要判断链表是不是空链表,还需要释放队头元素占用的空间

Status DeQueue(LinkQueue &Q,QElemType &e)
{
    if(Q.rear==Q.front) return ERROR;//判断是不是空链表
    QueuePtr p=Q.front->next;//头指针的下一个元素
    e=p->data;
    Q.front->next=p->next;//头指针移动位置
    if(Q.rear==p) Q.front=Q.rear;//当删除的是最后一个元素,需要头指针等于尾指针,表示空链表
    delete p;
    return OK;
}

取队头元素

QElemType GetHead(LinkQueue Q)//取队头元素
{
    if(Q.rear!=Q.front)
        return Q.front->next->data;//返回
}

销毁

Status DestroyQueue (LinkQueue &Q)//销毁
{
    QueuePtr p=Q.front->next;//
    QueuePtr q;
    while(p)//删除
    {
        q=p;
        p=p->next;
        delete q;
    }
    return OK;
}

清除

Status ClearQueue (LinkQueue &Q)//清除
{
    QueuePtr p=Q.front->next;//
    QueuePtr q;
    while(p)//删除,这里已经删除了头尾结点
    {
        q=p;
        p=p->next;
        delete q;
    }
    Q.front=Q.rear=new QNode;//重新创建
    Q.front->next= nullptr;
    return OK;
}

判断是否为空

bool QueueEmpty (LinkQueue Q)//判断是否为空
{
    if(Q.rear==Q.front) return true;
    else return false;
}

遍历

Status QueueTraverse(LinkQueue Q)//遍历
{
    QueuePtr p=Q.front->next;
    if(Q.front!=Q.rear)
    {
        while(p)
        {
            cout << p->data << endl;
            p=p->next;
        }
    }
    return OK;
}

附完整代码

#include<iostream>
#define OK "OK"
#define ERROR "ERROR"
using namespace std;
typedef int QElemType;
typedef string Status;
typedef struct QNode
{
    QElemType data;
    struct QNode *next;
}QNode,*QueuePtr;
typedef struct  //这个结构体里面的每个变量都装上面的数据
{
    QueuePtr front;//队头
    QueuePtr rear;//队尾
}LinkQueue;
Status InitQueue(LinkQueue &Q)//初始化
{
    Q.front=Q.rear=new QNode;//头尾结点指向相同的结点
    Q.front->next= nullptr;//头结点指针域置空
    return OK;
}
Status EnQueue(LinkQueue &Q,QElemType e)//入队
{
    auto p=new QNode;//分配的新结点
    p->data=e;//录入数据
    p->next= nullptr;//指针域置空
    Q.rear->next=p;//添加结点到链表
    Q.rear=p;//尾指针指向最后一个结点,也就是新建的结点
    return OK;
}
Status DeQueue(LinkQueue &Q,QElemType &e)//出队
{
    if(Q.rear==Q.front) return ERROR;//判断是不是空链表
    QueuePtr p=Q.front->next;//头指针的下一个元素
    e=p->data;
    Q.front->next=p->next;//头指针移动位置
    if(Q.rear==p) Q.front=Q.rear;//当删除的是最后一个元素,需要头指针等于尾指针
    delete p;
    return OK;
}
QElemType GetHead(LinkQueue Q)//取队头元素
{
    if(Q.rear!=Q.front)
        return Q.front->next->data;
}
Status DestroyQueue (LinkQueue &Q)//销毁
{
    QueuePtr p=Q.front->next;//
    QueuePtr q;
    while(p)//删除
    {
        q=p;
        p=p->next;
        delete q;
    }
    delete Q.front;//删除头指针
    return OK;
}
Status ClearQueue (LinkQueue &Q)//清除
{
    QueuePtr p=Q.front->next;//
    QueuePtr q;
    while(p)//删除,头尾都已经删除了
    {
        q=p;
        p=p->next;
        delete q;
    }
    delete Q.front;//删除头指针
    Q.front=Q.rear=new QNode;//重新创建
    Q.front->next= nullptr;
    return OK;
}
bool QueueEmpty (LinkQueue Q)//判断是否为空
{
    if(Q.rear==Q.front) return true;
    else return false;
}
Status QueueTraverse(LinkQueue Q)//遍历
{
    QueuePtr p=Q.front->next;
    if(Q.front==Q.rear)
    {
        return ERROR;
    }
    while(p)
    {
        cout << p->data << endl;
        p=p->next;
    }
    return OK;
}
int main()
{
    LinkQueue Q;
    int e;
    cout
    << InitQueue(Q) << endl
    << EnQueue(Q,2) << endl
    << EnQueue(Q,3) << endl
    << QueueTraverse(Q) << endl
    << DeQueue(Q,e) << endl
    << e << endl
    << GetHead(Q) << endl
    << ClearQueue(Q) << endl
    << EnQueue(Q,6) << endl
    << QueueTraverse(Q);
    return 0;
}

3.6案例分析与实现

3.6.1 数制转换

将十进制转换为八进制,将十进制数与八求余数压入栈中,这个数再变为其除以八,以此循环,直到N为0

算法实现

#include<iostream>
#define OK "OK"
#define ERROR "ERROR"
using namespace std;
typedef string Status;
typedef struct StackNode
{
    int data;
    StackNode *next;
}StackNode, *LinkStack;
Status IninStack(LinkStack &S)//初始化
{
    S= nullptr;
    return OK;
}
Status Push(LinkStack &S,int e)//入栈
{
    auto p=new StackNode;
    p->data=e;
    p->next=S;
    S=p;
    return OK;
}
Status Pop(LinkStack &S,int &e)//出栈
{
    if(!S) return ERROR;
    LinkStack p;
    p=S;
    e=S->data;
    S=S->next;
    delete p;
    return OK;
}
bool Isempty(LinkStack S)//判断是否为空
{
    if(!S) return true;
    else return false;
}
int main()
{
    LinkStack S;
    int e,a;
    cout << IninStack(S) << endl;
    cin >> a;
    while(a)//入栈
    {
        cout << Push(S,(a%8)) << endl;
        a=a/8;
    }
    while(!Isempty(S))//出栈
    {
        Pop(S,e);
        cout << e;
    }
    return 0;
}

3.6.2括号匹配的检验

当有左括号的时候入栈,当有右括号的时候,与栈顶元素比较,符合则往下比较,不符合直接退出匹配失败,最后当所有括号扫描完,,每个都匹配成功的时候最后匹配成功

算法实现

#include<iostream>
#define OK "OK"
#define ERROR "ERROR"
using namespace std;
typedef string Status;
typedef char Elemtype;
typedef struct StackNode
{
    Elemtype data;
    StackNode *next;
}StackNode, *LinkStack;
Status IninStack(LinkStack &S)//初始化
{
    S= nullptr;
    return OK;
}
Status Push(LinkStack &S,Elemtype e)//入栈
{
    auto p=new StackNode;
    p->data=e;
    p->next=S;
    S=p;
    return OK;
}
Status Pop(LinkStack &S,Elemtype &e)//出栈
{
    if(!S) return ERROR;
    LinkStack p;
    p=S;
    e=S->data;
    S=S->next;
    delete p;
    return OK;
}
bool Isempty(LinkStack S)//判断是否为空
{
    if(!S) return true;
    else return false;
}
Elemtype GetTop(LinkStack S)
{
    if(!Isempty(S))
        return S->data;
    else
        return 0;
}
int main()
{
    LinkStack S;
    int flag=1;
    char ch,x;
    cout << IninStack(S) << endl;
    cin >> ch;//输入括号表达式
    while(ch!='#'&&flag)
    {
        switch(ch)//比较
        {
            case '[':
                Push(S, ch);
                break;
            case '('://左括号入栈
                Push(S, ch);
                break;
            case ')'://右括号符合条件出栈
                if(!Isempty(S)&& GetTop(S)=='(')
                    Pop(S,x);
                else
                    flag = 0;
                break;
            case ']':
                if(!Isempty(S)&& GetTop(S)=='[')
                    Pop(S,x);
                else
                    flag = 0;
                break;
        }
        cin >> ch;
    }
    if(Isempty(S)&&flag) cout << "success";//最后比较
    else cout << "fail";
    return 0;
}

注意:case语句不需要写大括号,但是必须要有break语句,执行到break结束,default语句放在case后,当所有情况都不符合才会执行

3.6.3表达式求值(此题P78)

一个表达式都是由操作数,运算符,界限符组成,计算的时候还需要考虑各种运算符的优先级

  • 操作数:数字,字符,常量,变量
  • 运算符:+;-;*;/,算术运算符,关系运算符,逻辑运算符
  • 界限符:括号等
#include<iostream>
#include<unordered_map>
#define OK "OK"
#define ERROR "ERROR"
using namespace std;
typedef string Status;
typedef char Elemtype;
char ch1;
typedef struct StackNode
{
    Elemtype data;
    StackNode *next;
}StackNode, *LinkStack;
Status IninStack(LinkStack &S)//初始化
{
    S= nullptr;
    return OK;
}
Status Push(LinkStack &S,Elemtype e)//入栈
{
    auto p=new StackNode;
    p->data=e;
    p->next=S;
    S=p;
    return OK;
}
Status Pop(LinkStack &S,Elemtype &e)//出栈
{
    if(!S) return ERROR;
    LinkStack p;
    p=S;
    e=S->data;
    S=S->next;
    delete p;
    return OK;
}
bool Isempty(LinkStack S)//判断是否为空
{
    if(!S) return true;
    else return false;
}
Elemtype GetTop(LinkStack S)
{
    if(!Isempty(S))
        return S->data;
    else
        return 0;
}
bool In(char ch)
{
    if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='('||ch==')'||ch=='#')
        return true;
    else return false;
}
char Precede(char c1,char c2)
{
    unordered_map<char,int>hash_map{
        {')',0},
        {'#',-1},
        {'+',1},
        {'-',1},
        {'*',2},
        {'/',2},
        {'(',3}
    };
    if((c1=='('&&c2==')')||(c1=='#'&&c2=='#'))
        return '=';
    else if(c1=='(')
        return '<';
    else if(c1==')')
        return '>';
    else if(hash_map[c1]<hash_map[c2])
        return '<';
    else if(hash_map[c1]>hash_map[c2])
        return '>';
}
char Operate(char c1,char c2,char c3)
{
    if(c2=='+')
        return ch1=(c1-48)+(c3-48);
    else if(c2=='-')
        return ch1=(c1-48)-(c3-48);
    else if(c2=='*')
        return ch1=(c1-48)*(c3-48);
    else if(c2=='/')
        return ch1=(c1-48)/(c3-48);
}
int main()
{
    char ch,theta,a,b,x;
    LinkStack OPTR;
    LinkStack OPND;
    IninStack(OPND);
    IninStack(OPTR);
    Push(OPTR,'#');
    cin >> ch;
    while(ch!='#'|| GetTop(OPTR)!='#')
    {
        if(!In(ch)){Push(OPND,ch);cin >> ch;}
        else
            switch(Precede(GetTop(OPTR),ch))
            {
                case '<':
                    Push(OPTR,ch);cin>>ch;
                    break;
                case '>':
                    Pop(OPTR,theta);
                    Pop(OPND,b);
                    Pop(OPND,a);
                    Push(OPND, Operate(a,theta,b));
                    break;
                case '=':
                    Pop(OPTR,x);cin >> ch;
                    break;
            }
    }
    cout << (int)GetTop(OPND);
    return 0;
}

问题:复合运算的时候出现问题,暂时无法解决

3.6.4舞伴问题

舞伴配对问题用的是链队方法

#include<iostream>
#define OK "OK"
#define ERROR "ERROR"
#define MAXQSIZE 100
using namespace std;
typedef string Status;
typedef char QElemType;
typedef struct
{
    string name;
    char sex;
}Person;
typedef struct
{
    Person* base;
    int front;//队头
    int rear;//队尾
}SqQueue;
Status InitQueue(SqQueue& Q)
{
    Q.base = new Person[MAXQSIZE];
    if (!Q.base) exit(0);
    Q.front=Q.rear= NULL;
    return OK;
}
Status EnQueue(SqQueue& Q, Person e)
{
    if ((Q.rear + 1) % MAXQSIZE == Q.front)
        return 0;
    Q.base[Q.rear] = e;
    Q.rear = (Q.rear + 1) % MAXQSIZE;
    return OK;
}
Status DeQueue(SqQueue& Q, Person& e)
{
    if (Q.front == Q.rear) return ERROR;
    e = Q.base[Q.front];
    Q.front = (Q.front + 1) % MAXQSIZE;
    return OK;
}
Person GetHead(SqQueue Q)
{
    if (Q.front != Q.rear)
        return Q.base[Q.front];
}

bool QueueEmpty(SqQueue& Q)
{
    if (Q.front == Q.rear) return true;
    else return false;
}
void DancePartner(Person dancer[], int num)
{
    Person p;
    SqQueue Mdancers, Fdancers;
    InitQueue(Mdancers);
    InitQueue(Fdancers);
    for (int i = 0; i < num; i++)
    {
        p = dancer[i];
        if (p.sex == 'F') EnQueue(Fdancers, p);
        else EnQueue(Mdancers, p);
    }
    while (!QueueEmpty(Fdancers) && !QueueEmpty(Mdancers))
    {
        DeQueue(Fdancers, p);
        cout << p.name<<"-";
        DeQueue(Mdancers, p);
        cout << p.name<<endl;
    }
    if (!QueueEmpty(Fdancers))
    {
        p = GetHead(Fdancers);
        cout << "The first woman to get a partner is:" << p.name << endl;
    }
    else if (!QueueEmpty(Mdancers))
    {
        p = GetHead(Mdancers);
        cout << "The first man to get a partner is:" << p.name << endl;
    }
}
int main()
{
    SqQueue Mdancers, Fdancers;
    int n;
    Person dancer[MAXQSIZE];
    cout << "请输入跳舞的人数:" << endl;
    cin >> n;
    for (int i=1; i<=n; i++)
    {
        cin >> dancer[i-1].name;
        cin >> dancer[i-1].sex;
    }
    DancePartner(dancer, n);
    return 0;
}
posted @   艾洋mhduiy  阅读(111)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示