1.1 栈的概念
栈是一种思想
(
应用方法
)
本质上来说,栈是操作受限的线性表
栈是一种
后进先出
(
Last In First Out, LIFO
)的线性表
栈值允许在表的一段进行插入和删除
允许 进行插入和删除的这一端称之为
-----
栈顶(
Top
)
,
另外一端称之为栈底
满栈:是指
top
永远指向的是最后压入栈的数据的位置,入栈时
top
先操作,再进行数据入栈
空栈:是指
top
永远指向的是下一个要入栈的位置,入栈时先进行数据的入栈,再对
top
进行操作
增栈
:
堆栈由低地址向高地址生长
减栈:堆栈由高地址向低地址生长
根据以上概念可以有四种组合:
递增满栈,递增空栈,递减满栈,递减空栈
共享栈
:
两个栈共用同一块内存区域,一个栈由低地址向高地址生长,另一个栈由高地址向低地址
生长
上溢
:
栈已经满了,无法进行入栈操作了
下溢
: 栈已经空了,无法进行出栈操作了
1.2 栈的存储结构
1.2.1 顺序结构
栈的顺序结构存储,也称之为顺序栈
顺序栈是利用一组连续的存储单元来存放栈的元素
同时,需要一个
top"
指针
"(
数组下标
)
,来表示栈元素的位置
顺序栈的空间是有限的,当一个元素入栈时,一般需要判断栈是否满了
如果栈满,则元素不能入栈
假设数据元素类型是
int,
则顺序栈的一般定义如下
:
#define MAXSIZE 10
typedef struct SeqStack
{
int data[MAXSIZE]; //地址连续的存储单元
int top; //栈顶“指针”
}SeqStack;
栈的基本操作
:
创建一个数据元素为空的栈
stack_init()
入栈
push()
出栈
pop()
读取栈顶元素
get_top()
判断栈空
empty()
.........
1.2.2 链式结构
用单链表来实现栈这种思想,也称之为链式栈
本质上来说
:
链式栈就是一个只能在一端添加和删除结点的单链表
顺序栈代码:
SeqStack.c
#include "SeqStack.h"
/*
功能: 初始化一个栈,此时栈中无数据
返回值:
返回栈的地址
*/
SeqStack* seqstack_init()
{
SeqStack* s = malloc(sizeof(SeqStack));
s->top = -1; //top置为-1,表示栈目前是空的
return s;
}
/*
功能: 入栈
参数:
stack: 栈的地址
value: 需要入栈的数据
*/
void push_stack(SeqStack* stack, ElemType value)
{
//判断栈是否已满
if(stack->top == MAXSIZE-1)
{
printf("栈已满,无法进行入栈操作\n");
return ;
}
stack->top++; //栈顶“指针”指向需要入栈的位置
//data[top]
stack->data[stack->top] = value; //数据入栈
}
/*
功能: 出栈
参数:
stack: 栈的地址
返回值:
成功返回出栈的数据
失败返回0
*/
ElemType pop_stack(SeqStack* stack)
{
//判断栈是否为空
if(stack_empty(stack))
{
printf("栈已经为空,无法进行出栈操作\n");
return 0;
}
ElemType temp = stack->data[stack->top]; //栈顶元素的数据
stack->data[stack->top] = 0;
stack->top--;
return temp;
}
/*
功能: 获取栈顶元素的数据
参数:
栈的地址
返回值:
成功返回获取到的栈顶元素的数据
失败返回0
*/
ElemType get_top(SeqStack* stack)
{
//判断栈是否为空
if(stack_empty(stack))
{
printf("栈已经为空,无法获取栈顶元素\n");
return 0;
}
//data[top]
return stack->data[stack->top];
}
/*
功能: 判断栈是否为空
参数:
stack: 栈的地址
返回值:
为空则返回 true
不为空则返回false
*/
bool stack_empty(SeqStack* stack)
{
if(stack->top == -1)
return true;
return false;
}
/*
功能: 清空一个栈
参数:
stack: 栈的地址
*/
void clear_stack(SeqStack* stack)
{
if(stack_empty(stack))
printf("栈已经为空,不需要再清空\n");
else
stack->top = -1;
}
/*
功能: 销毁一个栈
参数:
stack: 栈的地址
*/
SeqStack* destroy_stack(SeqStack* stack)
{
while(1)
{
if(stack->top == -1) //栈已清空
break;
stack->data[stack->top] = 0;
stack->top--;
}
free(stack);
stack = NULL; //避免产生悬挂指针
return stack;
}
SeqStack.h
#ifndef __SEQSTACK__
#define __SEQSTACK__
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAXSIZE 10
typedef int ElemType;
typedef struct SeqStack
{
ElemType data[MAXSIZE]; //地址连续的存储单元
int top; //栈顶"指针"
}SeqStack;
SeqStack* seqstack_init();
void push_stack(SeqStack* stack, ElemType value);
ElemType get_top(SeqStack* stack);
ElemType pop_stack(SeqStack* stack);
bool stack_empty(SeqStack* stack);
void clear_stack(SeqStack* stack);
SeqStack* destroy_stack(SeqStack* stack);
#endif
main.c
#include "SeqStack.h"
int main()
{
//初始化栈
SeqStack* stack = seqstack_init();
//入栈
push_stack(stack, 100);
push_stack(stack, 200);
push_stack(stack, 300);
//清空栈
//clear_stack(stack);
//销毁栈
//stack = destroy_stack(stack);
//出栈
ElemType value = pop_stack(stack);
if(value != 0)
printf("value = %d\n", value);
//获取栈顶元素的数据
ElemType top_data = get_top(stack);
if(top_data != 0)
printf("top_data = %d\n", top_data);
return 0;
}
链式栈代码:
Stack.c
#include "Stack.h"
/*
功能: 初始化一个结点,并把数据写入到结点中
参数:
var: 结点的数据
返回值:
结点的地址
*/
stack_node* node_init(ElemType var)
{
//先申请一个结点那么大的存储空间
stack_node* pnew = malloc(sizeof(stack_node));
//往结点中写入数据
pnew->data = var;
pnew->next = NULL;
return pnew;
}
/*
功能: 初始化一个头结点
返回值:
返回头结点的地址
*/
Stack* stack_init()
{
//先申请一个头结点那么大的存储空间
Stack* stack = malloc(sizeof(Stack));
stack->low = NULL;
stack->top = NULL;
stack->num = 0;
return stack;
}
/*
功能: 入栈
参数:
stack: 栈的地址
value: 需要入栈的数据
*/
void push_stack(Stack* stack, ElemType value)
{
//初始化一个新的结点
stack_node* new_node = node_init(value);
//从无到有
if(stack->low == NULL)
{
stack->low = new_node;
stack->top = new_node;
}
else //从少到多
{
stack->top->next = new_node;
stack->top = new_node; //栈顶指向最后入栈的元素
}
stack->num++; //栈中元素个数加一
}
/*
功能: 出栈
参数:
栈的地址
返回值:
成功返回栈顶元素的值
失败返回0
*/
ElemType pop_stack(Stack* stack)
{
if(stack->num == 0)
{
printf("栈已经为空,无法进行出栈操作\n");
return 0;
}
stack->num--;
ElemType value; //用来保存出栈的元素的数据
//栈中只有一个元素
if(stack->low->next == NULL)
{
value = stack->top->data; //存储出栈的元素的数据
stack_node* temp = stack->top;
stack->low = NULL;
stack->top = NULL;
free(temp);
return value;
}
else //栈中有多个元素,释放栈顶元素
{
stack_node* p = stack->low; //从栈低往栈顶去找
stack_node* pre = NULL; //保存栈顶的前一个元素的地址
while(1)
{
if(p == stack->top) //找到栈顶的位置
{
value = stack->top->data; //存储出栈的元素的数据
stack->top = pre; //确定新的栈顶
stack->top->next = NULL; //把需要删除的结点与原来栈之间的连续断开
free(p);
return value;
}
pre = p; //先保存p现在指向的结点的地址
p = p->next; //p去遍历栈
}
}
}
/*
功能: 获取栈顶元素的数据
参数:
stack: 栈的地址
返回值:
成功返回栈顶元素的值
失败返回0
*/
ElemType get_top(Stack* stack)
{
if(stack->num == 0)
{
printf("栈已经为空,无法获取栈顶元素的数据\n");
return 0;
}
else
return stack->top->data;
}
/*
功能: 销毁一个栈
参数:
栈的地址
返回值:
NULL
*/
Stack* destory_stack(Stack* stack)
{
stack_node* p = stack->low; //从栈底往栈顶进行遍历
stack_node* q = NULL; //用来保存需要释放的元素指向的下一个元素的地址
while(p != NULL)
{
q = p->next;
p->next = NULL;
free(p);
p = q;
}
stack->low = NULL;
stack->top = NULL;
stack->num = 0;
free(stack);
stack = NULL;
return stack;
}
Stack.h
#ifndef __STACK_H__
#define __STACK_H__
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType; //方便存储的数据的类型做修改
//typedef: 给已有的数据类型起一个别名
//在这里是给struct Node起了一个短一点的名字node
typedef struct Stack_Node
{
ElemType data; //数据域
struct Stack_Node* next; //指针域
}stack_node;
//定义头结点的类型,用于存储链表的一些属性信息
typedef struct Stack
{
stack_node* top; //保存栈顶的地址
stack_node* low; //保存栈底的地址
int num; //记录栈中元素的数量
}Stack;
stack_node* node_init(ElemType var);
Stack* stack_init();
void push_stack(Stack* stack, ElemType value);
ElemType pop_stack(Stack* stack);
ElemType get_top(Stack* stack);
Stack* destory_stack(Stack* stack);
#endif
main.c
#include "Stack.h"
int main()
{
Stack* stack = stack_init();
push_stack(stack, 100);
push_stack(stack, 200);
push_stack(stack, 300);
ElemType top_data = get_top(stack);
if(top_data != 0)
printf("top_data = %d\n", top_data);
pop_stack(stack);
top_data = get_top(stack);
if(top_data != 0)
printf("top_data = %d\n", top_data);
//stack = destory_stack(stack);
//top_data = get_top(stack);
return 0;
}