数据结构与算法:线性表之栈

本文详细介绍了栈这一数据结构,包括其定义、存储结构(顺序栈与链栈)以及基本操作,如初始化、判断空栈、销毁栈、清空栈、获取栈的长度、获取栈顶元素、入栈、出栈和遍历栈。同时提供了C语言实现这些操作的代码示例。顺序栈和链栈各有特点,顺序栈在空间管理上更为简便,而链栈则在插入和删除操作上更灵活。
摘要由CSDN通过智能技术生成

栈是一种重要的线性结构。从数据结构角度来看,栈也是线性表,其特殊在于栈的基本操作是线性表操作的子集,它们的操作受限的线性表,因此可称为限定性的线性表。但从数据结构角度来看,它是和线性表大不相同的两类重要的抽象数据结构。由于它广泛应用在各种软件系统中,因此在面向对象的程序设计中,它是多型数据类型。



概念

栈的定义

:是限定仅在表尾进行插入或删除操作的线性表。因此,对于栈来说,表尾端有其特殊含义,称为栈顶(top),相应的,表头端称为栈底(buttom)。不含元素的空表称为空栈

假设栈S=(a1,a2,…an),则称a1为栈底元素,an为栈顶元素。栈中元素按a1,a2,······,an的次序进栈,退栈的第一个元素应为栈顶元素。换句话说,栈的修改是按后进先出的原则进行的。因此,栈的修改是按后进先出的原则进行的。因此,栈又称为后进先出的线性表(last in first out ,简称LIFO结构),如下图所示。

在这里插入图片描述

栈的存储结构

顺序栈:即栈的顺序储存结构是利用一组地址连续的储存单元依次存放自栈底到栈顶的数据元素,同时附设指针top指示栈顶元素在顺序栈中的位置。通常的习惯做法是以top=0表示空栈,鉴于C语言中数组的下标约定从0开始,则当以C作描述语言时,如此设定会带来很大不便;另一方面,由于栈在使用过程中所需最大空间的大小很难估计,因此,一般来说,在初始化设空栈时不应限定栈的最大容量。一个较合理的做法是:先为栈分配一个基本容量,然后在应用过程中,当栈的空间不够使用时再逐段扩大。为此,可设定两个变量:STACK_INIT_SIZE(储存空间初始分配量)和STACKINCREMNT(储存空间分配增量),并以下述类型说明作为顺序栈的定义

typdef struct{
	SElemType *base;//栈底指针
	SElemType *top;//栈顶指针
	int stacksize;//指示栈的当前可使用的最大容量
}SqStack;

base可称为栈底指针,在顺序栈中,它始终指向栈底的元素,若栈底base的值为NULL,则表明栈结构不存在。称top为栈顶元素,其初始值指向栈底,即top=base可以作为栈空的标志,每当插入新的栈顶元素时,指针top+1;删除栈顶元素时,指针top-1,因此,非空栈的栈顶指针始终在栈顶元素的下一个位置上

栈的基本操作

在这里我是想要实现插入一串数字再输出,所以所有的数据类型都是int,要是为了其他功能,可以适当更改数据类型。

先初始化一些全局变量

#define initsize 100;//储存空间初始分配量
#define size 10;//储存空间分配增量
1.1 顺序栈的初始化
typdef struct{
	int *base;//栈底指针
	int *top;//栈顶指针
	int stacksize;//指示栈的当前可使用的最大容量
}Stack;
1.2 链栈的初始化
typedef struct StackNode
{
	ElemType data;
	struct StackNode *next;
}StackNode,*LinkStack;

2.1 构造一个空顺序栈S
int InitStack (Stack *S){
    S->base = (int *)malloc(initsize * sizeof(int));
    if(!S->base) return 0;
    S->top = S->base;
    S->stacksize = initsize;
    return 1;
}
2.2 构造一个空链栈S
int InitStack(LinkStack *S)
{//构造一个空栈S,栈顶指针置空
	S=NULL:
	return 1:
}

3.1 判断顺序栈是否为空
int StackEmpty(Stack S)//判断是否为空栈 
{
	if(S->base==S->top) return 0;
	else return 1;
}
3.2 判断链栈是否为空
int StackEmpty()
{
	if (top->top == NULL)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}
4.1 销毁顺序栈
void DestroyStack(Stack *S){
	if(S->base){
    free(S->base);
    S->stacksize=0;
    S->base=S->top=NULL;
    }
}
4.2 销毁链栈
//销毁栈
void DestroyStack()
{
	stacknode* node = NULL;
	if (top->top == NULL)
	{
		printf("栈为建立,不用摧毁\n");
	}
	else
	{ 
		while (top->top != NULL)
		{
			node = (top->top)->next;
			free(top->top);
			top->top = node;
		}
		printf("摧毁成功\n");
	}
}
5.1 清空顺序栈
int ClearStack(Stack *S)
{
	if(S->base)
	{
		S->top=S->base;
	}
	return 1;
}
5.2 清空链栈
//清空栈
void ClearStack()
{
	stacknode* node = NULL;
	if (top->top == NULL)
	{
		printf("栈为建立,不用清空\n");
	}
	else if ((top->top)->next != NULL)
	{
		while ((top->top)->next != NULL)
		{
			node = (top->top)->next;
			free(top->top);
			top->top = node;
		}
		node->data = 0;
		printf("清空成功\n");
	}
	else
	{
		node = top->top;
		node->data = 0;
		printf("清空成功\n");
	}
}

6.1 获取顺序栈的长度
int StackLength(Stack S)
{
	return S->top - S->base;
}
6.2 获取链栈的长度
void StackLength()
{
	int deepnum = 0;
	stacknode* node;
	node = top->top;
	if (node == NULL)
	{
		printf("栈空深度为0\n");
	}
	else
	{
		printf("栈中深度为:\n");
		while (node != NULL)
		{
			deepnum++;
			node = node->next;
		}
		printf("%d",deepnum);
	}
}

7.1 获取顺序栈顶元素
int GetTop(Stack S,int *e)
{
	if(S->top != S->base)
	{
		e = *(S->top - 1);
		return 1;
	}
	else 
	{
		return 0;
	}
}
7.2 获取链栈栈顶元素

int GetTop(LinkStack S)
{//返回S的栈顶元素,不修改栈顶指针 
	if(S!=NULL)//栈非空 
		return S->data;//返回栈顶元素的值,栈顶指针不变 
}

8.1 插入新的元素作为顺序栈的新栈顶
//入栈操作
int Push(Stack* S, int e) {
	//判断栈是否已满
	if (S->top - S->base >= stacksize) {
		Stack q;
		q->base = (int*)realloc(S->base, (S->stacksize + size) * sizeof(Stack));
		if (!q->base) {
			return 0;
		}
		S->base = q->base;
		//更新top指针的指向
		S->top = S->base + S->stacksize;
		S->stacksize += size;
	}
	*(S->top)++ = e;
}



8.2 插入新的元素作为链栈的新栈顶

int Push(LinkStack *S,int e)
{// 在栈顶插入元素e
	StackNode *p;;//生成新节点
	p->data = e;//将新节点数据域置为e
	p->next = S;//将新节点插入栈顶
	S = p;//修改栈顶指针p
	return 1;
}

9.1 删除顺序栈顶元素,并返回该元素
int Pop(Stack *S,int *e){
//非法判断
    if(S->base==S->top){
        return 0;
    }
    S->top--;    //注意这里因为top指向栈中当前元素的上一个空间,所以要先将其位置减一
    e=*S->top;
    return 1;
    }
9.2 删除链栈顶元素,并返回该元素

int Pop(LinkStack *S,int *e)
{//删除S的栈顶元素,用e返回其值 
	
	if(S==NULL)
		return 0;//栈空 
	e = S->data;//将栈顶元素赋给e 
	p=S;//用p临时保存栈顶元素空间,以备释放 
	S=S->next;//修改栈顶指针 
	free(p);//释放原栈顶元素的空间 
	return 1;
} 


10.1 遍历顺序栈

int StackTraverse(Stack S){//从栈底到栈顶的方向
    if(S->top==S->base){
        return 0;
    }
    while(S->base < S->top ){
        printf("%d\t",*(S->base++));
    }
    printf("\n");
    return 1;
}
10.2 遍历链栈

int StackTraverse(LinkStack S)
{

	StackNode* node;
	node = top->top;
	if (node == NULL)
	{
		printf("栈空无法打印\n");
	}
	else
	{
		printf("栈中元素为:\n");
		while (node != NULL)
		{
			printf("%d\n",node->data);
			node = node->next;//让结点等于栈顶结点的后继
		}
	}

}

总结

顺序栈是指利用顺序存储结构实现的栈,即利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时设有指针top指示栈顶元素在顺序栈中的位置;另设指针base指示栈底元素在顺序栈中的位置。当top和base的值相等时,表示空栈。
链栈是指采用链式存储结构实现的栈,通常链栈用单链表表示。
没有特殊要去,顺序栈比链栈更实用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值