数据结构 栈和队列部分代码c

数据结构(c语言版) 第三章 栈和队列 数据结构(c语言版) 第三章 栈和队列 栈: 抽象数据栈的定义: 栈(stack)栈是限定仅在表尾进行插入或删除操作的线性表,因此表尾对栈有着特殊的含义,称为栈顶(top),相应表头成为栈底(bottom),不含元素的空表称为空栈。 因为栈的进出都是从表尾进行插入和删除,于是又叫后进先出(last in first out)也能叫先进后出。 栈的表示和实现 线性表类似,对于栈来说,也有两种存储结构(1)顺序栈(2)链式栈 (1)顺序栈: 顺序栈的结构结构体单位我们一般有两个指针和一个整型数据,其中整 阅读详情

栈

顺序栈

  • init
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>

#define MaxSize 10

typedef int ElemType;
typedef struct{//定义栈中元素的最大个数
    ElemType data[MaxSize];//静态数组存放栈中元素
    int top;//栈顶指针,顺序栈中表示数组下标,初始化的时候为-1
}SqStack;

// init a stack
void InitStack(SqStack *s){
    (*s).top=-1;//初始化栈顶指针
}

// judge
bool StackEmpty(SqStack s){
    if(s.top==-1)
        return true;
    return false;
}
  • push
// push
bool Push(SqStack *s,ElemType x){
    if((*s).top==MaxSize-1)//栈满,报错
        return false;
    (*s).top=(*s).top+1;
    (*s).data[(*s).top]=x;
    return true;
}
// 按照后进先出的顺序输出
void printfStack(SqStack s){
    if(s.top==-1)//空栈
        return;
    for(int i=s.top;i>=0;i--)
        printf("%d->",s.data[i]);
    printf("\n");
}
void test(){
    SqStack s;
    InitStack(&s);
    if(StackEmpty(s))
        printf("yes!");

    for(int i=0;i<4;i++){
        Push(&s,i+1);
    }
    printfStack(s);
    
}
void main(){
    test();
}
  • pop
// pop
bool Pop(SqStack *s,ElemType *x){
    if((*s).top==-1)//栈空
        return false;
    *x=(*s).data[(*s).top];
    (*s).top--;
    return true;
}

这里对于栈的顺序存储结构的实现要注意的是push和pop的实现过程中,先对top指针进行加减操作还是先存/取数据

  • 读栈顶元素
// 读取栈顶元素的操作,和pop的区别在于要不要删除top的元素
bool Gettop(SqStack s,ElemType *x){
    if(s.top==-1)//栈空
        return false;
    *x=s.data[s.top];
    return true;
}

以上代码中,top的初始条件是top==-1,但是也有另外的一种初始条件为top==0,这个表示top指向下一个可以存储数据的位置,如果初始条件是这种,那么对于push和pop的实现过程(先改变top还是先存取数据)和原本的实现刚好相反

// --------------------华丽的分界线----------------------
void InitStack2(SqStack *s){
    (*s).top=0;//表示下一个可以存储的位置
}
bool Push2(SqStack *s,ElemType x){
    if((*s).top==MaxSize)//栈满
        return false;

    (*s).data[(*s).top++]=x;
    return true;
}
bool Pop2(SqStack *s,ElemType *x){
    if((*s).top==0)//栈空
        return false;
    *x=(*s).data[--(*s).top];
    return true;
}
void printfStack2(SqStack s){
    if(s.top==0)
        return;
    for(int i=(s.top-1);i>=0;i--){
        printf("%d->",s.data[i]);
    }
    printf("\n");
}
void test(){
    SqStack s;
    InitStack2(&s);

    for(int i=0;i<4;i++){
        Push2(&s,i+1);
    }
    printfStack2(s);
    ElemType x=0;
    Pop2(&s,&x);
    printfStack2(s);
    
}
void main(){
    test();
}
  • 共享栈

栈满条件是top0+1==top1。这里代码很明显是有冗余的,实际上我们可以设定一个值为index,用来指定当前如果的栈顶指针,如果index=0说明是top0,如果index=1说明是top1,这样两个push函数可以简化为bool Push(ShStack *s,int index ElemType x)函数内部对index的合法性以及对栈满判断,最后使用一个switch语句就可以实现把两个push函数合并为一个push函数,在应用中,这个可以简化代码接口,所以这个是尤为重要的。类似对pop也可以有同等实现思路。

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>

#define MaxSize 10//定义栈中元素的最大个数

typedef int ElemType;
typedef struct{
    ElemType data[MaxSize];//静态数组存放栈中元素
    int top0;//栈顶指针,顺序栈中表示数组下标,初始化的时候为-1
    int top1;
}ShStack;

void InitStack3(ShStack *s){
    (*s).top0=-1;
    (*s).top1=MaxSize;
}

bool Push_0(ShStack *s,ElemType x){
    if((*s).top0+1>=(*s).top1){//栈满,溢出
        return false;
    }
    (*s).data[++(*s).top0]=x;
    return true;
}
bool Push_1(ShStack *s,ElemType x){
    if((*s).top0+1>=(*s).top1){//栈满,溢出
        return false;
    }
    (*s).data[--(*s).top1]=x;
    return true;
}
bool Pop_0(ShStack *s,ElemType *x){
    if((*s).top0==-1)//栈空
        return false;
    *x=(*s).data[(*s).top0--];
    return true;
}
bool Pop_1(ShStack *s,ElemType *x){
    if((*s).top1==MaxSize)//栈空
        return false;
    *x=(*s).data[(*s).top1++];
    return true;
}

链式栈

使用不带头结点的单链表来实现链式栈,对应的push就是头插法建立单链表,pop操作就是逐个删除头结点,和单链表的实现没有区别。

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
// 链栈,不带头结点的情况
typedef int ElemType;
typedef struct LinkNode{
    ElemType data;//数据域
    struct LinkNode *next;
}LinkNode,*LinkStack;


bool InitStack4(LinkStack *s){
    *s=NULL;//栈空,不带头结点
    return true;
}
bool Push4(LinkStack *s,ElemType x){
    LinkNode *p=(LinkNode *)malloc(sizeof(LinkNode));
    if(p==NULL)
        return false;
    p->data=x;
    // 这一步很容易错
    p->next=(*s);
    (*s)=p;
    return true;
}
bool Pop4(LinkStack *s,ElemType *x){
    if((*s)==NULL)//空表
        return false;
    LinkNode *p=*s;
    *s=(*s)->next;
    *x=p->data;
    free(p);

    return true;
}
void printfStack4(LinkStack s){
    // s=NULL;
    LinkNode *p=s;
    while(p!=NULL){
        printf("%d->",p->data);
        p=p->next;
    }
    printf("\n");
}
void test4(){
    LinkStack s;
    InitStack4(&s);
    // printfStack4(s);
    Push4(&s,1);
    Push4(&s,2);
    printfStack4(s);
    ElemType x=0;
    Pop4(&s,&x);
    printfStack4(s);

}
void main(){
    test4();
}

队列

队列的顺序存储结构

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>

#define MaxSize 10//定义栈中元素的最大个数

typedef int ElemType;
typedef struct{
    ElemType data[MaxSize];
    int front,rear;//front指向队头元素,rear指向队尾的下一个位置(也就是下一个应该插入的位置
}SqQueue;

void InitSqQueue(SqQueue *Q){
    (*Q).rear=(*Q).front=0;
}
bool SqQueueEmpty(SqQueue Q){
    if(Q.rear==Q.front)
        return true;
    else
        return false;
}
// 入队
// 对于队满的判断,我们初始化的时候认为,队空是说队头指针等于队尾指针这就说明我们必须要牺牲掉一个存储单元来区分空和满的状态
// 链表的指针的走向和循环队列的相同
bool EnSqQueue(SqQueue *Q,ElemType x){
    if((*Q).front==((*Q).rear+1)%MaxSize)//队满:尾指针的后一个位置和头指针相等
        return false;
    (*Q).data[(*Q).rear]=x;
    (*Q).rear=((*Q).rear+1)%MaxSize;
    return true;
}

// 出队
bool DeSqQueue(SqQueue *Q,ElemType *x){
    if((*Q).rear==(*Q).front)
        return false;
    *x=(*Q).data[(*Q).front];
    (*Q).front=((*Q).front+1)%MaxSize;
    return true;
}
// 获取但不删除队头
bool GetHead(SqQueue Q,ElemType *x){
    if(Q.rear==Q.front){
        return false;
    }
    *x=Q.data[Q.front];
    return true;
}
void printfSqQueue(SqQueue Q){
    if(Q.rear==Q.front)//队空
        return;
    while(Q.rear!=Q.front){
        printf("%d<-",Q.data[Q.front]);
        Q.front=(Q.front+1)%MaxSize;
    }
    printf("\n");
}
void test5(){
    SqQueue Q;
    InitSqQueue(&Q);
    printfSqQueue(Q);
    for(int i=1;i<=4;i++){
        printf("入队顺序:%d\n",i);
        EnSqQueue(&Q,i);
    }
    printfSqQueue(Q);
    ElemType x=0;
    while(!SqQueueEmpty(Q)){
        DeSqQueue(&Q,&x);
        printf("出队顺序:%d\n",x);
    }
}
void main(){
    test5();
}

前面这种队列以牺牲一个存储空间为代价来区分队满和队空状态,如果不想要牺牲存储空间,可以增加一个size字段来动态维护当前队列的长度。这样初始化的时候rear=front=0;size=0,对于插入(删除)操作size++(size--);对于队满和(队空)操作size==MaxSize(size==0);

#define MaxSize 10//定义栈中元素的最大个数

typedef int ElemType;
typedef struct{
    ElemType data[MaxSize];
    int front,rear;//front指向队头元素,rear指向队尾的下一个位置(也就是下一个应该插入的位置
    int size;
}SqQueue;

还有一种方案就是设置一个状态值tag=0,对于删除操作令tag=0;对于插入操作令tag=1,这个时候队满的条件是front==rear&&tag==1,队空的条件是front==rear&&tag==0,总之无论是什么方案,至少都需要花费一定的空间的代价。实现如下:

#ifndef T1_H
#define T1_H

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>

#define MaxSize 10//定义栈中元素的最大个数

typedef int ElemType;
typedef struct{
    ElemType data[MaxSize];
    int front,rear;//front指向队头元素,rear指向队尾的下一个位置(也就是下一个应该插入的位置
    int tag;//0表示出队操作,1表示入队操作,只有在指针相同且是出队操作才表示空,在指针相同的入队操作表示满
}SqQueue;

void InitSqQueue(SqQueue *Q);//初始化
bool EnSqQueue(SqQueue *Q,ElemType x);//入队操作
bool DeSqQueue(SqQueue *Q,ElemType *x);//出队操作

#endif
#include "t1.h"

void InitSqQueue(SqQueue *Q){
    (*Q).rear=(*Q).front=0;
    (*Q).tag=0;
}
bool EnSqQueue(SqQueue *Q,ElemType x){
    if((*Q).rear==(*Q).front&&(*Q).tag==1)//队列满
        return false;

    (*Q).data[(*Q).rear]=x;
    (*Q).rear=((*Q).rear+1)%MaxSize;
    (*Q).tag=1;
    return true;
}
bool DeSqQueue(SqQueue *Q,ElemType *x){
    if((*Q).rear==(*Q).front&&(*Q).tag==0)//队空
        return false;

    (*Q).tag=0;
    *x=(*Q).data[(*Q).front];
    (*Q).front=((*Q).front+1)%MaxSize;
    return true;
}
void printfSqQueue(SqQueue Q){
    if(Q.rear==Q.front&&Q.tag==0)
        return;

    do{
        printf("%d<-",Q.data[Q.front]);
        Q.tag=0;
        Q.front=(Q.front+1)%MaxSize;
    }while(Q.rear!=Q.front&&Q.tag==0);
    printf("\n");
}
void test1(){
    SqQueue Q;
    InitSqQueue(&Q);
    
    ElemType x=0;
    scanf("%d",&x);
    while(x!=999){
        EnSqQueue(&Q,x);
        scanf("%d",&x);
    }
    // printf("%d-%d\n",Q.front,Q.rear);
    printfSqQueue(Q);
    DeSqQueue(&Q,&x);
    printfSqQueue(Q);
}
void main(){
    test1();
}

以上所有的代码都是基于rear指向队尾元素的后一个位置也就是下一个需要插入的位置,但是也有一种方案是rear直接指向队尾元素,这种的入队操作、初始化操作和判空操作会有所不同,具体来说:

入队操作:

Q.rear=(Q.rear+1)%MaxSize;
Q.data[Q.rear]=x

初始化操作:

Q.front=0;
Q.rear=MaxSize-1

判空条件:

(Q.rear+1)%MaxSize==front

队满操作:

和上面一个,要么牺牲一个存储单位,要么增加辅助变量。

队列的链式存储结构

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>

typedef int ElemType;
typedef struct LinkNode{//链式队列结点
    ElemType data;
    struct LinkNode *next;
}LQNode;
typedef struct{//链式队列
    LQNode *front,*rear;
}LQueue;
// 带头结点的初始化
void InitLQueue_withHead(LQueue *Q){
    (*Q).front=(LQNode *)malloc(sizeof(LQNode));
    (*Q).rear=(*Q).front;
    (*Q).front->next=NULL;
}
void InitLQueue_withoutHead(LQueue *Q){
    (*Q).front=NULL;
    (*Q).rear=NULL;
}
bool LQueueEmpty(LQueue Q){
    if(Q.front==NULL)
        return true;
    return false;
}

// 入队
void EnLQueue_withHead(LQueue *Q,ElemType x){
    LQNode *s=(LQNode *)malloc(sizeof(LQNode));
    s->data=x;
    s->next=NULL;
    (*Q).rear->next=s;
    (*Q).rear=s;//修改表尾指针
}
void EnLQueue_withoutHead(LQueue *Q,ElemType x){
    LQNode *s=(LQNode *)malloc(sizeof(LQNode));
    s->data=x;
    s->next=NULL;
    if((*Q).front==NULL){
        (*Q).front=s;
        (*Q).rear=s;
    }else{
        (*Q).rear->next=s;
        (*Q).rear=s;//修改表尾指针
    }
}
// 出队
bool DeLQueue_withHead(LQueue *Q,ElemType *x){
    if((*Q).front==(*Q).rear)//空队
        return false;

    LQNode *p=(*Q).front->next;
    *x=p->data;
    (*Q).front->next=p->next;
    if((*Q).rear==p)//最后一个结点出队
        (*Q).rear=(*Q).front;
    free(p);
    return true;
}
bool DeLQueue_withoutHead(LQueue *Q,ElemType *x){
    if((*Q).front==NULL)//空队列
        return false;
    LQNode *p=(*Q).front;
    *x=p->data;
    (*Q).front=p->next;//对于不带头结点和带头结点,这一部分是有区别的
    if(p==(*Q).rear){//说明这是最后一个结点
        (*Q).rear=NULL;
    }
    free(p);
    return true;
}
// printf:两个打印操作的区别不大,可以合并为一个打印操作
void printfLQueue_withHead(LQueue Q){
    if(Q.front==Q.rear)
        return;

    LQNode *p=Q.front->next;
    while(p!=NULL){
        printf("%d<-",p->data);
        p=p->next;
    }
    printf("\n");
}
void printfLQueue_withoutHead(LQueue Q){
    if(Q.front==NULL)
        return;
    LQNode *p=Q.front;
    while(p!=NULL){
        printf("%d<-",p->data);
        p=p->next;
    }
    printf("\n");
}
void test6(){
    LQueue Q;
    InitLQueue_withHead(&Q);
    ElemType x=0;
    scanf("%d",&x);
    while(x!=999){
        EnLQueue_withHead(&Q,x);
        scanf("%d",&x);
    }
    printfLQueue_withHead(Q);
    DeLQueue_withHead(&Q,&x);
    printfLQueue_withHead(Q);

    LQueue L;
    InitLQueue_withoutHead(&L);
    scanf("%d",&x);
    while(x!=999){
        EnLQueue_withoutHead(&L,x);
        scanf("%d",&x);
    }
    printfLQueue_withoutHead(L);
    DeLQueue_withoutHead(&L,&x);
    printfLQueue_withoutHead(L);
}
void main(){
    test6();
}

队列长度:

对于循环队列,队列长度=(Q.rear+MaxSize-Q.front)%MaxSize

对于链表存储的队列,可以在定义数据结构的时候,增加一个辅助变量size来维护队列长度

typedef int ElemType;
typedef struct LinkNode{//链式队列结点
    ElemType data;
    struct LinkNode *next;
}LQNode;
typedef struct{//链式队列
    LQNode *front,*rear;
    int size;//队列长度
}LQueue;

栈和队列的应用

栈在括号匹配中的应用

思路:遇到左括号入栈

遇到有括号,出栈匹配,同一类型括号且左右括号匹配成功,其他失败

全部匹配成功且栈为空,匹配成功

#ifndef LISTACK_H
#define LISTACK_H
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
// 链栈,不带头结点的情况
typedef char ElemType;
typedef struct LinkNode{
    ElemType data;//数据域
    struct LinkNode *next;//这里的定义是有问题的,在栈中应该设计一个top指针,但是考虑到手比脑快代码都写完了就不改了,介意的话把next改名为top就可以了
}LinkNode,*LinkStack;

bool InitStack4(LinkStack *s);//初始化不带头结点的栈
bool Push4(LinkStack *s,ElemType x);//入栈
bool Pop4(LinkStack *s,ElemType *x);//出栈
void printfStack4(LinkStack s);//打印
bool EmptyStack4(LinkStack s);//空栈
#endif
#include "listack.h"


bool InitStack4(LinkStack *s){
    *s=NULL;//栈空,不带头结点
    return true;
}
bool EmptyStack4(LinkStack s){
    if(s==NULL){
        return true;
    }
    return false;
}
bool Push4(LinkStack *s,ElemType x){
    LinkNode *p=(LinkNode *)malloc(sizeof(LinkNode));
    if(p==NULL)
        return false;
    p->data=x;
    // 这一步很容易错
    p->next=(*s);
    (*s)=p;
    return true;
}
bool Pop4(LinkStack *s,ElemType *x){
    if((*s)==NULL)//空表
        return false;
    LinkNode *p=*s;
    *s=(*s)->next;
    *x=p->data;
    free(p);

    return true;
}
void printfStack4(LinkStack s){
    // s=NULL;
    LinkNode *p=s;
    while(p!=NULL){
        printf("%c->",p->data);
        p=p->next;
    }
    printf("\n");
}
// void test4(){
//     LinkStack s;
//     InitStack4(&s);
//     // printfStack4(s);
//     Push4(&s,1);
//     Push4(&s,2);
//     printfStack4(s);
//     ElemType x=0;
//     Pop4(&s,&x);
//     printfStack4(s);

// }
// void main(){
//     test4();
// }
#include "listack.h"
// 假设字符串中只有三种括号 {} [] ()
bool ifMatch(char c[],int len){
    if(len==0)
        return true;
    if(len%2!=0)//括号一定是成对的
        return false;

    LinkStack s;
    InitStack4(&s);
    for(int i=0;i<len;i++){
        if(c[i]=='{'||c[i]=='('||c[i]=='['){//左括号入栈
            Push4(&s,c[i]);
        }else{
            if(EmptyStack4(s))//如果是右括号需要被匹配但是栈空,直接返回false
                return false;
            char temp=' ';
            Pop4(&s,&temp);
            if(c[i]=='}'&&temp!='{')
                return false;
            else if(c[i]==']'&&temp!='[')
                return false;
            else if(c[i]==')'&&temp!='(')
                return false;   
        }
    }
    if(!EmptyStack4(s))//所有都正常匹配,但是左括号还有多余的
        return false;

    return true;

}
void test7(){
    char c[11]="((((()))){}";
    if(ifMatch(c,11))
        printf("YES");
    else
        printf("NO");
}
void main(){
    test7();
}

栈在括号匹配中的应用其实不仅仅是局限在括号匹配,对于常遇到的检验对称性的数据,都可以使用类似的思路去实现,比如检验回文序列等,在不同的应用中会有不同的表达,但是总体都是一个思路。

栈在表达式求值中的应用

  • 实现从中缀表达式转换到后缀表达式

虽然这里使用的是c语言编写的代码,但是我个人更加建议使用更高级的语言去实现这个代码,因为比如说c不能直接给出数组长度,我们需要用sizeof(ElemType[])/sizeof(ElemType)才可以实现求值长度,但是使用更高级语言就可以直接len(array)多方便。

#ifndef LISTACK_H
#define LISTACK_H
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
// 链栈,不带头结点的情况
typedef char ElemType;
typedef struct LinkNode{
    ElemType data;//数据域
    struct LinkNode *next;//这里的定义是有问题的,在栈中应该设计一个top指针,但是考虑到手比脑快代码都写完了就不改了,介意的话把next改名为top就可以了
}LinkNode,*LinkStack;

bool InitStack4(LinkStack *s);//初始化不带头结点的栈
bool Push4(LinkStack *s,ElemType x);//入栈
bool Pop4(LinkStack *s,ElemType *x);//出栈
void printfStack4(LinkStack s);//打印
bool EmptyStack4(LinkStack s);//空栈
#endif
#include "listack.h"


bool InitStack4(LinkStack *s){
    *s=NULL;//栈空,不带头结点
    return true;
}
bool EmptyStack4(LinkStack s){
    if(s==NULL){
        return true;
    }
    return false;
}
bool Push4(LinkStack *s,ElemType x){
    LinkNode *p=(LinkNode *)malloc(sizeof(LinkNode));
    if(p==NULL)
        return false;
    p->data=x;
    // 这一步很容易错
    p->next=(*s);
    (*s)=p;
    return true;
}
bool Pop4(LinkStack *s,ElemType *x){
    if((*s)==NULL)//空表
        return false;
    LinkNode *p=*s;
    *s=(*s)->next;
    *x=p->data;
    free(p);

    return true;
}
void printfStack4(LinkStack s){
    // s=NULL;
    LinkNode *p=s;
    while(p!=NULL){
        printf("%c->",p->data);
        p=p->next;
    }
    printf("\n");
}
// void test4(){
//     LinkStack s;
//     InitStack4(&s);
//     // printfStack4(s);
//     Push4(&s,1);
//     Push4(&s,2);
//     printfStack4(s);
//     ElemType x=0;
//     Pop4(&s,&x);
//     printfStack4(s);

// }
// void main(){
//     test4();
// }
#include "listack.h"

/*
初始化一个栈用来保存暂时还不能确定运算顺序的运算符
从左到右处理各个元素,直到末尾
 如果遇到操作数,直接加入后缀表达式
 如果遇到界限符,"(",直接入栈,遇到")"则依次弹出站内运算符并加入后缀表达式,直到弹出"("为止
 遇到运算符,依次弹出栈中优先级高于或者等于当前运算符的所有运算符,并依次加入后缀表达式中,若碰到"("或者栈空就停止,再把当前的运算符入栈。
处理完所有的字符后将栈中剩余运算符依次弹出,加入到或后缀表达式中

*这里要注意的是,连续弹出运算符都是依次弹出的
优先级高于或者等于的都要弹出,除非是带括号(
*/
bool ifNum(char c);
// 采用16进制,也就是A表示10,以此类推,只表示16个数
void postfitExpression(char c[],char result[],int length){
    LinkStack s;//初始化一个空栈来存储还不能确定顺序的运算符
    InitStack4(&s);
    int index=0;
    char temp=' ';//弹出的数据存储

    LinkStack l;
    InitStack4(&l);//用来临时存储低优先级的运算符
    for(int i=0;i<length;i++){
        if(ifNum(c[i])){//如果是操作数,直接加入后缀表达式
            result[index]=c[i];
            // printf("------------");
            index++;
            // index++;
        }else if(c[i]=='('){
            Push4(&s,c[i]);
        }else if(c[i]==')'){
            // 依次弹出栈中的运算符,直到遇到第一个'('
            temp=' ';//避免脏数据
            while(temp!='('&&!EmptyStack4(s)){
                // if(EmptyStack4(s))
                //     break;
                Pop4(&s,&temp);
                if(temp!='(')
                    result[index++]=temp;
            }
        }else{//除了数字和左右括号,其他都是运算符,默认不使用大括号和花括号
            // 遇到运算符,依次弹出栈中优先级高于或者等于当前运算符的所有运算符,并依次加入后缀表达式中,若碰到"("或者栈空就停止,再把当前的运算符入栈。
            temp=' ';//避免脏数据
            while(temp!='('&&!EmptyStack4(s)){
                Pop4(&s,&temp);
                if(c[i]=='+'||c[i]=='-'){//所有的运算符都是相同或者高的优先级
                    if(temp!='(')
                        result[index++]=temp;
                }else{
                    if(temp=='+'||temp=='-')
                        Push4(&l,temp);
                    else if(temp=='*'||temp=='/')
                        result[index++]=temp;
                }
            }
            if(temp=='(')//如果是(,就要放回去,可以直接用getTop(),但是这里没有实现这个函数就麻烦点
                Push4(&s,temp);
            while(!EmptyStack4(l)){//把低优先级的依次放回原来的栈中
                Pop4(&l,&temp);
                Push4(&s,temp);
            }
            Push4(&s,c[i]);
        }
    }
    // 处理完所有的字符后将栈中剩余运算符依次弹出,加入到或后缀表达式中
    while(!EmptyStack4(s)){
        Pop4(&s,&temp);
        result[index++]=temp;
    }
    // for(int i=0;i<length;i++){
    //     printf("%c",result[i]);
    // }
    // return result;
}

bool ifNum(char c){
    if(c>='0'&&c<='9')//0-9
        return true;
    else if(c>='A'&&c<='E')//A-E
        return true;
    else
        return false;
}

void test8(){
    char c[]="((2/(7-(1+1)))*3)-(2+(1+1))";
    int length=27;
    char result[27]=".";
    postfitExpression(c,result,length);
    for(int i=0;i<length;i++){
        printf("%c",result[i]);
    }
}
void main(){
    test8();
}


少见的输出结果展示:

PS D:\workspaces\CWorkspace\project408\chapter3> cd "d:\workspaces\CWorkspace\project408\chapter3\" ; if ($?) { gcc *.c -o postfit_expression } ; if ($?) { .\postfit_expression }
2711+-/3*211++-
PS D:\workspaces\CWorkspace\project408\chapter3>
  • 利用后缀表达式计算
/*
遇到操作数,入栈
遇到运算符,两个元素出栈,运算结果入栈
*/
void calculation(char result[],int length){
    
}
  • 中缀表达式的计算

中缀表达式计算=中缀变后缀+利用后缀计算

/*
用栈实现中缀表达式的计算
初始化两个栈,操作数栈和运算符栈
	若扫描到操作数,压入操作数栈
	若扫描到运算符或者界限符,按照“中缀转到后缀”的相同逻辑压入运算符栈(期间也会弹出运算符,每弹出一个运算符就需要弹出两个操作数栈的元素来进行相应的运算,运算结果再压回操作数栈中,注意先弹出的元素在运算符左边,后弹出的在运算符右边)
*/

栈在递归调用中的应用

队列在层次遍历中的应用

树的层次遍历、图的广度优先遍历都是相同的思想

/*
根节点入队
队列的第一个节点出队,并且访问其直接后继结点,如果有直接后继结点就依次入队
循环以上步骤直到队空
*/
数据结构,C语言,停车场管理,栈,链队列,带有题目及注释 这还是一个数据结构作业 阅读详情

相关推荐

stdbool.h头文件

stdbool.h头文件

C语言中的stdbool.h头文件

Win7下安装的VS2015中的stdbool.h的位置为: F:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\includestdbool.h的文件内容为:// // stdbool.h // // Copyright (c) Microsoft Corporation. All rights reserved. // //

大自然的代码 3万+

头文件stdbool.h

编译器不支持2113c99标准,5261_Bool是在c99标准以后才有的。解决 Dve c++或 vc6++不能编译 _Bool类型问题 。将头文件下载下来的头文件放在编译器头文件安装位置可以。也可以放在编写保存文件夹中。 在程序中输入#include 即可

C语言的布尔类型

在C语言标准(C89)没有定义布尔类型,所以C语言判断真假时以0为假,非0为真。所以我们通常使用逻辑变量的做法: //定义一个int类型变量,当变量值为0时表示false,值为1时表示true int flag; flag = 0; //...... flag = 1; if( flag ) { //...... } 但这种做法不直观,而且没有明确flag一定是布尔值。所以我们又借助C语

4073

stdbool.h(c语言库文件)

stdbool.h(c语言库文件) stdbool.h(c语言库文件)

stdbool.zip_stdbool_stdbool.h_stdbool.h下载_stdbool下载

网上其他网站下载的STDBOOL.H文件,上传,方便大家下载使用

C语言数据结构与算法(栈和队列)

数据结构与算法中的栈和队列经常作为解决问题的一个辅助工具,能为难题打开一道突破口。

2301_81978155的博客 1297

Python 列表(list)所有方法超全汇总

以上就是 Pythonlist 列表全部 11 个内置方法的完整汇总,全覆盖、无遗漏。掌握所有列表方法,基本可以应对 99% 的列表操作场景,无论是日常开发、数据分析还是算法刷题都能高效编码。

jdksjw的博客 235

栈和队列的基础知识,C语言实现及经典OJ题

堆栈又名栈(stack),它是一种运算受限的线性表。限定。

2303_81216104的博客 929

MuJoCo 动捕接口 Mocap 直接操控机械臂(附代码)

动作捕捉(Motion Capture,简称 Mocap)是一种记录并处理人或物体动作的技术,在影视、游戏、机器人等领域应用广泛。通过上下左右以及alt_l,alt_r可以控制hand这个hody跟着mocap进行同步,这里将quat固定为Z朝下。首先在 scene.xml 中修改添加 mocap 和 equality。下面介绍如何配置 Mocap 以及使用按键进行末端控制。控制核心代码,通过按键控制mocap的pos和quat。

darcsdn 879

PG-FP6编程器错误代码解析与高效排障实战指南

在嵌入式系统开发与量产烧录中,编程器是连接开发环境与目标硬件的重要桥梁。其工作原理是通过特定的通信协议(如UART、SWD)与微控制器(MCU)建立连接,完成程序代码的写入、擦除与校验。这项技术的核心价值在于确保固件能够准确、可靠地部署到硬件中,是产品从原型到量产的关键环节。在实际的工程实践中,尤其是在使用瑞萨(Renesas)PG-FP6这类编程器进行调试或批量生产时,工程师常会遇到各种通信失败、编程验证错误或电源异常等问题,这些问题往往以特定的错误代码形式呈现。深入理解这些错误代码背后的硬件连接、电源时

weixin_34387468的博客 581

C语言栈和队列大大大礼包【栈实现队列、队列实现栈、再附赠一个循环队列,啊啊啊啊】

C语言实现栈和队列,栈实现队列,队列实现栈,循环链表的实现。数据结构与算法初阶。leetcode刷题

qq_63188326的博客 140

【AI实战】用Coze工作流打造抖音视频文案提取神器——从单链接到批量处理的进阶指南

本文详细介绍了如何利用Coze工作流打造抖音视频文案提取工具,从单链接处理到批量提取的进阶指南。通过AI技术和工作流的结合,用户可以高效提取抖音视频的ASR和OCR文本,大幅提升内容创作效率。文章还涵盖了性能优化、异常处理及实际应用场景扩展,助力开发者快速实现抖音文案自动化提取。

weixin_29210759的博客 281

队列和栈C语言 超详细

/栈//地址int top;//记录位置//储存}ST;//初始化assert(ps);//增加assert(ps);if (ps->top == ps->capacity)//储存满了,要扩容//定义一个变量,尽量先不改变if (tmp == NULL)//判断扩容是否成功 不成功退出exit(-1);//尾插ps->top++;//判空assert(ps);//打印assert(ps);//检查队列是否为空i <ps->top;i++)

weixin_74447672的博客 174

装配完整性检查系统:基于YOLOv10的螺丝/零件缺失自动检测(含UI界面与完整代码)

建议自行采集装配场景数据,标注缺失螺丝、错误零件等,模拟真实缺陷。手机/工业相机采集图像;使用LabelImg进行目标标注;转换为 YOLO 格式。本文构建了一个完整的装配完整性检测系统,基于 YOLOv10 实现高精度螺丝缺失检测,并使用 PyQt5 构建了图形界面,实现一键导入与可视化检测流程,适用于工业质检自动化部署。项目可灵活扩展至零件缺失、错装、错位、顺序错误等检测场景,是深度学习在制造业中落地的典型应用案例之一。

YOLO 703

解决k8s核心组件calico pod资源不创建问题

解决k8s核心组件calico pod资源不创建问题 1.问题描述 由于K8S集群Master节点故障,导致calico网络组件虽然处于Running状态,但是一直无法准备就绪,如下图所示 calico-node-lpt7h运行在master节点,第一时间紧急处理方法就是将其pod删除,让K8S自动重建该pod,使整个集群快速恢复 但是就当我将calico-node-lpt7h pod删除后,该pod始终无法自建,就好像是从来没有这个pod似的 2.解决方法 期初排查时,我觉得可能是由于当前master

江晓龙的博客 4808

数据结构(C语言版)-2.栈和队列

数据结构(C语言版)-2.栈和队列

yang_pi_pi的博客 490

中科大大数据学院2023年保研夏令营机试题目【无offer,直接放题了~】(2023.07.22下午14:35-17:35考试)

给定一串数字,最后一个数是0表示结尾,表示数字串的终止,为无效数字。将该数字串存储在双向链表中,判断是否为回文串,若是,则输出Yes,否则输出No.

m0_51339444的博客 1922

数据结构之栈和队列算法题

思路:两个栈pushst popst 然后往pushst里面push ,每当要出队列或者要去队头数据时,就返回popst的栈顶数据,如果popst为空,就一口气把pushst里面的数据全塞进去。(数组实现)思路:创建K(存有效数据的大小)+1的长度,两个指针(严格来讲应该是下标)指向头和尾。首先说明一点,这只是对栈和队列熟练度的考察,并不是栈的更好地实现方式。思路:两个队列,保证有一个队列为空,然后其余操作基于空队列实现。这一题就是反过来用栈实现队列,要实现后进先出。栈的实现在上面有,不重复拷贝了。

2403_87718362的博客 673

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

链式栈与链式队列

链式队列是一种队列,其元素使用链表结构存储,每个节点包含存储的数据和指向下一个节点的指针。链式队列的队首和队尾分别由链表的头节点和尾节点来表示。

m0_71637218的博客 854

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

C语言使用栈和队列实现二进制与十进制的互转(带小数)

使用栈和队列的特性来实现进制转换 需要看普通C语言版的看这里 C语言实现二进制与十进制的互转(带小数) 全部代码 #include <stdio.h> #include <stdlib.h> #include <math.h> #define M 100 typedef long ElemType; // 栈 typedef struct { El...

一碗单炒饭的专栏 4319

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

C语言数据结构之精简讲

数据结构是计算机科学的核心基础,研究数据的组织、存储和操作方式。算法+数据结构=程序。数据结构分为逻辑结构(集合、线性、树形、图形)和物理结构(顺序、链式、索引、散列存储)。线性结构中最基础的数组具有随机访问高效(O(1))但插入删除低效的特点,可通过动态数组实现扩容功能。理解数据结构需要掌握内存存储原理,其本质与编程语言无关,如同数学定理与表达语言的关系。高效的数据结构设计能显著提升程序性能,是解决复杂问题的关键。

2301_76633821的博客 2385

数据结构和算法学习记录——栈和队列作业(实现链栈上的进栈、实现链栈上的退栈、实现链队上的入队列)

数据结构和算法学习记录——栈和队列作业(实现链栈上的进栈、实现链栈上的退栈、实现链队上的入队列) 题目来自:《数据结构》大连理工大学出版社(2019.8第一版)

li13437542099的博客 359

严蔚敏版数据结构(C语言版)算法实现代码

严蔚敏版数据结构(C语言版)算法实现代码数据结构(C语言版)代码实现线性表顺序表 数据结构(C语言版)代码实现 部分采用C++的语法实现 线性表 顺序表与链表 顺序表 代码如下: #include <bits/stdc++.h> using namespace std; #define MaxSize 100 #define ElemType int #define Status int #define LIST_INIT_SIZE 100 #define LISTINCREMENT 10

weixin_45741097的博客 1万+
上一篇: 数据结构应用题第二章线性表代码
下一篇: 数据结构应用题第三章栈和队列代码c
@@老胡
博客等级 码龄7年 291粉丝 184原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值