数据结构与算法(二)栈

1、栈

1.1、什么是栈

栈的结构类似于枪的弹夹,第一颗放入弹夹的子弹却是最后一颗被打出来,最后一颗放入弹夹的子弹却是第一颗被打出来,称为先进后出的数据结构。

现实中,栈的应用非常广泛和普遍,例如,使用浏览器上网时,不管什么浏览器都会有 个"后退"键,点击后可以按访问顺序的逆序,加载浏览过的网页;如office、photoshop等文档或图像的编辑软件中,都有撤销(undo)的操作,也是使用栈来实现的。

栈的定义:栈(stack)是限定仅能在表尾进行插入和删除的线性结构。

我们通常把可以进行插入和删除的一端称为栈顶,就像弹夹可以放入子弹的一端是位于弹夹顶部的,另一端则称为栈底,不含任何数据元素的栈称为空栈。

首先它是一个线性表 ,也就是说,栈元素具有线性关系,即前驱后继关系。只不过栈是一种特殊的线性表而已。栈的特殊之处就在于限制了这个线性表的插入和删除位置,它始终只在栈顶进行。这也就使得:栈底是固定的,最先进栈的只能在栈底。

栈的插入操作,叫作进栈,也叫压栈、入栈。
栈的删除操作,叫作出栈,也叫弹栈。

这个最先进栈的元素,是不是一定就只能最后出栈呢? 

答案是不一定,栈只是对线性表的插入和删除的位置进行了限制 ,并没有对元素进出的时间进行限制,也就是说,在所有元素没有完全进栈时,先进栈的元素也可以先出栈,只要保证是栈顶元素出栈即可。就像我们有五颗子弹来打枪,先放入三颗子弹,打了两枪,再放入一颗子弹,又打了两枪,再放入一颗子弹,最后把这课子弹打出去,此时最后入栈的子弹最后打出去。

1.2、栈的基本功能

InitStack:初始化操作,建立一个空栈。
DestroyStack:若栈存在,则销毁栈。
ClearStack:清空栈元素。
StackEmpty:判断栈是否为空栈。
GetTop:若栈存在且非空,返回栈顶元素。
Push:入栈,将新元素放置栈顶。
Pop :弹栈,返回栈顶元素并删除该栈顶元素。
StackLength:返回栈的元素个数。

2、栈的数组结构实现

栈的一切操作取决于栈顶指针,实现栈的功能更多的是对栈顶指针的操作。

2.1、入栈操作

int Push(Stack *s, DataType element)
{
	if (s->top >= MAXSIZE-1) return 0; //如果栈满则返回错误 
	s->top++;                          //栈顶指针向上移到空位 
	s->data[s->top] = element;         //将新元素赋给栈顶
	return 1;
}

2.2、出栈操作

DataType Pop(Stack *s)
{
	if (s->top <= -1) return 0;  //如果栈空则返回错误      
	DataType element = 0;        //初始化一个返回值 
	element = s->data[s->top];   //将栈顶元素赋给返回值 
	s->top--;                    //栈顶指针向下移 
	return element;
}

两个最重要功能都没有涉及任何循环, 因此时间复杂度都为O(1)。

实现栈的数组结构还是非常简单的,因为它只准栈顶进出元素,所以不存在线性表插入和删除时需要移动大量元素的问题。不过栈的数组结构还是有个很大的缺陷,就是必须事先确定数组存储空间大小,万一不够用了,就需要编程手段来扩展数组的容量,非常麻烦。

3、栈的链表结构实现

栈的链表结构简称链栈,栈只是用栈顶来进行操作,单链表有头指针而栈顶指针也是必须,所以可以让他们合二为一:头结点的头指针为栈顶指针,头结点的数据用来记录栈元素个数。

对于链栈来说,基本不存在满栈的情况,所以无需考虑。

3.1、入栈操作

int Push(LinkStackTop *s, DataType element)
{
	LinkStackNode *node = new LinkStackNode;
	node->data = element;   //新元素赋值给新节点
	node->next = s->top;    //新节点的后继节点为当前栈顶节点
	s->top = node;          //新节点成为栈顶节点
	s->length++;            //栈元素个数加一 
	return 1;
} 

3.2、出栈操作

DataType Pop(LinkStackTop *s)
{
	if (StackEmpty(s) == 0) return 0;//如果栈空则返回错误      
	DataType element = 0;            //初始化一个返回值 
	LinkStackNode *node = s->top;    //得到栈顶节点 
	element = node->data;            //将栈顶元素赋给返回值 
	s->top = node->next;             //删除栈顶节点 
	s->length--;                     //栈元素个数减一 
	free(node);
	return element;
}

两个最重要功能在链表结构中的时间复杂度也都为O(1),只是清空栈操作稍微麻烦一下。 

4、对比两种结构的栈

和栈的链表结构在实现上比栈的数组结构稍微复杂一点,但时间复杂度基本相同。相较之下,栈的链表结构的优点在于不会满栈,不受限制,比较灵活,因此更推荐栈的链表结构。

附录一: 栈的数组结构实现全部基本功能

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

const int MAXSIZE=10;

typedef int DataType;        //栈的数据元素类型 
typedef struct {
	DataType data[MAXSIZE];  //栈的数组 
	int top;                 //栈顶指针 
}Stack;

Stack* InitStack()
{
	Stack *s = new Stack;
	s->top = -1;
	return s;
}

int StackEmpty(Stack *s) 
{
	if (s->top <= -1) return 0;
	else return 1;
}

int Push(Stack *s, DataType element)
{
	if (s->top >= MAXSIZE-1) return 0; //如果栈满则返回错误 
	s->top++;                          //栈顶指针向上移到空位 
	s->data[s->top] = element;         //将新元素赋给栈顶
	return 1;
}

DataType Pop(Stack *s)
{
	if (StackEmpty(s) == 0) return 0;//如果栈空则返回错误      
	DataType element = 0;            //初始化一个返回值 
	element = s->data[s->top];       //将栈顶元素赋给返回值 
	s->top--;                        //栈顶指针向下移 
	return element;
}

DataType GetTop(Stack *s) 
{
	if (StackEmpty(s) == 0) return 0;//如果栈空则返回错误      
	DataType element = 0;            //初始化一个返回值 
	element = s->data[s->top];       //将栈顶元素赋给返回值
								     //不需要删除栈顶元素,栈顶指针不用下移 
	return element;
}

void ClearStack(Stack *s) 
{
	s->top=-1;
}

int StackLength(Stack *s) 
{
	return s->top+1;
}

void DestroyStack(Stack *s) 
{
	free(s);
}

int main() 
{ 
	Stack *s =InitStack();
	return 0;
}

附录二: 栈的链表结构实现全部基本功能

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

typedef int DataType;  //栈的数据元素类型 
typedef struct StackNode{
	DataType data;     //栈的数据
	StackNode *next;   //后继指针 
}LinkStackNode;

typedef struct {
	int length;        //栈元素个数 
	StackNode *top;    //栈顶指针 
}LinkStackTop;

LinkStackTop* InitStack()
{
	LinkStackTop *s = new LinkStackTop;
	s->length = 0;
	s->top = NULL;
	return s;
}

int StackEmpty(LinkStackTop *s) 
{
	if (s->top == NULL) return 0;
	else return 1;
}

int Push(LinkStackTop *s, DataType element)
{
	LinkStackNode *node = new LinkStackNode;
	node->data = element;   //新元素赋值给新节点
	node->next = s->top;    //新节点的后继节点为当前栈顶节点
	s->top = node;          //新节点成为栈顶节点
	s->length++;            //栈元素个数加一 
	return 1;
} 

DataType Pop(LinkStackTop *s)
{
	if (StackEmpty(s) == 0) return 0;//如果栈空则返回错误      
	DataType element = 0;            //初始化一个返回值 
	LinkStackNode *node = s->top;    //得到栈顶节点 
	element = node->data;            //将栈顶元素赋给返回值 
	s->top = node->next;             //删除栈顶节点 
	s->length--;                     //栈元素个数减一 
	free(node);
	return element;
}

DataType GetTop(LinkStackTop *s) 
{
	if (StackEmpty(s) == 0) return 0;//如果栈空则返回错误      
	DataType element = 0;            //初始化一个返回值 
	LinkStackNode *node = s->top;    //得到栈顶节点 
	element = node->data;            //将栈顶元素赋给返回值 
	return element;
}

void ClearStack(LinkStackTop *s) 
{
	while (s->top != NULL) 
	{
		LinkStackNode *node = new LinkStackNode;
		node = s->top;
		s->top=node->next;
		free(node);
	}
	s->top = NULL;
	s->length = 0;
}

int StackLength(LinkStackTop *s) 
{
	return s->length;
}

void DestroyStack(LinkStackTop *s) 
{
	if (s->top != NULL) ClearStack(s);
	free(s);
}

int main() 
{ 
	LinkStackTop *s = InitStack();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36557133/article/details/89298016