栈
定义:栈的顺序存储结构是由一个一维数组和一个栈顶元素位置的变量构成的。
#define MaxSize <存储数据元素的最大个数>
typedef struct SNode* Strack // 将结构体指针定义为Strack
struct SNode
{
ElementType Data[Maxsize];
int Top; // 非Staack的指针变量
//整型变量表示位于栈顶元素的下标是什么
};
入栈
Something should not be ignored:
栈中存在一个元素那个Top对应的数值为0;如果栈空:那么对应的Top值就在栈的下面那么对应的是==-1==.
但是数组下标是从0元素开始的!!理论上不冲突
void Push(ElementType X,Stack DStack* PtrS)
{
//判断是否栈满
if (PtrS->top == MaxSize-1) //栈的top元素的起始位置为0
{
printf{"栈满,不能继续存放,会导致溢出"};
return;
}
//如果栈不满
else
{
PtrS->Data[++(PtrS->Top)] = X;
return ;
}
}
出栈
ElementType Pop(Stack DStack* PtrS)
{
//首先判断栈是否为空
if (PtrS->Top == -1)
{ printf("栈为空");
return RERROR;
}
//栈不为空执行出栈操作
else
{
return (PtrS->Data[(PtrS->Top)--]);
}
}
一维数组实现两个堆栈
首先需要注意的是两个堆栈分别从数组的两头开始向中间增长,直到两个栈的栈顶指针在相遇之后,表明这两个栈满了
!!!绝对不能想做Top1+Top2等于MaxSize!!这是错误的因为:Top1,Top2下标相加为MaxSize但是可能存在两指针中间元素空余的情况
#define MaxSize<存储数据元素的最大数>
struct DStack
{
int Top_1,Top_2;
ElementType Data[MaxSize];
}S
S.Top_1 = -1;
S.Top_2 = MaxSize;
两个堆栈实现的入栈操作
void Push(Stack SNode *PtrS,ElementType item,int Tag)
{
//首先判断Top_1与Top_2是否已经相遇(栈已满)
if(PtrS->Top_2-PtrS->Top_1 ==1)
{
printf("栈已满,不能继续添加");
return;
}
//栈不满则继续添加
//定义Tag表示要往哪个数组中加入元素
//Tag=1表示往左边数组添加,Tag=0表示往右边数组添加
if (Tag==1)
{
PtrS->Data[++(PtrS->Top_1)] = item;
}
else
{
PtrS->Data[--(PtrS->Top_2)] = item;
}
return;
}
两个数组的出栈操作
ElementType Pop(Stack DStack* PtrS,int Tag)
{
//判断要弹出数据的数组是否为空
if (Tag == 1) //左侧数组弹出数据
{
if(PtrS->Top_1 == -1)
{ printf("栈元素为空,弹出数据不成功");
return NULL;
}
else
{
return PtrS->Data[(PtrS->Top_1)--];
}
}
else
{
if(PtrS->Tag_2==MaxSize)
{
printf("栈已空,无可弹出元素");
return NULL;
}
else
{
return PtrS->Data[(PtrS->Top2)++];
}
}
}
堆栈的链式存储
1)首先栈的链式存储结构实际上是一个单链表,叫做链栈。插入和删除操作只能在链栈的栈顶进行。
2)区分链表的头部还是尾部能作为栈顶元素呢?
:因为栈顶元素首先是:能够自由地进行插入和删除操作,所以链表的头部能够比链表的尾部实现更加快捷,链表尾部不能实现删除操作,因为他没有下一个Top指针可以指向的位置
//定义链式堆栈
typedef struct SNode* Stack;
struct SNode{
ElementType Data;
Struct SNode *Next;
}
//同时我们想建立一个空的栈头节点
//生成空的头节点不代表任何一个元素,而是通过这个头节点方便找到堆栈里面的具体元素
Stack CreatStack()
{
Stack s = (Stack)malloc ((struct SNode*)*1);
s->Next = NULL;
return s;
}
//判断堆栈是否为空?
int IsEmpty(Stack S)
{
return(S->Next == NULL);
}
链式堆栈的入栈操作
不存在栈满的情况
void Push(ElementType item ,Stack S)
{
//首先将元素压入栈
struct SNode* TempCell;
TempCell = (stack SNode*)malloc((struct SNode)*1);
TempCell->Data = item;
TempCell->Next = S->Next;
S->Next = TempCell;
}
链式堆栈的删除操作
ElementType Pop(Stack S)
{
Struct SNode*FirstCell;
ElementType TopItem;
//判断链式堆栈是否为空
if(Is empty(s) )//栈空为1
{
printf("堆栈为空");
return NULL;
}
else
{
FirstCell = S->Next;
S->Next = FirstCell->Next;
TopItem = FirstCell->Data;
free(FirstCell);
return TopItem;
}
}
中缀表达式转换为后缀表达式
- 从头到尾读取中缀表达式中的每个对象,按照不同对象的情况处理
- 运算数:直接输出
- 左括号:压入堆栈
- 右括号:将栈顶的运算符号弹出并且输出,直到遇到左括号;这里左括号不输出,直接扔掉了
- 运算符:
- 若优先级大于栈顶运算符的时候,那么将该运算符压入栈
- 若优先级低于栈顶运算符,将栈顶运算符输出;再比较新的栈顶运算符,指导该运算符大于栈顶运算符优先级,压入栈后为止
- 对象处理完毕将所有的堆栈中残留的运算符输出。
堆栈的用途:函数的调用以及递归调用
深度优先搜索
回溯算法