☆ 链栈(Linked Stack)

Q点我直达顺序栈部分Q

如果将链栈(Linked Stack)与链表(Linked List)相比,我们还是会发现很多不一样的地方,

其中最明显的地方就是头节点的问题,但是究其根本其原理几乎是相通的,加之将其流程图形化后就会更加容易理解了。

Q点我直达链表(Linked List)部分Q

****************************************************************************************************************************************

首先介绍什么是栈,

“栈”和“表”一样,栈也分为顺序栈与链栈,本文主要讲链栈;

所谓栈就是一种先进的元素被压制到了“容器”的最下面,输出的时候先输出最上面的元素的一种数据结构,

之所以出现了这种数据结构而不是使用“表”,最关键的就是为了解决指定某一类问题而制定的比较简便的方法,例如在厨房中洗盘子放的顺序与再次取用的问题、浏览器的后退功能

接下来介绍链栈所要实现的基本功能:

初始化链栈、入栈(写入数据)、出栈(删除数据)、遍历(输出数据),

下面直接附上代码,因为为了调试与理解的方便,并没有过多进行优化,代码还处于原生状态~~难点会在下方逐个解析,

(代码中已省去大量注释,部分细节内容在以前关于链表的那篇文章也已经解释过,这里就不做再次解释了,什么什么?你说还是看不懂?好吧好吧~~给你一个入口吧->点我):

#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语句中的两个==的问题,写代码的时候需要额外留心,否则不会报错,但是运行结果很意外。

还是不明白的小伙伴可以参考我的前一篇关于链表的文章,还是希望大家看到这都可以明明白白的~

千万不要着急~我相信你们哟~~

文章到这就结束咯~~~

****************************************************************************************************************************************

             最快的脚步不是跨越,而是继续,最慢的步伐不是小步,而是徘徊。

****************************************************************************************************************************************

猜你喜欢

转载自blog.csdn.net/qq_42292831/article/details/81512453