《数据结构》002线性结构——0B 堆栈

栈:仅在表头定义操作的线性表

引例:

运算数+运算符(前缀、中缀:a+b*c-d/e、后缀:abc*+de)

例1:(1)计算 62/3-42*+ =___

解: 6/2 = 3 --> 33- ---> 3-3 = 0 ---> 042* ---> 4*2 = 8 ---> 08+ ---> 8

故结果为 8  

        (2)计算

 计算机从左向右扫描,遇到数字保存,遇到运算符取出最近保留的2个数字,需要时倒序输出 ---> 堆栈,先进后出,在一端做插入、删除

数据类型:Stack

数据对象集: 一个有0个或多个元素的有穷线性表

操作集: 长度为MaxSize的堆栈S∈Stack,堆栈元素 item ∈ ElementType 

基本算法:

1、生成空堆栈,最大长度为 MaxSize:  Stack CreateStack( int MaxSize )

2、判断S是否为满 :  int IsFull(Stack S, int MaxSize)

3、将元素item压栈(插入/ 入栈) :   void Push(Stack S, ElementType item)  

4、判断是S否为空 :   int IsEmpty( Stack S)

5、删除并返回栈顶元素 :  ElementType Pop( Stack S )

 

例2: Push(S, A) Pop(A)  Push(S, B)  Push(S, C) Pop(C) Pop(B) 的结果为____

 A C B

动脑:ABCD 有哪几种情况?哪些可行哪些不可行?

一、栈的顺序存储实现

1、基本算法:

1、 定义结构体 Stack

#define MaxSize <允许存储元素的个数>
typedef struct SNode *Stack;

struct SNode{
    ElementType Data[MaxSize];
    int Top;   
};

2、 入栈

void Push( Stack PtrS, ElementType item)
{
    if ( PtrS->Top == MaxSize-1 )
        { printf("堆栈满"); 
          return;}
    else              //此处为前缀(PtrS->Top)++; PtrS->Data[PtrS->Top] = item;  
        { PtrS->Data[++(PtrS->Top)] = item;
          return;}
} 

3、 出栈

ElementType Pop( Stack PtrS)
{
    if( PtrS->Top == -1 )
        { printf("堆栈空");
          return ERROR; }       // ERROR 
    else
        return( PTrS->Data[(PtrS->Top0--]);
}

2、利用一个数组实现两个堆栈,要求最大利用数组空间,是数组只要有空间入栈,操作就可以成功

不能两头从中间往外:因为会有空余的格子

方法:在数组的两头定义Top1 Top2, 分别存放栈顶元素,然后让元素依次从两头入栈,判断堆栈满:Top1、Top2相遇,而不是 Top1+Top2 = MaxSize


1、定义结构体
#define MaxSizez<允许存储的元素个数>

struct DStack
{
    ElementType Data[MaxSize];
    int Top1;
    int Top2; 
} S;
S.Top1 = -1;          //判断堆栈空
S.Top2 = MaxSize;     //

2、入栈
void Push( struct DStack *PtrS, ElementType item, int Tag)
{   //Tag取值1和2,判断是左边还是右边入栈
    if( PtrS->Top2 - PtrS->Top1 == 1)
    {    printf("堆栈满"); 
         return; 
    }
    if( Tag==1 )
    {    PtrS->Data[++(PtrS->Top)] = item;
        // Top1 原值为 -1,这里需要从下标[0]开始
    }
    else
    {    PtrS->Data[--(PtrS->top)] = item;
       //Top2 原值为 MaxSize, 这里需要先向前移一位再进行运算
    }
}

3、 出栈

ElementType Pop( struct DStack *PtrS, int Tag)     // Tag指示那边的栈
{
    if( Tag ==1 )
    {  if( PtrS->Top == -1)
            {printf("堆栈1 空");   return NULL;}
       else 
            return PtrS->Data[(PtrS->Top1)--];     // 运算完毕后,元素向前移一格(区别前缀)
    }
    else
    {   if( PtrS->Top2 == MaxSize )
            {printf(" 堆栈2 空");  return NULL;}
        else 
            return PrtS->Data[(PtrS->Top2)++];     // 运算完毕后,元素向后移一格
    }
}

二、堆栈的链式存储实现

单链表—链栈,插入、删除只在链栈的栈顶进行,(栈顶指针Top 应在链表哪一头?)

1、 定义结构体
typedef struct SNode *Stack;
struct SNode
{
    ElementType Data;
    struct SNode *Next;
};

2、堆栈初始化
Stack CreatStack()  // 建立一个头结点S,指向后面的数据
{
    Stack S;
    S = (Stack)malloc(sizeof(struct SNode));
    S->Next = NULL;
    return S;
}

3、 判断是否为空
int IsEmpty(Stack S)
{
    return (S->Next == NULL); // 判断语句。若为空,则返回0; 否则,返回1
}

4、 插入
void Push(ElementType item, Stack S)
{
    struct SNode *TmpCell;
    TmpCell = (struct SNode *)malloc(sizeof(struct SNode));
    TmpCell->Data = item;   
    TmpCell->Next = S->Next;
    S->Next = TmpCell;    
}

5、  删除
ElementType Pop( Stack S )
{
    struct SNode *FirstCell;
    ElementType TopElem;
    if( IsEmpty(S) )                   // 判断链表是否为空
    {   printf("堆栈空"); return NULL;}
    else
    { 
        FirstCell = S->Next;
        S->Next = FirstCell->Next;
        TopElement = FirastCell->Data; // 用于装要删除的元素值
        free(FirstCell);               // 清除此节点
        return TopElement;             // 返回要删除的元素的值
    }
}

三、后缀、中缀转换

方式:

                                   C++ 运算符优先级

例3: (1)请详细写出表达式中缀a*(b+c)/d 转换为 后缀abc+*d/ 的过程 时间复杂度呈线性 T(N) = O(N)

        (2)2*(6/3+4)-5 转化为后缀表达式时,堆栈元素最多为____(3)

        (3) 中 -> 后: 2 *(9+6/3-5)+4  =________                        

解:(3)请看大图

堆栈其他应用: 1、函数调用即递归实现 2、深度优先搜索 3、回溯算法

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值