数据结构(C语言描述)栈

1 栈的基本概念

栈是一种特殊的表,这种表只在表首进行插入和删除操作。因此,表首对栈来说具有特殊的意义,称为栈顶。表尾称为栈底。不含任何元素的栈称为空栈。
假设一个栈S中的元素为a(n),a(n-1),…,a(1),则称a(1)为栈底元素,a(n)为栈顶元素。栈中元素按a(1),a(2),……,a(n)的次序进栈。在任何时候,出栈的元素都是栈顶元素。换句话说,栈的修改是按后进先出的原则进行的。因此,栈又称为后进先出(Last In First Out) 表, 简称为LIFO表
在这里插入图片描述

栈也是一个抽象数据类型。常用的栈运算如下。
(1) StackEmpty(S):测试栈S是否为空。
(2) StackFull(S) :测试栈S是否已满。
(3) StackTop(S) :返回栈S的栈顶元素。
(4) Push(x, S) :在栈S的栈顶插入元素x, 简称为将元素x入栈。
(5) Pop(S) :删除并返回栈S的栈顶元素, 简称为抛栈。
栈的应用非常广泛, 只要问题满足LIFO原则, 就可以使用栈。

2 用数组实现栈

用一个数组data存储栈元素时,栈底固定在数组的底部,即data[0]为最早入栈的元素,并让栈向数组上方(下标增大的方向)扩展。

2.1 用数组实现的栈结构

Stack定义如下。

typedef struct astack *Stack;//栈指针类型
typedef struct astack;//栈结构
	int top,//栈顶
	maxtop;//栈空间上界
	StackItem *data;//存储栈元素的数组
}Sstack;

栈元素存储在数组data中,用top指向当前栈顶位置,栈顶元素存储在data[top]中,栈的容量为maxtop。

2.2 栈元素的类型定义

将栈元素的类型定义为int。

typedef int StackItem;//栈元素类型int
typedef StackItem *addr;//栈元素指针类型

2.3 函数StackInit(size)

创建一个容量为size的空栈。

Stack StackInit(int size)
{
    
    
	Stack S=(Stack)malloc(sizeof *S);
	S->data=(StackItem *)malloc(size*sizeof(StackItem));
	S->maxtop=size;
	S->top=-1;
	return S;
}

2.4 函数StackEmpty(S)

当top=-1时当前栈为空栈。

int StackEmpty(Stack S)
{
    
    
	return S->top<0;
}

2.5 函数StackFull(S)

当top=maxtop时当前栈满。

int StackFull(Stack S)
{
    
    
	return S->top>=S->maxtop;
}

2.6 函数StackTop(S)

栈顶元素存储在data[top]中。

StackItem StackTop(Stack S)
{
    
    //前提栈为非空
	if(StackEmpty(S)) exit(1);
	return S->data[S->top];
}

2.7 函数Push(x,S)

新栈顶元素x应存储在data[top+1]中。

void Push(StackItem x,Stack S)
{
    
    //前提栈未满
	if(StackFull(S)) exit(1);
	S->data[++S->top]=x;
}

2.8 函数Pop(S)

删除栈顶元素后,新栈顶元素在data[top-1]中。

StackItem Pop(Stack S)
{
    
    //栈为非空
	if(StackEmpty(S)) exit(1);
	return S->data[S->top--];
}

2.9 函数StackFree(S)

由于数组data是动态分配的,在使用结束时应由StackFree释放分配给data的空间,以免产生内存泄漏。

void StackFree(Stack S)
{
    
    
	free(S->data);
	free(S);
}

2.10 使用多个栈

在一些算法中使用栈时,常需要同时使用多个栈。为了使每个栈在算法运行过程中不会溢出,通常要为每个栈预置一个较大的栈空间。但做到这一点并不容易,因为各个栈在算法运行过程中实际所用的最大空间很难估计。另一方面,各个栈的实际大小在算法运行过程中不断变化,经常会发生其中一个栈满,而另一个栈空的情形。
]假设让程序中的两个栈共享一个数组data[0:n] 。利用栈底位置不变的特性,可以将两个栈的栈底分别设在数组data的两端,然后各自向数组data的中间伸展。这两个栈的栈顶初值分别为0和n,当两个栈的栈顶相遇时才可能发生上溢。由于两个栈之间可以互补余缺,每个栈实际可用的最大空间往往大于n/2。
共享同一数组空间的两个栈
在这里插入图片描述

3 用指针实现栈

用指针实现栈,称为链栈,如下图。
在这里插入图片描述

3.1 链栈的结点类型定义

typedef struct snode *slink;//栈结点指针类型
typedef struct snode{
    
    //栈结构
	StackItem element;//栈元素
	slink next;//下一结点指针
}StackNode;

slink NewStackNode()
{
    
    
	return (slink)malloc(sizeof(StackNode));
}

其数据成员element存储栈元素,next是指向下一个结点的指针,函数NewStackNode()创建一个新结点。

3.2 用指针实现的链栈Stack

typedef struct lstack *Stack;//栈指针类型
typedef struct lstack{
    
    //栈结构
	slink top;//栈顶指针
}Lstack;

top是指向栈顶结点的指针。

3.3 函数StackInit(size)

函数StackInit()将top置为空指针,创建一个空栈。

Stack StackInit()
{
    
    
	Stack S=(Stack)malloc(sizeof *S);
	S->top=0;
	return S;
}

3.4 函数StackEmpty(S)

检测指向栈顶的指针top是否为空指针。

int StackEmpty(Stack S)
{
    
    
	return S->top==0;
}

3.5 函数StackTop(S)

返回栈S的栈顶结点中的元素。

StackItem StackTop(Stack S)
{
    
    //前提栈为非空
if(StackEmpty(S)) exit(1);
return S->top->element;
}

3.6 函数Push(x,S)

函数Push(x,S)先为元素x创建一个新结点,然后修改S的栈结点指针top使新结点成为新栈顶结点。

void Push(StackItem x,Stack S)
{
    
    
	slink p=NewStackNode();
	p->element=x;
	p->next=S->top;
	S->top=p;
}

3.7 函数Pop(S)

函数Pop(S)先将S的栈顶元素存于x中,然后修改栈顶指针使其指向栈顶元素的下一个元素,从而删除栈顶元素,最后返回x。

StackItem Pop(Stack S)
{
    
    //前提栈非空
	if(StackEmpty(S)) exit(1);
	StackItem x=S->top->element;
	slink p=S->top;
	S->top=p->next;
	free(p);
	return x;
}

猜你喜欢

转载自blog.csdn.net/qq_45059457/article/details/114778129