数据结构之栈

在这里插入图片描述

1. 顺序栈

//顺序栈
#include<iostream>
using namespace std;
#define Maxsize 50
#define ElemType int

typedef struct
{
    ElemType data[Maxsize]; //存放栈中元素
    int top;                //栈顶指针
} SqStack;

//初始化
void InitStack(SqStack &S)
{
    S.top = -1;
}

//判断栈空
bool StackEmpty(SqStack S)
{ 
    if (S.top == -1)//栈空
        return true;
    else
        return false;
}

//进栈
bool Push(SqStack &S, ElemType x)
{
    if (S.top == Maxsize - 1) //栈满
        return false;
    S.data[++S.top] = x; 
    return true;
}

//出栈
bool Pop(SqStack &S, ElemType& x)
{
    if (S.top == -1) //栈空
        return false;
    x=S.data[S.top--];
     return true;
}

//读栈顶元素
bool GetTop(SqStack S, ElemType& x)
{
    if (S.top == -1)//栈空
        return false;
    x = S.data[S.top]; return true;
}

void test01(){
 SqStack s;
 InitStack(s);
 //bool key=true;
 //压栈
 cout<<"进栈顺序为: ";
 for(int i=1;i<10;i++){
    Push(s,i);//在C++(以及许多其他编程语言)中,当你调用一个返回布尔值(bool)的函数时,你可以选择是否显式地接收这个返回值
    cout<<s.data[s.top]<<" ";
 }
cout<<endl;

//弹栈
int a=0;
 Pop(s,a);
 cout<<"弹栈元素为: "<<a<<endl;
 cout<<"出栈顺序为: ";
  for(int i=s.top;i>=0;i--){
    cout<<s.data[i]<<" ";
 }
 cout<<endl;

//读栈顶
int x=0;
GetTop(s,x);
cout<<"栈顶元素为: "<<x<<endl;
}
int main(){
    test01();
   // system("pause");
    return 0;
}

在这里插入图片描述

2. 共享栈

在这里插入图片描述

3. 链栈

在这里插入图片描述

//链栈,默认没有头节点,且只能在首部插入和删除
#include<iostream>
using namespace std;
typedef struct link{
    int data;
    struct link* next;

}*linklist;


 linklist push(linklist s,int a){
  //创建新节点
  linklist p=(linklist)malloc(sizeof(link));
  p->data=a;

  //新节点的指针域指向头指针一开始指向
  p->next=s;

  //头指针指向新节点
  s=p;
  return s;
}

linklist pop(linklist s){
    if(s){
          linklist p;
          p=s;
          s=s->next;
          cout<<"弹栈元素为:"<<p->data<<" ";

          if(s){
            cout<<"新栈顶元素为"<<s->data<<endl;
          }
          else{
            cout<<"栈空了"<<endl;
          }
          ///free(p);
    }
    else{
        cout<<"栈内没有元素"<<endl;
        return s;
    }
    return s;
}
void test01(){
linklist s=NULL;
s=push(s,1);
s=push(s,2);
s=push(s,3);
s=push(s,4);
s=pop(s);
s=pop(s);
s=pop(s);
s=pop(s);

}


int main(){
    test01();
    //system("pause");
    return 0;
}

在这里插入图片描述

4. 栈的应用

4.1括号匹配
在这里插入图片描述

//栈应用:括号匹配
 #include <iostream>
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 10
using namespace std;

typedef struct {
   char data[MaxSize];
   int top;
}SqStack;

//初始化栈,这里栈空s.top=0,要注意是:入栈时先赋值再栈顶指针top++,出栈时还是先保存值再top--
void IniStack(SqStack &s)
{
    s.top=0;
}

//判断栈是否为空
bool StaxkEmpty(SqStack s){
   if(s.top==0)
    return true;
   else
    return false;
}

//新元素入栈
bool Push(SqStack &s,char x){
    //判断栈是否满
    if (s.top == MaxSize) //栈满
        return false;
    s.data[s.top]=x;
    s.top++;
    return true;
}

//栈顶元素出栈,用x返回
bool Pop(SqStack &s,char &x){
    //判断栈是否空
    if (s.top == 0) //栈空
        return false;
    x=s.data[s.top-1];
    s.top--;
    return true;
}

//匹配算法
bool bracketCheck(char str[],int length){
     SqStack s;
     IniStack(s);
     for(int i=0;i<length;i++){
        if(str[i]=='('||str[i]=='{'||str[i]=='['){
            Push(s,str[i]); //如果是左括号,入栈
           }
           //这里的逻辑是先判断错误情形,最后剩余的就是正确的
        else{
            if(StaxkEmpty(s))//如果是右括号并且栈为空
             return false;
           char topELem;
           Pop(s,topELem);
      
           if(str[i]==')'&&topELem!='(')
            return false;
           if(str[i]=='}'&&topELem!='{')
            return false;
           if(str[i]==']'&&topELem!='[')
            return false;
        }
       }
       //最后再判断栈是否为空
       return StaxkEmpty(s);
}

int main()
{    char str[MaxSize];
     int n;
     scanf("%s",str);
     scanf("%d",&n);

    if(bracketCheck(str,n))
        printf("匹配成功");
    else
        printf("匹配失败");
    return 0;
}


在这里插入图片描述
在这里插入图片描述

4.2表达式求值
首先明白啥是中缀、前缀和后缀表达式,啥是中缀转后缀和后缀转中缀啥是中缀转前缀和前缀转中缀,他们的手算逻辑知不知道?然后对于机算逻辑主要明白3条:

  • 中缀转后缀中缀转前缀的机算逻辑
  • 后缀表达式求值前缀表达式求值的机算逻辑
  • 中缀表达式求值的机算逻辑

在这里插入图片描述
首先是中缀转后缀和中缀转前缀
在这里插入图片描述

在这里插入图片描述

下面是
**真题**

在这里插入图片描述

//目的:为了不用运算符也能无歧义的表达运算顺序(波兰数学家)
//实现中缀转后缀的机算
#include<stdio.h>
#define ElemType char
#define MaxSize 50
//定义顺序栈
typedef struct {
	ElemType data[MaxSize];
	int top;
}SqStack;

//一些基本操作
void initStack(SqStack& S)
{
	S.top = -1;   //初始化栈顶指针
}

bool StackEmpty(SqStack S)
{
	if (S.top == -1)   //栈空
		return true;
	else
		return false;  //栈不空
}

bool Push(SqStack& S, ElemType x)
{
	if (S.top == MaxSize - 1)      //栈满 不能执行入栈操作
		return false;
	S.top++;                      //指针先加1,再入栈
	S.data[S.top] = x;
	return true;
}

bool Pop(SqStack& S, ElemType& x)
{
	if (S.top == -1)              //栈空 不能执行出栈操作
		return false;
	x = S.data[S.top];            //先出栈 指针再减1
	S.top--;
	return true;
}



//中缀-------->后缀
//遇到操作数直接加入后缀表达式
//遇到界限符(直接入栈,遇到)依次弹出栈内运算符并加入后缀表达式直到弹出(为止,(和)去掉
/*遇到运算符:
	1.如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
	2.否则,若优先级比栈顶运算符的高,也将运算符压入s1(注意转换为前缀表达式时是优先级较高或相同,而这里则不包括相同的情况);
	3.否则,依次弹出优先级比它高的运算符*/
void test01(){
	SqStack S;
	initStack(S);
	char NifixExpression[] = { '(','(','A','+','B',')','*','C',')','-','(','E','-','F',')','\0' };//中缀,在字符数组最后添加'\0',作为结束标志
	char Prefixxpression[60];    //后缀
	int index = 0;//后缀表达式索引
	char* p = NifixExpression;//指针依次遍历中缀表达式
	while (*p!='\0')
	{
		if (*p == '(')         //如果为左括号,直接入栈
		{
			Push(S, *p);
			p++;
		}
		else if (*p == ')')//若为右括号,依次弹出栈中运算符,直到'(',并删除'('和')'
		{
			while (S.data[S.top] != '(')
			{
				char temp;
				Pop(S, temp);
				if (temp == '+' || temp == '-' || temp == '*' || temp == '/')
				{
					Prefixxpression[index] = temp;
					index++;
				}
			}
			char temp;
			Pop(S, temp);     //把左括号也出栈
			p++;
		}
		else if (*p >= 'A' && *p <= 'Z') //这里用大写字母代替表达式中的数字,为大写字母则直接进入后缀表达式
		{
			Prefixxpression[index] = *p;
			index++;
			p++;
		}
		else
		{
			if (*p == '+' || *p == '-'){
				//如果遍历到'+''-',且栈为空或栈顶为'(',直接入栈
				if (S.data[S.top] == '('||StackEmpty){
					Push(S, *p);
					p++;
				}else {
					while (S.data[S.top] != '('&&!StackEmpty)//依次弹出较高优先级运算符,直到'('或者栈空停止,再将它入栈
					{
						char temp;
						Pop(S, temp);
						Prefixxpression[index] = temp;
						index++;
					}
                    Push(S, *p);
					p++;
				}
			}
			else//  遇到*和/运算符
			{
				Push(S, *p);
				p++;
			}
		}
	}
	if (!StackEmpty(S))          //若栈不为空,依次弹出其中的运算符
	{
		while (S.top != -1)
		{
			char temp;
			Pop(S,temp);
			Prefixxpression[index] = temp;
			index++;
		}
	}
	Prefixxpression[index] = '\0';         //在字符数组后加'\0',作为结束标志
	printf("中缀表达式为:%s",NifixExpression);
	printf("\n");
	printf("后缀表达式为:%s", Prefixxpression);
}
 



int main()
{
	test01();
	return 0;
	
	
}

其次是后缀、中缀、前缀表达式的机器计算
在这里插入图片描述
在这里插入图片描述

// 实现中缀、后缀计算的栈处理
#include <stdio.h>
#include <iostream>
using namespace std;
#define ElemType char
#define MaxSize 50
// 定义顺序栈
typedef struct
{
    ElemType data[MaxSize];
    int top;
} SqStack;

void initStack(SqStack &S)
{
    S.top = -1; // 初始化栈顶指针
}

bool StackEmpty(SqStack S)
{
    if (S.top == -1) // 栈空
        return true;
    else
        return false; // 栈不空
}

bool Push(SqStack &S, ElemType x)
{
    if (S.top == MaxSize - 1) // 栈满 不能执行入栈操作
        return false;
    S.top++; // 指针先加1,再入栈
    S.data[S.top] = x;
    return true;
}

bool Pop(SqStack &S, ElemType &x)
{
    if (S.top == -1) // 栈空 不能执行出栈操作
        return false;
    x = S.data[S.top]; // 先出栈 指针再减1
    S.top--;
    return true;
}

bool GetPop(SqStack S, ElemType &x)
{
    if (S.top == -1) // 栈空报错
        return false;
    x = S.data[S.top]; // 用x存储栈顶元素
    return true;
}

char *caculator(SqStack &S, char *p)
{
    char temp1, temp2, result;
    int a, b, sum;
    Pop(S, temp1);
    Pop(S, temp2);
    if (*p == '+')
    {
        a = temp1 - '0';
        b = temp2 - '0';
        sum = a + b;
        result = sum + '0';
        Push(S, result);
        p++;
    }
    if (*p == '-')
    {
        a = temp1 - '0';
        b = temp2 - '0';
        sum = b - a;
        result = sum + '0';
        Push(S, result);
        p++;
    }
    if (*p == '*')
    {
        a = temp1 - '0';
        b = temp2 - '0';
        sum = a * b;
        result = sum + '0';
        Push(S, result);
        p++;
    }
    if (*p == '/')
    {
        a = temp1 - '0';
        b = temp2 - '0';
        sum = b / a;
        result = sum + '0';
        Push(S, result);
        p++;
    }
    return p;
}
// 后缀计算:遇到操作数直接入栈,遇到运算符先弹栈2个运算符,计算,再将计算的结果入栈
void houzhui()
{
    SqStack S;
    initStack(S);
    char PostfixExpression[] = {'3', '6', '+', '8', '*', '9', '4', '-', '-', '\0'}; // 这是后缀表达式AB+C*EF--   67
    char *p = PostfixExpression;
    while (*p != '\0')
    {
        if (*p >= '0' && *p <= '9')
        {
            Push(S, *p);
            p++;
        }
        else
        {
            p = caculator(S, p);
        }
    }
    char x;
    GetPop(S, x);
    int a;
    a = x - '0';
    cout << a << endl;
}

// 中缀表达式计算:初始化两个栈,一个是操作数栈,一个是运算符栈
/*若扫描到操作数直接压入操作数栈,若扫描到运算符或者界限符,
按照中缀转后缀相同的逻辑压入运算符栈,期间也会弹出运算符,若弹出一个运算符
那么需要弹出两个操作数栈的栈顶元素并执行相应的运算并将结果压入操作数栈。*/
void zhongzhui()
{
    // 初始化两个栈,一个是操作数栈,一个是运算符栈
    SqStack S1;
    initStack(S1); // 操作数栈
    SqStack S2;
    initStack(S2); // 运算符栈
    // 若扫描到操作数直接压入操作数栈,((A+B)*C)-(E-F)
    char NifixExpression[] = {'(', '(', '1', '+', '2', ')', '*', '3', ')', '-', '(', '3', '-', '2', ')', '\0'}; // 8
    char *p = NifixExpression;
    while (*p != '\0')
    {
        if (*p >= '0' && *p <= '9')
        {
            Push(S1, *p);
            p++;
        }
        // 若扫描到运算符或者界限符,按照中缀转后缀相同的逻辑压入运算符栈,
        // 期间也会弹出运算符,若弹出一个运算符那么需要弹出两个操作数栈的栈顶元素并执行相应的运算并将结果压入操作数栈
        else if (*p == '(') // 如果为左括号,直接入栈
        {
            Push(S2, *p);
            p++;
        }
        else if (*p == ')') // 若为右括号,依次弹出栈中运算符,直到'(',并删除'('--用出栈不保存数据实现
        {
            while (S2.data[S2.top] != '(')
            {
                char temp;
                Pop(S2, temp);
                char *k = &temp;
                if (temp == '+' || temp == '-' || temp == '*' || temp == '/')
                {
                    k = caculator(S1, k);
                }
            }
            char temp;
            Pop(S2, temp); // 把左括号也出栈
            p++;
        }
        else
        {
            if (*p == '+' || *p == '-')
            {
                if (S2.data[S2.top] == '(' || StackEmpty) // 如果遍历到'+''-',且栈为空或栈顶为'(',直接入栈
                {
                    Push(S2, *p);
                    p++;
                }
                else
                {
                    while (S2.data[S2.top] != '(' && !StackEmpty) // 依次弹出较高优先级运算符,直到'('
                    {
                        char temp;
                        Pop(S2, temp);
                        char *k = &temp;
                        if (temp == '+' || temp == '-' || temp == '*' || temp == '/')
                        {
                            k = caculator(S1, k);
                        }
                    }

                    Push(S2, *p);
                    p++;
                }
            }
            else //  遇到*和/运算符  6+2+4*5
            {
                Push(S2, *p);
                p++;
            }
        }
    }
         if (!StackEmpty(S2))          //若栈不为空,依次弹出其中的运算符
	{
		while (S2.top != -1){
                 char temp;
			Pop(S2,temp);
			char *k=&temp;
            k=caculator(S1,k);
        }
			
		
	}
    char x;
    GetPop(S1, x);
    int a;
    a = x - '0';
    cout << a << endl;
    // char y;
    // Pop(S1,x);
    // GetPop(S1,y);
    // int b;
    // b=y-'0';
    // cout<<b<<endl;
}
int main()
{
    houzhui();
    zhongzhui();
    return 0;
}

在这里插入图片描述

4.3递归

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值