栈实际上是线性表的特例,限定在表尾进行插入或删除操作,表尾端称为栈顶,表头端称为栈顶,栈拥有后进先出的特点。
栈分为顺序栈和链栈两种,的主要操作有:创建空栈、栈的判空、进栈、出栈、取栈顶元素等,下面逐一分析:
先介绍顺序栈:
**
顺序栈
栈的结构类型的定义
因为栈是线性表的特例,所有顺序栈有最大容量,以及栈顶指针,还有存放元素的起始指针(用于指向存放元素的位置)
typedef int DataType;//类型声明
struct Stack
{
DataType *elem;//存放元素起始指针
int Max;//最大容量
int top;//栈顶指针
};
typedef Struct Stack* SeqStack;//定义顺序栈的类型
- **
创建空栈
类似于数组的声明,创建空栈就是为顺序栈分配预先定义的数组空间,并将栈顶指针top变量设置为-1。
SeqStack SetNullStack_Seq(int m)
{
SeqStack stack=(SeqStack)malloc(sizeof(struct Stack));//申请空间
if(stack!=NULL)
{
stack->elem=(int *)malloc(sizeof(int)*m);//申请m个节点空点
if(stack->elem!=NULL)
{
stack->Max=m;
stack->top=-1;
return stack;
}
else
{
free(stack);
return NULL;
}
}
else
{
printf("Alloc failure");
return NULL;
}
}
- **
栈的判空
顺序栈的判空即检查栈顶指定是否等于初始化的-1即可,如果是则为空栈,返回1,否则返回0。
int IsNullStack_seq(SeqStack stack)
{
return (stack->top==-1);//检查栈顶指针
}
- **
顺序栈入栈
顺序栈的入栈需要检查栈是否已经满,即栈顶指针是否已经达到最大值,进栈时要先修改栈顶指针,再将元素压入栈中。
void Push_seq(SeqStack stack,int x)
{
if(stack->top==stack->Max-1)//检查栈顶指针
printf("Overflow!\n");
else
{
stack->top++;//修改栈顶指针
stack->elem[stack->top]=x;//压入元素
}
}
- **
顺序栈出栈
出栈操作要检查栈是否为空,若不为空则修改栈顶指针。
void Pop_seq(SeqStack stack)
{
if(IsNullStack_seq(stack))
printf("Undelflow!\n")
else
{
stop->top=stack->top-1;
}
}
- **
顺序栈取栈顶元素
需要先检查栈是否为空,若不为空则返回栈顶元素。
DataType Top_seq(SeqStack stack)
{
if(IsNullStack_seq(stack))
printf("Underflow!\n")
else
return stack->elem[stack->top];
}
有时候面对动态的存储问题,顺序栈往往不能满足我们的要求(因为顺序栈创建时指定了栈的最大存储空间),这时使用链栈就解决了顺序栈的不足,下面介绍链栈操作的实现方法:
链栈
链栈结构体类型
定义:链栈的节点包括数据域和指针域
typedef int DataType;
struct Node
{
DataType data;//数据域
struct Node *next;//指针域
};
typedef struct Node * PNode;//结点类型
typedef steuct Node *top;//栈顶类型
typedef struct Node *LinkStack;//链栈类型
- **
链栈创建空栈
创建带有头结点的空链栈,需要申请结构空间并使top->next为空
ListStack SetNullStack_Link()
{
LinkStack top=(LinkStack)malloc(sizeof(struct Node));//申请空间
if(top!=NULL)
top->next=NULL;
else
printf("Alloc failure");
return top;//返回栈顶指针
}
- **
链栈的判空
判空:链栈的判空只需要判断栈顶结点后继是否为空,为空则返回1,否则返回0。
int IsNullStack_Link(LinkStack top)
{
if(top->next==NULL)
return 1;
else
return 0;
}
链栈进栈
进栈:链栈的进栈操作首先要申请结点空间,然后进行数据域和指针域赋值,并修改top指针指向
void Push_Link(LinkStack top,DataType x)
{
PNode p=(PNode)malloc(sizeof(struct Node));//申请结点空间
if(p==NULL)
printf("Alloc faliure");
else
{
p->data=x;//数据域赋值
p->next=top->next;//指针域赋值
top->next=p;//修改栈顶
}
}
链栈出栈
出栈:出栈首先要判断栈是否为空,不为空则修改栈顶指针,并释放结点空间
void Pop_Link(LinkStack top)
{
PNode p;
if(IsNullStack_Link(top))
printf("It is empty stack");
else
{
p=top->next;//p指向待删除的结点
top->next=p->next;//修改栈顶指针
free(p);//释放删除结点
}
}
链栈取栈顶元素
取栈顶元素:首先判断栈是否为空,不为空则返回栈顶元素
DataType Pop_seq_return(LinkStack top)
{
if(IsNullStack_Link(top))
printf("It is empty stack!");
else
return top->next->data;
}
总结
总结:
栈的应用很广泛,通常被用作一种工具取解决数据结构的各类问题,常见的有:进制转换、括号匹配、迷宫、表达式求值、树的创建与遍历等等,感兴趣的可以看看一下几篇文章。
创作不易,支持一下呗q(≧▽≦q)