数据结构(C语言版)——链栈(代码版)

一、代码

#include 
#include 

#define OK 1
#define ERROR 0
 
typedef int Status;
typedef struct stackNode{
	long int data;
	struct stackNode* next;
}STACKNODE;//定义链栈结点结构 
typedef struct stackNode* nodePointer;
typedef struct linkStack{
	nodePointer top;
	int counter;
}LINKSTACK;//定义指针top和计数器结构 

int printMenu(void);
void PleaseInit(void);
Status initLinkStack(LINKSTACK* T);
Status insertLinkStack(LINKSTACK* T);
Status printElementNumber(LINKSTACK* T);
Status linkStackEmpty(const LINKSTACK* T);
Status returnLinkStackTop(const LINKSTACK* T);
Status pop(LINKSTACK* T);
Status clearLinkStack(LINKSTACK* T);
Status destroyLinkStack(LINKSTACK* T);
 
int main(int argc, char *argv[]) {
	int menuChoice;
	LINKSTACK topLinkStack;//声明一个LINKSTACK类型的变量,以后用以指向链栈结点 
	topLinkStack.top=NULL;//初始化为NULL,表示没有指向链栈可见当前链栈为空
	 
	while(menuChoice=printMenu())
		{
				switch(menuChoice)
				{
					case 1:
					    initLinkStack(&topLinkStack);
						break;
					case 2:
						destroyLinkStack(&topLinkStack);
						break;
					case 3:
						clearLinkStack(&topLinkStack);
						break;
					case 4:
					   	linkStackEmpty(&topLinkStack);
						break;
					case 5:
						returnLinkStackTop(&topLinkStack);
						break;
					case 6:
						insertLinkStack(&topLinkStack);
						break;
					case 7:
						pop(&topLinkStack);
						break;
					case 8:
						printElementNumber(&topLinkStack);
						break;
				}
		}
	return 0;
}

//打印菜单
int printMenu(void)
{
	int choice;
	
	printf("****************链栈练习******************\n");
	printf("1:初始化链栈\n");
	printf("2:销毁链栈\n");
	printf("3:清空链栈\n");
	printf("4:链栈是否为空\n");
	printf("5:返回栈顶元素\n");
	printf("6:元素压入到链栈中\n");
	printf("7:删除栈顶元素,并返回\n"); 
	printf("8:当前栈元素个数\n");
	printf("按下0退出程序\n"); 
	printf("*******************************************\n");
	printf("请选择:");
	scanf("%d",&choice);
	return choice;
}

//1:初始化链栈
Status initLinkStack(LINKSTACK* T)
{
	system("cls");//清屏  
    printf("当前选的为--1:初始化链栈--\n");
    
    if(T->top!=NULL)
    {
    	printf("请勿重复操作\n");
    	return ERROR;
	}
	
	T->top=(nodePointer)malloc(sizeof(STACKNODE));
	if(T->top==NULL)
	{
		printf("初始化失败!\n");
		return ERROR;
	}
	T->counter=0;//初始化为0,表示链栈为空。但是已经初始化了 
	T->top->next=NULL;//申请分配一个空间之后,它是第一个元素所以要压入栈。栈底元素没有指向别的结点
	printf("初始化成功!\n"); 
	return OK;
} 

//2:销毁链栈
Status destroyLinkStack(LINKSTACK* T)
{
	system("cls");//清屏  
    printf("当前选的为--2:销毁链栈--\n");
    
    if(T->top==NULL)
    {
    	PleaseInit();
		return ERROR;	
	}
	
	char inputValue;
	printf("是否要销毁链表?(Y/N)");
	scanf("	%c",&inputValue);
	fflush(stdin);
	if(inputValue=='Y'||inputValue=='y')
	{
		nodePointer param;
		while(T->top->next!=NULL)
		{
			param=T->top;
			T->top=param->next;//回退
			T->counter--;
			free(param);//把结点回收
		}
		free(T->top);
		T->top=NULL;
		printf("销毁成功!\n");
		return OK;
	}
	if(inputValue=='N'||inputValue=='n')
	{
		return OK;
	}
	return OK;
}

//3:清空链栈
Status clearLinkStack(LINKSTACK* T)
{
	system("cls");//清屏  
    printf("当前选的为--3:清空链栈--\n");
    
    if(T->top==NULL)
    {
    	PleaseInit();
		return ERROR;	
	}
	if(T->counter==0)
	{
		printf("当前栈为空,请先压入元素吧\n");
		return ERROR;
	}
	char inputValue;
	printf("是否要清空链表?(Y/N)");
	scanf("	%c",&inputValue);
	fflush(stdin);
	if(inputValue=='Y'||inputValue=='y')
	{
		nodePointer param;
		while(T->top->next!=NULL)
		{
			param=T->top;
			T->top=param->next;//回退
			T->counter--;
			free(param);//把结点回收
		}
		printf("清除成功!\n");
		return OK;
	}
	if(inputValue=='N'||inputValue=='n')
	{
		return OK;
	}
	return OK;
}

//4:链栈是否为空
Status linkStackEmpty(const LINKSTACK* T)
{
	system("cls");//清屏  
    printf("当前选的为--4:链栈是否为空--\n");
    
    if(T->top==NULL)
    {
    	PleaseInit();
		return ERROR;	
	}
	if(T->counter==0)
	{
		printf("当前栈为空,请先压入元素吧\n");
		return ERROR;
	}
	printf("当前链栈不为空\n");
	return OK;
} 

//5:返回栈顶元素
Status returnLinkStackTop(const LINKSTACK* T)
{
	system("cls");//清屏  
    printf("当前选的为--5:返回栈顶元素--\n");
    
    if(T->top==NULL)
    {
    	PleaseInit();
		return ERROR;	
	}
	if(T->counter==0)
	{
		printf("当前栈为空,请先压入元素吧\n");
		return ERROR;
	}
	printf("当前栈顶元素为:%d\n",T->top->next->data); 
	return OK;
}

//6:元素压入到链栈中
Status insertLinkStack(LINKSTACK* T)
{
	system("cls");//清屏  
    printf("当前选的为--6:元素压入到链栈中--\n");
    
    if(T->top==NULL)
    {
    	PleaseInit();
		return ERROR;	
	}
	nodePointer param;
	int pushElement;
	param=T->top;
	printf("请输入要压入的元素:");
	scanf("%d",&pushElement);
	fflush(stdin);//防止多输入 
	param=(nodePointer)malloc(sizeof(STACKNODE));
	if(param==NULL)
	{
		printf("压入失败!\n");
		return ERROR; 
	}
	T->top->data=pushElement;
	param->next=T->top;
	T->counter++;
	T->top=param;
	printf("压入成功!\n");
	return OK;
}

//7:删除栈顶元素,并返回
Status pop(LINKSTACK* T)
{
	system("cls");//清屏  
    printf("当前选的为--7:删除栈顶元素,并返回--\n");
    
    if(T->top==NULL)
    {
    	PleaseInit();
		return ERROR;	
	}
	if(T->counter==0)
	{
		printf("当前栈为空,请先压入元素吧\n");
		return ERROR;
	}
	
	nodePointer param;
	param=T->top;
	printf("当前栈顶元素为:%d\n",T->top->next->data);
	if(param->next!=NULL)
	{
		T->top=param->next;//回退
		T->counter--;
		free(param);//把结点回收
		printf("删除成功!\n"); 
	}
	return OK;
}

//8:当前栈元素个数
Status printElementNumber(LINKSTACK* T)
{
	system("cls");//清屏  
    printf("当前选的为--8:当前栈元素个数--\n");
    
    if(T->top==NULL)
    {
    	PleaseInit();
		return ERROR;	
	}
	if(T->counter==0)
	{
		printf("当前栈为空,请先压入元素吧\n");
		return ERROR;
	}
	printf("当前栈元素个数为:%d\n",T->counter);
	return OK;
}

//请先初始化样式
void PleaseInit(void)
{
		printf("**************\n");
		printf("*请先初始化  *\n");
		printf("**************\n\n");
}  

二、代码中重要的函数或语句

(一)、

typedef struct stackNode{
	long int data;
	struct stackNode* next;
}STACKNODE;//定义链栈结点结构 
typedef struct stackNode* nodePointer;
typedef struct linkStack{
	nodePointer top;
	int counter;
}LINKSTACK;//定义指针top和计数器结构 

第一个结构是定义了一个结点结构,就像链表一样的结点。效果如下图
数据结构(C语言版)——链栈(代码版)_第1张图片
第二个是定义了指向结点的结构,里面包含一个指向栈结点的指针和一个计数器。效果图如下

数据结构(C语言版)——链栈(代码版)_第2张图片
(二)、初始化函数中

T->top=(nodePointer)malloc(sizeof(STACKNODE));
T->counter=0;//初始化为0,表示链栈为空。但是已经初始化了 
T->top->next=NULL;//申请分配一个空间之后,它是第一个元素所以要压入栈。栈底元素没有指向别的结点

上面三条语句,第一个是动态分配栈结点空间并且top指向它,然后counter=0,这个分配的地址空间用于存储栈底元素。效果图如下
数据结构(C语言版)——链栈(代码版)_第3张图片
这个初始化和下面的链栈效果是一样的,当top=0时为空栈
数据结构(C语言版)——链栈(代码版)_第4张图片
(三)、压入栈函数中

param=(nodePointer)malloc(sizeof(STACKNODE));
T->top->data=pushElement;
param->next=T->top;
T->counter++;
T->top=param;

下面我们用一组图片说明上面的5条语句的意思

param=(nodePointer)malloc(sizeof(STACKNODE));

数据结构(C语言版)——链栈(代码版)_第5张图片
动态分配空间,返回param指针指向这个地址,注意指针类型它和T不一样。

T->top->data=pushElement;

数据结构(C语言版)——链栈(代码版)_第6张图片

接着就是把输入的值放入第一个地址空间中,这里用data代替(我不会说是因为太难画了才代替的 ̄へ ̄)。

param->next=T->top;

数据结构(C语言版)——链栈(代码版)_第7张图片
使新分配的地址空间中的指针指向了之前的值。

T->counter++;

数据结构(C语言版)——链栈(代码版)_第8张图片
counter+1

T->top=param;

数据结构(C语言版)——链栈(代码版)_第9张图片
最后一句就是T指针向前移动,指向新分配的空间。以后的压栈就是上面的重复操作。
(四)、出栈,以销毁链栈操作为例

while(T->top->next!=NULL)
		{
			param=T->top;
			T->top=param->next;//回退
			T->counter--;
			free(param);//把结点回收
		}
		free(T->top);
		T->top=NULL;

咱们接着看几幅图理解一下如何出栈并销毁链栈的。
假设栈中的元素如下
数据结构(C语言版)——链栈(代码版)_第10张图片
现在开始销毁栈

param=T->top;

数据结构(C语言版)——链栈(代码版)_第11张图片
parm和T->top指向同一个地方

T->top=param->next

数据结构(C语言版)——链栈(代码版)_第12张图片
这一步T回退到之前(能不能回退到上一个地址,需要while中的T->top->next!=NULL判断,它的意思是,如果不是栈底的话就可以回退,否则退出循环)

T->counter–;

数据结构(C语言版)——链栈(代码版)_第13张图片
把counter-1;表示出栈

free(param)

数据结构(C语言版)——链栈(代码版)_第14张图片

因为T已经回退了,所以之前的结点就可以销毁了。
就这样循环下去,直到循环条件不成立。退出循环,到下面的情况

数据结构(C语言版)——链栈(代码版)_第15张图片

free(T->top);

数据结构(C语言版)——链栈(代码版)_第16张图片
把T->top指向的地址空间给销毁了。

最后

T->top=NULL;

数据结构(C语言版)——链栈(代码版)_第17张图片
top指向了空,以上是销毁的全部过程

三、运行截图

①:初始化栈,然后压出1 2 3 4 5元素到栈中。并返回栈顶元素
数据结构(C语言版)——链栈(代码版)_第18张图片
数据结构(C语言版)——链栈(代码版)_第19张图片
数据结构(C语言版)——链栈(代码版)_第20张图片
②:返回并删除栈顶元素,判断是否为空栈,最后清空栈
数据结构(C语言版)——链栈(代码版)_第21张图片
数据结构(C语言版)——链栈(代码版)_第22张图片
数据结构(C语言版)——链栈(代码版)_第23张图片
③:看是否能返回栈顶元素,最后销毁栈
数据结构(C语言版)——链栈(代码版)_第24张图片
数据结构(C语言版)——链栈(代码版)_第25张图片

如有错误欢迎指出
本篇博客源代码和文件已经上传,欢迎下载

https://download.csdn.net/download/qq_42683219/12882019

你可能感兴趣的:(数据结构,链栈)