数据结构(六)—— 栈

1.栈的定义与用处

 

        栈是只允许在一端进行插入或者删除操作的线性表。栈顶,线性表允许进行插入删除的那一端;栈底,固定的不允许插入的一端。如下图所示:

        栈的操作是先进后出,因此常用在函数的传值或传值,就是一般在进行函数的操作时,如果传入的值超过函数栈时,就会报出栈溢出的错误。

        栈与线性表的不同仅在于运算规则的不同:

2.栈的线性表实现

        因为栈时从一端进入一端出来,因此用线性存储时,将插入的元素都置于表尾即可,因此插入取出删除都是在表尾进行。

        这里栈的顺序表的实现定义,一个是数据的指针域一个为其栈顶,通过判断是否已经到达栈顶,从而去判断栈空或者栈满。而指针域指向的数据则是存储栈的内容。

        另外一种栈的顺序表的实现定义,可以定义为栈底指针跟栈顶指针,通过判断栈顶与栈底相减从而判断栈空或者栈满。

        栈顺序表的实现跟一般线性表顺序表实现是非常相似的,只有进栈出栈的规则不一样罢了。

栈的顺序定义可为:

#define MaxSize 50
typedef int Elemtype;
typedef struct Stack
{
	Elemtype* data;
	int top;
}SqStack;

栈的顺序表实现有以下函数:

SqStack InitStack(SqStack* S);           //初始化空栈
Status StackEmpty(SqStack S);            //判断栈是否为空
Status Push(SqStack* S, int x);          //进栈
Status Pop(SqStack* S, Elemtype* e);     //出栈
Status GetTop(SqStack S, Elemtype* e);   //返回栈顶元素
Status DestroyStack(SqStack* S);         //销毁栈

具体实现代码:

Stack.h

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


#define OK 1
#define FALSE 0
#define MaxSize 50
typedef int Elemtype;
typedef int Status;

typedef struct Stack
{
	Elemtype* data;
	int top;
}SqStack;


SqStack InitStack(SqStack* S);           //初始化空栈
Status StackEmpty(SqStack S);            //判断栈是否为空
Status Push(SqStack* S, int x);          //进栈
Status Pop(SqStack* S, Elemtype* e);     //出栈
Status GetTop(SqStack S, Elemtype* e);   //返回栈顶元素
Status DestroyStack(SqStack* S);         //销毁栈

Stack.c

#include "Stack.h"

SqStack InitStack(SqStack* S)            //初始化空栈
{
	S->data = (Elemtype*)malloc(sizeof(Elemtype) * MaxSize);
	S->top = -1;
	return *S;
}
Status StackEmpty(SqStack S)             //判断栈是否为空
{
	if (S.top == -1)
	{
		return OK;
	}
	else {
		return FALSE;
	}
}
Status Push(SqStack* S, int x)          //进栈
{
	if (S->top == MaxSize - 1) {
		return FALSE;
	}
	S->data[++S->top] = x;
	return OK;
}
Status Pop(SqStack* S, Elemtype* e)           //出栈
{
	if (S->top == -1) {
		return FALSE;
	}
	*e = S->data[S->top];
	S->top--;
	return OK;
}
Status GetTop(SqStack S, Elemtype* e)  //返回栈顶元素
{
	if (S.top == -1)
	{
		return FALSE;
	}
	*e = S.data[S.top];
	return OK;
}
Status ClearStack(SqStack* S)
{
	for (int i = 0; i < MaxSize; i++)
	{
		if (S->top == -1)
		{
			break;
		}
		else {
			S->top--;
		}
	}
	return OK;
}
Status DestroyStack(SqStack* S)         //销毁栈
{
	ClearStack(S);
	if (S->data)
	{
		free(S->data);
	}
	return OK;
}

test.c

#include "Stack.h"

int main()
{
	SqStack S;
	Elemtype e;
	int x = 0;

	InitStack(&S);           //初始化空栈
	int Flag = StackEmpty(S); //判断栈是否为空
	for (x = 0; x < 10; x++)
	{
		Push(&S, x);              //进栈
	}
	for (x = 0; x < 5; x++)
	{
		Pop(&S, &e);               //出栈
		printf("%d ", e);
	}
	printf("\n");
	GetTop(S, &e);            //返回栈顶元素
	printf("%d \n", e);
	DestroyStack(&S);         //销毁栈
	if (GetTop(S, &e)) {
		printf("%d \n", e);
	}
	else {
		printf("出错了!");
	}
	

	return 0;
}

3.栈的链表实现

        栈的链表的实现,跟一般线性表的链表实现也是非常的相似,只有插入的位置在链表的头,而有带头结点的链表和没有带头结点的链表也有一定的区别,这里实现采用的是有带头结点的链表。带头结点的链表则是通过判断下一个指针是否为NULL从而来判断指针空与否。

        没有带头结点的链表的话其第一个元素就为栈顶,通过定义栈的长度从而去判断栈是否已经到底了。

以下实现是带头结点的链表;

栈链表定义:一个数据域跟一个指针域,指针域指向下一个结点的位置。

typedef int Elemtype;

typedef struct SNode
{
	Elemtype data;
	struct SNode* next;
}SNode,*LinkStack;

各种函数的定义:

typedef int Status;

LinkStack InitLinkStack(LinkStack S);     //初始化栈
Status StackEmpty(LinkStack S);           //判断栈空
Status Posh(LinkStack S,Elemtype e);      //进栈
Status Pop(LinkStack S, Elemtype* e);     //出栈
Status PrintStack(LinkStack S);           //打印栈
Status GetTop(SNode S, Elemtype* e);      //获取栈顶
Status ClearStack(LinkStack S);           //清空栈
Status DestryStack(LinkStack S);          //销毁栈

具体实现的文件

LinkStack.h

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

#define OK 1
#define FALSE 0

typedef int Status;
typedef int Elemtype;

typedef struct SNode
{
	Elemtype data;
	struct SNode* next;
}SNode,*LinkStack;

LinkStack InitLinkStack(LinkStack S);     //初始化栈
Status StackEmpty(LinkStack S);           //判断栈空
Status Posh(LinkStack S,Elemtype e);      //进栈
Status Pop(LinkStack S, Elemtype* e);     //出栈
Status PrintStack(LinkStack S);           //打印栈
Status GetTop(SNode S, Elemtype* e);      //获取栈顶
Status ClearStack(LinkStack S);           //清空栈
Status DestryStack(LinkStack S);          //销毁栈

LinkStack.c

#include "LinkStack.h"

LinkStack InitLinkStack(LinkStack S)        //初始化栈
{
	S = (LinkStack)malloc(sizeof(SNode)*2);
	if (S->next)
	{
		S->next = NULL;
	}
	return S;
}
Status StackEmpty(LinkStack S)           //判断栈空
{
	if (S->next == NULL)
		return OK;
	else
		return FALSE;
}
Status Posh(LinkStack S,Elemtype e)                 //进栈
{
	LinkStack new;
	if (StackEmpty(S)) {
		S->next = NULL;
		new = (LinkStack)malloc(sizeof(SNode));
		new->data = e;
		new->next = S->next;
		S->next = new;
	}
	else
	{
		new = (LinkStack)malloc(sizeof(SNode));
		new->data = e;
		new->next = S->next;
		S->next = new;
	}
	
	return OK;
}
Status Pop(LinkStack S, Elemtype* e)     //出栈
{
	LinkStack p = S->next;
	if (!StackEmpty(S)) {
		*e = p->data;
		S->next = p->next;
		free(p);
		return OK;
	}
	else 
		return FALSE;
}

Status PrintStack(LinkStack S)           //打印栈
{
	while (S->next != NULL )
	{
		S = S->next;
		printf("%d ", S->data);
	}
	printf("\n");
	return OK;
}
Status GetTop(SNode S, Elemtype* e)     //获取栈顶
{
	SNode* p = S.next;
	if (S.next != NULL) {
		*e = p->data;
		return OK;
	}
	else
		return FALSE;
}
Status ClearStack(LinkStack S)           //清空栈
{
	LinkStack p, q;
	p = S->next;
	while (p)
	{
		q = p->next;
		free(p);
		p = q;
	}
	S->next = NULL;
	return OK;
}
Status DestryStack(LinkStack S)          //销毁栈
{
	LinkStack p;
	while(S)
	{
		p = S;
		S = S->next;
		free(S);
	}
	return OK;
}

test.c

#include "LinkStack.h"

int main()
{
	SNode S;
	Elemtype e;
	S = *InitLinkStack(&S);        //初始化栈
	if (StackEmpty(&S))           //判断栈空
	{
		printf("栈是空的!\n");
	}
	//Posh(&S, 1);
	for (int i = 0; i < 5; i++)
	{
		Posh(&S, i);                 //进栈
	}
	PrintStack(&S);
	for (int i = 0; i < 4; i++)
	{
		//出栈
		if (Pop(&S, &e))
		{
			printf("%d ", e);
		}
		else {
			printf("栈下溢了!!\n");
		}
	}
	printf("\n");
	
	PrintStack(&S);
	//获取栈顶
	if (GetTop(S, &e)) {
		printf("此时栈顶为:%d\n", e);
	}
	else {
		printf("栈下溢了!!!\n");
	}
	PrintStack(&S);
	ClearStack(&S);           //清空栈
	DestryStack(&S);          //销毁栈
	return 0;
}

 总结:栈的理解和实现都是基于线性表的,因此,其理解起来也是相对比较简单。

链表实现过程中,采用头插法的方式进行插入,但是跟在创建链表不同的是,其不是一次性全部插入的,因此需要进行判断是否是第一个插入的结点,如果是则将插入后的下一个结点置为NULL,其他插入的话就直接插在第一个结点之前。还有初始化栈链表的时候,需要将链表返回在main函数中重新赋值,这样子链表的初始化就能够比较稳妥的成功。我遇到过初始化后,在进行进栈时,链表初始化就没用了,因此重新赋值一下会比较稳妥。

S = *InitLinkStack(&S);        //初始化栈

//进栈操作
if (StackEmpty(S)) {
		S->next = NULL;
		new = (LinkStack)malloc(sizeof(SNode));
		new->data = e;
		new->next = S->next;
		S->next = new;
	}
	else
	{
		new = (LinkStack)malloc(sizeof(SNode));
		new->data = e;
		new->next = S->next;
		S->next = new;
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值