观 郝斌老师 视频
目录
一.栈的定义(Stack)
栈是限制插入和删除只能在一个位置上进行的表,该位置 是表的末端,叫做栈的顶部(Top)。
栈是一种实现“先进后出”的存储结构。
类似于箱子,只能一端在箱子的同一端进出。
二.栈的分类
栈分为两种:
静态栈(数组栈)(用数组实现)
动态栈(链式栈)(用链表实现)
三.栈的基本操作
1.压栈(Push)
2.出栈(Pop)
四.栈的实现
(一)动态栈的实现
1.创建结构体
//创建结构体
typedef struct Node
{
int data;
struct Node * pNext;
}NODE,*PNODE; //创建链表的结点
typedef struct Stack
{
PNODE pTop; //栈顶
PNODE pBottom; //栈底
}STACK,*PSTACK; //创建栈的大概框架
2.函数声明
//函数声明
void init (PSTACK );//初始化
void push (PSTACK ,int ) ; //压栈/入栈
bool pop (PSTACK ,int *);//出栈
bool empty (PSTACK ); //判断是否为空
void traverse (PSTACK);//遍历
void clear (PSTACK);//清空
3.栈的初始化
//栈的初始化
void init (PSTACK ps)//创造一个空栈 ,需要一个头指针(方便链表)
{
ps->pTop = (PNODE)malloc(sizeof(NODE));
if(NULL == ps->pTop)
{
printf("动态分配内存失败!\n");
exit(-1);
}
else
{
ps->pBottom = ps->pTop;//栈底 等于 栈顶,则栈为空
ps->pBottom->pNext = NULL;//或ps->pTop->pNext = NULL; 使底指针(头指针)的指针域为空
}
return;
}
4.压栈
//压栈
void push (PSTACK ps ,int val )//可以不用 int * ,因为没有改变 val。
{
PNODE pnew = (PNODE) malloc (sizeof (NODE));
pnew->data = val;
pnew->pNext = ps->pTop;//ps->pTop 不能改为 ps->pBottom
ps->pTop = pnew;
return ;
}
5.遍历
//遍历
void traverse (PSTACK ps)
{
PNODE p = ps->pTop; //遍历不改变栈,所以要定义一个新的变量,不移动Top
while(p != ps->pBottom)
{
printf("%3d",p->data);//可以进行相关替换
p = p->pNext;
}
printf("\n");
}
6.出栈
//出栈
//把 ps 所指向的栈 出栈一次,并把出栈的元素存入 pval形参 所指向的变量中 ,如果出栈失败返回false
bool pop (PSTACK ps,int * pval)
{
if( empty(ps) )// ps 本身就存放的就是 s 的地址
{
return false;
}
else
{
PNODE r = ps->pTop;
ps->pTop = r->pNext;
* pval = r->data ;//不能 pval = &r->data; (有区别)
free(r);
r = NULL;
}
}
7.判断是否为空栈
//判断是否为空栈
bool empty (PSTACK ps)
{
if( ps->pBottom == ps->pTop)
{
return true;
}
else
{
return false;
}
}
8.清空
//清空(注意清空与销毁的区别)
//清空只是清除数据,框架仍然存在;销毁是整个栈不存在了
void clear (PSTACK ps)
{
if(empty(ps))
{
return ;
}
else
{
PNODE p = ps->pTop ,q = NULL;
while(p != ps->pBottom)
{
q = p->pNext;
free(p);
p = q;
}
ps->pTop = ps->pBottom;
}
}
9.完整代码(动态栈实现)
/*链式栈*/
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef struct Node
{
int data;
struct Node * pNext;
}NODE,*PNODE;
typedef struct Stack
{
PNODE pTop;
PNODE pBottom;
}STACK,*PSTACK;
//函数声明
void init (PSTACK );//初始化
void push (PSTACK ,int ) ; //压栈/入栈
bool pop (PSTACK ,int *);//出栈
bool empty (PSTACK ); //判断是否为空
void traverse (PSTACK);//遍历
void clear (PSTACK);//清空
int main(void)
{
STACK s;//创建一个名为 s 的栈 ,未存放有效数据
int val;
init (&s);
push(&s,1);
push(&s,54);
push(&s,3);
push(&s,2);
push(&s,7);
push(&s,8);
traverse(&s);
if(pop(&s,&val))
{
printf("出栈成功,出栈元素是%d\n",val);
}
else
{
printf("出栈失败\n");
}
traverse(&s);
clear (&s);
traverse(&s);
return 0;
}
void init (PSTACK ps)//创造一个空栈 ,需要一个头指针(方便)
{
ps->pTop = (PNODE)malloc(sizeof(NODE));
if(NULL == ps->pTop)
{
printf("动态分配内存失败!\n");
exit(-1);
}
else
{
ps->pBottom = ps->pTop;
ps->pBottom->pNext = NULL;//或ps->pTop->pNext = NULL; 使底指针(头指针)的指针域为空
}
return;
}
void push (PSTACK ps ,int val )//可以不用 int * ,因为没有改变 val。
{
PNODE pnew = (PNODE) malloc (sizeof (NODE));
pnew->data = val;
pnew->pNext = ps->pTop;//ps->pTop 不能改为 ps->pBottom
ps->pTop = pnew;
return ;
}
void traverse (PSTACK ps)
{
PNODE p = ps->pTop;
while(p != ps->pBottom)
{
printf("%3d",p->data);
p = p->pNext;
}
printf("\n");
}
//把 ps 所指向的栈 出栈一次,并把出栈的元素存入 pval形参 所指向的变量中 ,如果出栈失败返回false
bool pop (PSTACK ps,int * pval)
{
if( empty(ps) )// ps 本身就存放的就是 s 的地址
{
return false;
}
else
{
PNODE r = ps->pTop;
ps->pTop = r->pNext;
* pval = r->data ;//不能 pval = &r->data; (有区别)
free(r);
r = NULL;
}
}
bool empty (PSTACK ps)
{
if( ps->pBottom == ps->pTop)
{
return true;
}
else
{
return false;
}
}
void clear (PSTACK ps)
{
if(empty(ps))
{
return ;
}
else
{
PNODE p = ps->pTop ,q = NULL;
while(p != ps->pBottom)
{
q = p->pNext;
free(p);
p = q;
}
ps->pTop = ps->pBottom;
}
}
(二)静态栈的实现
1.简单描述
用一个数组实现栈,要提前声明数组的大小。(静态栈相对比较简单可以自己尝试实现)
空栈的 Top 为 -1 ,即空栈的初始化。
将 x 压入栈中,使 Top = Top + 1 ; Stack[Top] = x ; 其中Stack代表的是具体栈的数组名。
关于是否要判断栈是否已满的问题:链式栈一般不会有满的情况,不需要判断是否栈满。
数组栈可能会满,一般来说这并不是一个问题,因为在典型应用程序中,即使有相当多的栈操作,在任一时刻栈的元素的实际个数从不会太大。
2.完整代码(动态栈实现)
/*数组栈*/
#include<stdio.h>
#define N 7
typedef struct Stack
{
int Top;
int stack[N];
}STACK;
//函数声明
void init (STACK *);
bool push(STACK * , int );
bool full(STACK *);
bool empty(STACK *);
bool pop(STACK * ,int *);
void traverse(STACK *);
int main(void)
{
STACK s;
int val;
init(&s);
push(&s,15);
push(&s,8);
push(&s,7);
push(&s,6);
push(&s,5);
push(&s,4);
push(&s,3);
push(&s,1);//不能压入栈,因为 N = 7,此为第八个元素
traverse(&s);
if(pop(&s,&val))
{
printf("出栈成功,出栈的元素为:%d\n",val);
}
else
{
printf("出栈失败\n");
}
traverse(&s);
return 0;
}
void init (STACK * ps)
{
ps->Top = -1;
return ;
}
//压栈
bool push(STACK * ps, int val)
{
if( full(ps) )
{
return false;
}
else
{
ps->Top = ps->Top + 1;
ps->stack[ps->Top] = val;
return true;
}
}
//判断栈是否已满,一般不需要
bool full(STACK *ps)
/*链式栈一般不会有满的情况,不需要判断是否栈满。
但是数组栈可能会满,一般来说这并不是一个问题,
因为在典型应用程序中,即使有相当多的栈操作,
在任一时刻栈的元素的实际个数从不会太大。
*/
{
if( N - 1 == ps->Top )
{
return true;
}
else
{
return false;
}
}
//出栈
bool pop(STACK * ps,int * pval)
{
if( empty(ps) )
{
return false;
}
else
{
* pval = ps->stack[ps->Top];
ps->Top = ps->Top - 1;
return true;
}
}
//判断栈是否为空
bool empty(STACK * ps)
{
if(ps->Top == -1)
{
return true;
}
else
{
return false;
}
}
//遍历
void traverse(STACK * ps)
{
if( empty(ps) )
{
;
}
else
{
int p = ps->Top;
while(p >= 0)
{
printf("%4d",ps->stack[p]);
p = p - 1;
}
}
printf("\n");
return ;
}
四.栈的应用(略)
1.函数调用
2.中断
3.表达式求值
4.内存分配
5.缓冲处理
6.迷宫