栈的基本概念
栈是一种基于先进后出(FILO)或者后进先出(LIFO)的数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。
我们称数据进入到栈的动作为压栈(入栈),数据从栈中出去的动作为弹栈(出栈)。
链式栈
链式栈就是使用链表的方式实现的栈,为了实现先进后出(FILO),我们可以采用链表中的“头插法”实现一个链式栈。
但是与之前所学的链表不同的是:链式栈中不需要头结点(数据域为空的结点)。
如上图所示,指向链表中的第一个结点的指针就是栈顶指针,指向链表最后一个结点的指针就是栈底指针。
1、链式栈的描述
typedef struct StackNode{
ElemType data; //数据域
struct StackNode * next; //指针域
}StackNode, *LinkStack;
2、链式栈的初始化
/*
* @brief 初始化一个链式栈
* @return 返回链式栈的栈顶指针
* */
LinkStack stack_init()
{
LinkStack s;
//因为没有头结点,因此初始化链式栈时因为栈为空,所以栈顶指针赋值为NULL
s = NULL;
return s;
}
3、入栈
入栈:链表的头插法,在链表的第一个结点之前插入新的结点
/*
* @brief 入栈
* @param s 栈顶指针的地址
* @param data 需要入栈的元素
* @return 成功返回TRUE,失败返回FALSE
* */
int push(LinkStack *s, ElemType data)
{
if (NULL == s)
return FALSE;
StackNode *p = (StackNode *)malloc(sizeof(StackNode));
p->data = data;
//新的结点的next指向链表的第一个结点(原来的栈顶)
p->next = *s;
//栈顶指针指向新的结点(p变成了链表上的第一个结点)
*s = p;
return TRUE;
}
void print_stack(LinkStack s)
{
if (NULL == s)
return ;
StackNode *t = s;
while (t)
{
printf("%d ", t->data);
t = t->next;
}
printf("\n");
}
4、出栈
/*
* @brief 出栈
* @param s 栈顶指针的地址
* @param data 需要出栈的元素
* @return 成功返回TRUE,失败返回FALSE
* */
int pop(LinkStack *s, ElemType *data)
{
if (NULL == s || NULL == data || NULL == *s)
return FALSE;
*data = (*s)->data;
StackNode *t = (*s)->next;
free(*s);
*s = t;
return TRUE;
}
5、获取栈顶元素
/*
* @brief 获取栈顶元素
* @param s 栈顶指针
* @param data 需要入栈的元素
* @return 成功返回TRUE,失败返回FALSE
* */
int get_top(LinkStack s, ElemType *data)
{
if (NULL == s || NULL == data)
return FALSE;
*data = s->data;
return TRUE;
}
6、销毁链式栈
/*
* @brief 销毁链式栈
* @param s 栈顶指针的地址
* @return 成功返回TRUE,失败返回FALSE
* */
int stack_destroy(LinkStack *s)
{
if (NULL == s || NULL == *s)
return FALSE;
StackNode *t = *s;;
while (t)
{
t = (*s)->next;
free(*s);
*s = t;
}
//*s = NULL;
return TRUE;
}