数据结构之栈

4.2 栈的定义
4.2.1 栈的定义
栈这种后进先出数据结构的应用非常普遍。撤销的操作,也是用栈这种方式实现的。    栈是限定仅在表尾进行插入和删除操作的线性表。
栈顶:允许插入和删除的一端  栈底:另一端
不含任何数据元素的栈称为空栈。栈又称为先进后出的线性表。

线性表,栈元素具有线性关系,即前驱后继关系。定义中说是在线性表的表尾进行插入和删除操作,这里表尾是指栈顶,而不是栈底。栈底是固定的,最先进栈的只能在栈底。
栈的插入操作,叫做进栈、压栈、入栈。
栈的删除操作,出栈、弹栈。
4.2.2 进栈出栈变化形式
栈对线性表的插入和删除的位置进行了限制,并没有对元素进出的时间进行限制。
第一种:1、2、3进栈,再3、2、1出。出栈次序321
第二种:1进,1出,2进,2出,3进,3出。也就是进一个出一个。出栈次序123
第三种:1进,2进,2出,1出,3进,3出。出栈次序213
第四种:1进,1出,2进,3进,3出,2出。出栈次序132
第五种:1进,2进,2出,3进,3出,1出。出栈次序231
312次序出栈不会出现。 只有三个元素,就有5种可能的出栈顺序。如果元素量多,出栈的变化将会更多。
4.3 栈的抽象数据类型
特别是插入和删除操作,改名为push和pop,压栈和出栈。
栈(stack)
data 
同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系。
Operation
init_stack(&s);   //初始化操作,建立一个空栈
destroy_stack(&s);//若栈存在,则销毁它
clear_stack(&s);  //将栈清空
is_empty_stack(&s);   //若栈为空,返回true,否则返回false
gettop_stack(&s,&val); //若栈存在且为非空,用val返回栈顶元素
push_stack(&s,val); //若栈存在,插入新元素val到栈中并称为栈顶元素 
pop_stack(&s,&val);//删除栈顶元素,并用val返回其值
length_stack(&s); //返回栈的元素个数
由于栈本身就是一个线性表,线性表的顺序和链式存储结构,对于栈来说同样适用。
4.6 栈的链式存储结构及实现
4.6.1 栈的链式存储结构
栈只是栈顶来做插入和删除的,栈顶放在链表的头部还是尾部呢?由于单链表有头指针,而栈顶指针也是必需的,所以比较好的办法就是把栈顶放在单链表的头部。另外,都已经有了栈顶在头部了,单链表中比较常用的头结点就失去意义,通常对于链栈来说,是不需要头结点的。
对于链栈来说,基本不存在栈满的情况,除非内存没有可使用的空间,如果真的发生,那此时计算机操作系统已经面临死机崩溃的情况,而不是这个链栈是否溢出的问题。
空栈,链表原定义是头指针指向空,那么链栈的空其实就是top=NULL
链栈的结构代码:
typedef struct Node
{
int data;
    struct Node *next;
} node,*pnode;
typedef struct Stack
{
pnode top;
int count;  //有效元素的个数
} stack;
4.6.2 进栈操作
4.6.3 出栈操作
4.6.4 顺序栈和链栈
时间复杂度上一样,均为0(1)。
空间性能,顺序栈需要事先确定一个固定的长度,可能会存在内存空间浪费的问     题,但是它的优势是存取定位很方便,而链栈要求每个元素都有指针域,增 加内存开销,但对于栈的长度无限制。
如果在使用过程中元素变化不可预料,有时很小,有时很大,那么最好用链栈。
如果变化在可控范围内,建议使用顺序栈更好一些。
4.7 栈的作用
4.8 栈的应用
4.8.1 递归

4.8.2 四则运算表达式求值

程序如下所示:

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


//定义结点类型
typedef struct Node
{
int data;    //内容
struct Node *next;  //指向下一个节点
} node,*pnode;


//定义栈的抽象数据类型
typedef struct Stack
{
pnode ptop;   //栈顶指针
    pnode pbottom;//栈底指针
} stack,*pstack;


//函数声明


//对栈进行初始化的函数
void init_stack(pstack list);
//入栈的函数
void push_stack(pstack list,int val);
//出栈的函数
bool pop_stack(pstack list,int *val);
//遍历栈的函数
void tranverse_stack(pstack list);
//判断栈是否为空
bool is_empty_stack(pstack list);
//清空栈的函数
void clear_stack(pstack list);


int main(void)
{
stack s; //定义一个栈,里面有两个元素,栈顶指针和栈底指针

int val = 0;
init_stack(&s);
push_stack(&s,1);
push_stack(&s,2);
push_stack(&s,3);
push_stack(&s,4);
push_stack(&s,5);
push_stack(&s,6);
tranverse_stack(&s);


if(pop_stack(&s,&val))
{
printf("出栈成功,出栈的元素是:%d.\n",val);
}
else
{
printf("出栈失败!\n");
}


tranverse_stack(&s);
clear_stack(&s);
tranverse_stack(&s);


return 0;
}


//对栈进行初始化的函数
void init_stack(pstack list)
{
//创建一个空结点,让ptop指向它
list->ptop = (pnode)malloc(sizeof(node));


if(NULL == list->ptop)
{
printf("内存分配失败!\n");
exit(-1);
}
else
{
list->pbottom = list->ptop; //将pbottom也指向空结点
list->pbottom->next = NULL; //清空空结点的指针域
}
}
//入栈的函数
void push_stack(pstack list,int val)
{
pnode p;
p = (pnode)malloc(sizeof(node));  //动态创建一个新节点
if(NULL == p)
{
printf("内存分配失败!\n");
exit(-1);
}
else
{
p->data = val;      //设置新结点的数据域的值
//将新结点的指针域指向之前的空结点
p->next = list->ptop;   //注意:list->ptop不能换成list->pbottom

list->ptop = p;    //list->ptop指向新的节点
}
return ;
}
//判断栈是否为空
bool is_empty_stack(pstack list)
{
if(list->ptop == list->pbottom)
{
return true;
}
else
{
return false;
}
}
//遍历栈的函数
void tranverse_stack(pstack list)
{
pnode p;
p = list->ptop;  //将栈顶赋给一个临时结点,因为在遍历栈的时候不能销毁栈
//循环遍历栈直到栈底
while(list->pbottom != p)
{
printf("%d ",p->data);
p = p->next;
}
printf("\n");
return ;
}
//出栈的函数
bool pop_stack(pstack list,int *val)
{
if(is_empty_stack(list))
{
return false;
}
else
{
//先保存栈顶元素的地址,然后将pTop指向下一元素,最后释放之前栈顶元素的内存
pnode q;
q = list->ptop;


*val = q->data;
list->ptop = q->next;


free(q);
return true;
}
}
//清空栈的函数
void clear_stack(pstack list)
{
if(is_empty_stack(list))
{
return ;
}
else
{
//两个结点指针变量用来释放栈中元素的内存
pnode p,q;
p = list->ptop;


while(list->pbottom != p)
{
q = p->next;
free(p);
p = q;
}
//将栈顶和栈底指向同一个指针域为空的结点
list->ptop = list->pbottom;
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值