数据结构之栈

数据结构之栈

什么是栈?

今天,我将具体分析栈。什么是栈,与链表不一样,打个比方。栈就像是一堆书,叠在一起,如果你要取最下面的一本书出来,那么,你首先要做的就是将这本书上方的书移开,才可以拿这本书。同理,想要这一系列的书本复原,你需要做的就是一本一本书往上叠。这个过程就是栈中存取数据的过程。
搜索引擎查找关于栈的相关定义,堆栈(英语:stack)又称为栈或堆叠,是计算机科学中的一种抽象资料类型,只允许在有序的线性资料集合的一端(称为堆栈顶端,英语:top)进行加入数据(英语:push)和移除数据(英语:pop)的运算。因而按照后进先出(LIFO, Last In First Out)的原理运作。
与栈类似又不一样的就是队列了,什么是队列,简单讲下,与栈不同的地方就是先进先出。以后我会详细介绍。
栈与队列的用法有很多,栈常用于深度优先搜索,逆波兰计算器(有空我会专门写一篇博文来介绍逆波兰算法),队列常用于广度优先搜索。栈的用途还有很多,比如我们浏览器浏览网站时,常常有回退,回头功能就是通过栈来完成的,还有我们平时常用的递归,也是通过栈来完成的,需要递归的算法,我们都可以讲其改成非递归实现。
与链表类似,栈也可以分成顺序栈和链栈,我们常用的也是链栈。

图解栈

在这里插入图片描述
这就是栈,数据只能从一端进,也从这一端出。
常见的有链栈和顺序栈,链栈的和上一节的线性表一样,不必考虑生成的栈的长度,增加一个结点,申请一块内存空间。
下面我们来看一看链栈的入栈图解

  1. 生成新结点
  2. 新结点的后继直接指向当前的栈顶结点
  3. 栈顶指针直接指向新结点

出栈操作类似,不一一举例。

栈的常用操作

顺序栈 ADT

Status initStack(SqStack *s,int sizes);//初始化栈
Status IsEmptyStack(SqStack *s);//判断栈是否为空
Status getTopStack(SqStack *s,ElemType *e);//获取栈顶元素
Status clearStack(SqStack *s);//清空栈
Status destoryStack(SqStack *s);//销毁栈
Status StackLength(SqStack *s);//获取栈的长度
Status pushStack(SqStack *s,ElemType data);//入栈
Status popStack(SqStack *s,ElemType *data);//出栈

上述的是顺序栈,链栈的基本操作也是如此,只需要稍微改动一下即可。

顺序栈的实现

头文件

/*filename:SqStack.h*/
#ifndef STACK_H_INCLUDED
#define STACK_H_INCLUDED

typedef enum Status 
{
	ERROR = 0, SUCCESS = 1
} Status;

typedef int ElemType;

typedef struct SqStack 
{
	ElemType *elem;
	int top;
	int size;
} SqStack;

//基于数组的顺序栈
Status initStack(SqStack *s,int sizes);//初始化栈
Status isEmptyStack(SqStack *s);//判断栈是否为空
Status getTopStack(SqStack *s,ElemType *e); //得到栈顶元素
Status clearStack(SqStack *s);//清空栈
Status destroyStack(SqStack *s);//销毁栈
Status stackLength(SqStack *s,int *length);//检测栈长度
Status pushStack(SqStack *s,ElemType data);//入栈
Status popStack(SqStack *s,ElemType *data);//出栈

#endif 

源文件

#include "SqStack.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


Status initStack(SqStack* s, int sizes)//初始化栈
{
    s->elem = (ElemType*)malloc(sizeof(ElemType) * sizes);
    s->top = -1;
    s->size = sizes;
}

Status isEmptyStack(SqStack* s)//判断栈是否为空
{
    if (s->top == 0)
        return SUCCESS;
}

Status getTopStack(SqStack* s, ElemType* e) //得到栈顶元素
{
    if (s->top == -1)
        return ERROR;
    *e = s->elem[s->top];
    return SUCCESS;
}

Status clearStack(SqStack* s)//清空栈
{
    if (s->top == -1)
        return ERROR;
    s->top = -1;
    return SUCCESS;
}

Status destroyStack(SqStack* s)//销毁栈
{
    free(s->elem);
    s->top = 0;
    s->size = 0;
    return SUCCESS;
}

Status stackLength(SqStack* s, int* length)//检测栈长度
{
    *length = s->top+1;
    return SUCCESS;
}

Status pushStack(SqStack* s, ElemType data)//入栈
{
    if (s->top == s->size - 1)/*判断栈是否已满*/
        return ERROR;
    s->top++;
    s->elem[s->top] = data;
    return SUCCESS;
}

Status popStack(SqStack* s, ElemType* data)//出栈
{
    if (s->top == -1)
        return ERROR;
    *data = s->elem[s->top];
    s->top--;
    return SUCCESS;
}

链式栈的实现

头文件

#ifndef STACK_H_INCLUDED
#define STACK_H_INCLUDED
#define NULL 0
typedef enum Status 
{
    ERROR = 0, 
	SUCCESS = 1
} Status;

typedef int ElemType;

typedef  struct StackNode
{
	ElemType data;
	struct StackNode *next;
}StackNode, *LinkStackPtr;

typedef  struct  LinkStack
{
	LinkStackPtr top;
	int	count;
}LinkStack;

//链栈
Status initLStack(LinkStack *s);//初始化栈
Status isEmptyLStack(LinkStack *s);//判断栈是否为空
Status getTopLStack(LinkStack *s,ElemType *e);//得到栈顶元素
Status clearLStack(LinkStack *s);//清空栈
Status destroyLStack(LinkStack *s);//销毁栈
Status LStackLength(LinkStack *s,int *length);//检测栈长度
Status pushLStack(LinkStack *s,ElemType data);//入栈
Status popLStack(LinkStack *s,ElemType *data);//出栈
#endif 

源文件

#include "LinkStack.h"
#include <stdio.h>

Status initLStack(LinkStack* s)//初始化栈
{
	LinkStackPtr S = (LinkStackPtr)malloc(sizeof(StackNode));
	S->next = NULL;
	s->top = S;
	s->count = 0;
}

Status isEmptyLStack(LinkStack* s)//判断栈是否为空
{
	if (s->count == 0)
		return SUCCESS;
	return ERROR;
}

Status getTopLStack(LinkStack* s, ElemType* e)//得到栈顶元素
{
	if (s->count == 0)
		return ERROR;
	else
		*e = s->top->data;
	return SUCCESS;
}

Status clearLStack(LinkStack* s)//清空栈
{
	if (s->count == 0)
		return ERROR;
	ElemType e;
	for (int i = s->count; i > 0; i--)
	{
		popLStack(s, &e);
	}
	return SUCCESS;
}

Status destroyLStack(LinkStack* s)//销毁栈
{
	if (isEmptyLStack(&s))
		return ERROR;
	while (s->top!=NULL)
	{
		LinkStackPtr p = s->top;
		s->top = s->top->next;
		free(p);
	}
	s->count = 0;
	return SUCCESS;
}

Status LStackLength(LinkStack* s, int* length)//检测栈长度
{
	*length = s->count;
	return SUCCESS;
}


Status pushLStack(LinkStack* s, ElemType data)//入栈
{
	LinkStackPtr p = (LinkStackPtr)malloc(sizeof(StackNode));
	if (p == NULL)
	{
		printf("动态分配内存失败!\n");
		return ERROR;
	}
	p->data = data;
	p->next = s->top;
	s->top = p;
	s->count++;
	return SUCCESS;
}

Status popLStack(LinkStack* s, ElemType* data)//出栈
{
	*data = s->top->data;
	LinkStackPtr p = s->top;
	s->top = s->top->next;
	free(p);
	s->count--;
	return SUCCESS;
}

忘记提醒大家了,注意,申请内存空间后后一定要记得free,否则会造成内存泄露。如果泄露了,以后这块内存就无法再使用了。

posted @ 2021-05-21 16:42  ChrisNg  阅读(177)  评论(0)    收藏  举报