数据结构之栈的链式存储结构 C语言版

前言

在上次单链表的实现之后,由于为期末考试所累,暂停了,回家后电脑又坏了,由于系统崩溃重装了系统,之前写的循环链表的东西都没了,之后休息了几天,决定先搞栈这个东西吧。由于我是照程杰老师的书学习的,所以很多思想方法都是继承程杰老师的

1.栈的作用

栈和链表其实有很多共通之处,那么为什么还要链表呢。这就像明明你可以两条腿走路,干嘛还要乘坐火车和飞机呢。栈的特点是先进后出,浏览器的后退键,还有其他软件的撤销键,都用到了栈。而且链栈不存在栈满的情况。

2.栈的定义

栈还是用结构体来定义,但是和单链表不同的是,栈用了两个结构体来定义,多出来的那一个结构体我管他叫“管理者”,他的作用是控制插入和删除。而且在链栈中我们是不需要头结点的,而且只有压栈是才会新创建一个结点,所以没有必要把新创建结点的函数单独拿出来作为一个独立模块,我们需要的是高聚合度,低耦合度。栈的定义代码如下:

//定义结点(普通链表)
typedef struct StackNode
{
	SElemType data;
	struct StackNode* next;
}StackNode,*LinkStackPtr;
//定义栈(管理者)
typedef struct LinkStack
{
	LinkStackPtr top;
	int count;
}LinkStack;

3.内容布局

本篇文章所涉及的主要操作有:
1.压栈

p->next = s->top;
s->top = p;
s->count++;

2.出栈

*e = s->top->data;
p = s->top;
s->top = s->top->next;
free(p);
s->count--;

4.操作的一些图解

栈的操作

代码如下

/*
程序名称:链栈的建立与基本操作
编译环境:vs2010
最后修改:2019.7.31
作者:许安
*/

#include<stdio.h>
#include<stdlib.h>

#define OK 1
#define ERROR 0
typedef int Status;
typedef int SElemType;
//定义结点(普通链表)
typedef struct StackNode
{
	SElemType data;
	struct StackNode* next;
}StackNode,*LinkStackPtr;
//定义栈(管理者)
typedef struct LinkStack
{
	LinkStackPtr top;
	int count;
}LinkStack;

Status InitStack(LinkStack *s);//初始化栈
Status ClearStack(LinkStack *s);//清空栈
Status StackElem(LinkStack *s);//判断栈是否为空
Status GetTop(LinkStack *s,SElemType *e);//取栈顶元素
Status Push(LinkStack *s);//压栈
Status Pop(LinkStack *s,SElemType *e);//出栈
Status OutStack(LinkStack *s);//读栈

int main()
{
	LinkStack s;
	SElemType e;
	int i,x=0,n=0;
	if(InitStack(&s))
		printf("初始化成功!\n");
	else
		printf("初始化失败!\n");
	if(StackElem(&s))
		printf("栈为空!\n");
	else
		printf("栈非空!\n");
	while(n != 7)
	{
		printf("----------------------------\n");
		printf("$1.压栈 $2.出栈 $3.清空栈  $\n");
		scanf("%d",&n);
		switch(n)
		{
		case 1:
			i = Push(&s);
			if(i == ERROR)
				printf("压入失败\n");
			else
				printf("操作后的栈\n");
			OutStack(&s);
			break;
		case 2:
			i = Pop(&s,&e);
			if(i == ERROR)
				printf("出栈失败\n");
			else
				printf("成功,出栈的数:%d\n",e);
			printf("操作后的栈:\n");
			OutStack(&s);
			break;
		case 3:
			i = ClearStack(&s);
			if(i == ERROR)
				printf("清空失败\n");
			else
				printf("操作后的栈\n");
			OutStack(&s);
			break;
		}
	}
}

Status InitStack(LinkStack *s)
{
	s->top = NULL;
	s->count = 0;
	return OK;
}

Status ClearStack(LinkStack *s)
{
	LinkStackPtr p,q;
	p = s->top;
	while(p)
	{
		q = p;
		p = p->next;
		free(q);
	}
	s->top = NULL;
	s->count = 0;
	return OK;
}

Status StackElem(LinkStack *s)
{
	if(s->count == 0)
		return OK;
	else
		return ERROR;
}

Status GetTop(LinkStack *s,SElemType *e)
{
	if(s->top == NULL)
		return ERROR;
	else
		*e = s->top->data;
	return OK;
}

Status Push(LinkStack *s)
{
	int i,x=0;
	printf("输入您要压进去的数,-1时停止\n");
	for(i = 0;x!=-1;i++)
	{
		scanf("%d",&x);
		if(x!=-1)
		{
			LinkStackPtr p = (LinkStackPtr)malloc(sizeof(StackNode));
			if(!p)
				return ERROR;
			p->data = x;
			p->next = s->top;
			s->top = p;
			s->count++;
		}
	}
	return OK;
}

Status Pop(LinkStack *s,SElemType *e)
{
	LinkStackPtr p;
	if(s->top == NULL)
		return ERROR;
	*e = s->top->data;
	p = s->top;
	s->top = s->top->next;
	free(p);
	s->count--;
	return OK;
}

Status OutStack(LinkStack *s)
{
	LinkStackPtr p = s->top;
	printf("栈内容为:\n");
	while(p)
	{
		printf("%d	",p->data);
		p = p->next;
	}
	printf("\n");
	printf("栈的长度为:%d	\n",s->count);
	return OK;
}

运行结果

运行结果

后记

可能有同学发现了,链栈是把头结点的那一段当作了栈顶,那是因为在单链表中本身就有一个头结点,为了方便就用头结点代替栈指针。

上述代码把链表
栈的各种操作柔和到一个方程里面,以致于代码有些庞大,但是在实际操作中还可以适当加减操作

以上就是链栈的表示和各种操作,喜欢的多多支持哦~

发布了12 篇原创文章 · 获赞 10 · 访问量 1144

猜你喜欢

转载自blog.csdn.net/bsqetuo/article/details/97886961