如果将链栈(Linked Stack)与链表(Linked List)相比,我们还是会发现很多不一样的地方,
其中最明显的地方就是头节点的问题,但是究其根本其原理几乎是相通的,加之将其流程图形化后就会更加容易理解了。
****************************************************************************************************************************************
首先介绍什么是栈,
“栈”和“表”一样,栈也分为顺序栈与链栈,本文主要讲链栈;
所谓栈就是一种先进的元素被压制到了“容器”的最下面,输出的时候先输出最上面的元素的一种数据结构,
之所以出现了这种数据结构而不是使用“表”,最关键的就是为了解决指定某一类问题而制定的比较简便的方法,例如在厨房中洗盘子放的顺序与再次取用的问题、浏览器的后退功能;
接下来介绍链栈所要实现的基本功能:
初始化链栈、入栈(写入数据)、出栈(删除数据)、遍历(输出数据),
下面直接附上代码,因为为了调试与理解的方便,并没有过多进行优化,代码还处于原生状态~~难点会在下方逐个解析,
(代码中已省去大量注释,部分细节内容在以前关于链表的那篇文章也已经解释过,这里就不做再次解释了,什么什么?你说还是看不懂?好吧好吧~~给你一个入口吧->点我):
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
typedef int ElemType;
typedef int Status;
typedef struct node
{
ElemType data;
struct node *link;
}StackNode,*LinkStack;
void InitStack(LinkStack top)
{
top->link = NULL;
}
Status IsEmpty(LinkStack top)
{
if(top->link == NULL)
{
return FALSE;
}
return TRUE;
}
Status Push(LinkStack top,ElemType element)
{
LinkStack temp;
if(!(temp=(LinkStack)malloc(sizeof(StackNode))))
{
printf("Memory allocate error!");
exit(FALSE);
}
temp->data = element;
temp->link = top->link;
top->link = temp;
return TRUE;
}
Status Pop(LinkStack top,ElemType *element)
{
ElemType i;
if(!IsEmpty(top))
{
return FALSE;
}
LinkStack temp;
temp = top->link;
*element = temp->data;
top->link = temp->link;
free(temp);
return TRUE;
}
Status TopStack(LinkStack top,ElemType *element)
{
if(!IsEmpty(top))
{
return FALSE;
}
*element = top->link->data;
return TRUE;
}
Status TraverseStack(LinkStack top,ElemType *element)
{
if(!IsEmpty(top))
{
return FALSE;
}
printf("Top->Bottom:\n");
while(IsEmpty(top))
{
*element = top->link->data;
top->link=top->link->link;
printf("%d\n",*element);
}
return TRUE;
}
Status main()
{
LinkStack top;
ElemType i,result,n;
if(!(top=(LinkStack)malloc(sizeof(StackNode))))
{
printf("Memory allocate error!");
exit(FALSE);
}
InitStack(top); /*别忘了初始化链栈,否则会无法判断栈底是否为空 */
for(i=1;i<=10;i++)
{
Push(top,i);
}
printf("Pop Stack:\n");
/*
while(IsEmpty(top)) //全部弹出
{
Pop(top,&result,n);
printf("Already pop : %d\n",result);
}
*/
printf("Please enter the number of data need to be pop:"); //弹出n个
scanf("%d",&n);
for(i=0;i<n;i++)
{
Pop(top,&result);
printf("Already pop : %d\n",result);
}
TraverseStack(top,&result);
printf("\nTop Stack:"); /*在堆栈操作中,当进栈数据全部弹出后,这时S P应指向:栈底单元地址加1 ;*/
TopStack(top,&result);
printf("\n%d ",result);
return TRUE;
}
初始化链栈:
代码如下,
void InitStack(LinkStack top)
{
top->link = NULL;
}
相信不少人已经卡在这里了,有人一定会问为什么不直接让top指针指向NULL,而是让top->link指向NULL呢?
再来看一眼下面的图,空栈时top并不是指向我们原以为的0,而是指向了-1,这样定义的话top->link就会指向链栈的存放数据的栈底,就好像链表里面的头结点一样。
如果下定决心一定要用top->NULL……那么也不是写不出来来啦~,有兴趣的可以尝试一下~
入栈:
代码如下,该函数拥有两个参数,第一个是栈顶指针,第二个是需要输入的数据;
Status Push(LinkStack top,ElemType element)
{
LinkStack temp;
if(!(temp=(LinkStack)malloc(sizeof(StackNode))))
{
printf("Memory allocate error!");
exit(FALSE);
}
temp->data = element;
temp->link = top->link;
top->link = temp;
return TRUE;
}
因为是链式结构,首先需要为新来的数据分配一段存储空间,然后就是将其余头指针连接起来,头指针移位
(什么什么?解释太简单了,没理解?结合上面的那幅图仔细想想~不要急~);
判断栈是否为空(出栈前需要做的判断):
代码如下,这…这不解释了:
Status IsEmpty(LinkStack top)
{
if(top->link == NULL)
{
return FALSE;
}
return TRUE;
}
出栈(Pop):
代码如下,可以参考链表那一篇文章,那里说了与free有关的部分,其余也都与链表中类似(链表那篇入口在文章开头)。
Status Pop(LinkStack top,ElemType *element)
{
ElemType i;
if(!IsEmpty(top))
{
return FALSE;
}
LinkStack temp;
temp = top->link;
*element = temp->data;
top->link = temp->link;
free(temp);
return TRUE;
}
遍历(Traverse):
代码如下,注释放在了代码中。
Status TraverseStack(LinkStack top,ElemType *element)
{
if(!IsEmpty(top))
{
return FALSE;
}
printf("Top->Bottom:\n");
while(IsEmpty(top)) //当头指针不为空时继续向下寻找
{
*element = top->link->data;
top->link=top->link->link; /*这个用法也很好理解,上面也用到过只不过是将top->link定义为temp了*/
printf("%d\n",*element);
}
return TRUE;
}
主函数(main):
代码如下,解释已经放在注释中;
Status main()
{
LinkStack top;
ElemType i,result,n;
if(!(top=(LinkStack)malloc(sizeof(StackNode)))) /*链表中不用在主函数开头分配空间,这里需要多注意点*/
{
printf("Memory allocate error!");
exit(FALSE);
}
InitStack(top); /*别忘了初始化链栈,否则会无法判断栈底是否为空,程序到输出的时候就会卡住了 */
for(i=1;i<=10;i++) /*向栈中压入数据,这里压入10个整型数*/
{
Push(top,i);
}
printf("Pop Stack:\n");
/*
while(IsEmpty(top)) //全部弹出
{
Pop(top,&result,n);
printf("Already pop : %d\n",result);
}
*/
printf("Please enter the number of data need to be pop:"); //弹出n个
scanf("%d",&n);
for(i=0;i<n;i++)
{
Pop(top,&result);
printf("Already pop : %d\n",result);
}
TraverseStack(top,&result); /*遍历链栈*/
printf("\nTop Stack:"); /*在堆栈操作中,当进栈数据全部弹出后,这时S P应指向:栈底单元地址加1 ;*/
TopStack(top,&result);
printf("\n%d ",result);
return TRUE;
}
特别提示:
1.这里的栈顶元素的问题,这里只是说了一点,大家可以尝试在数据不全部弹出时看看栈顶是谁。
2.这里提一下if语句中的两个==的问题,写代码的时候需要额外留心,否则不会报错,但是运行结果很意外。
还是不明白的小伙伴可以参考我的前一篇关于链表的文章,还是希望大家看到这都可以明明白白的~
千万不要着急~我相信你们哟~~
文章到这就结束咯~~~
****************************************************************************************************************************************
最快的脚步不是跨越,而是继续,最慢的步伐不是小步,而是徘徊。
****************************************************************************************************************************************