【顺序栈的实现1】--------含栈顶,栈底指针;栈顶指针指向栈顶元素的下一个位置

1. 栈的抽象数据类型定义:

在这里插入图片描述

2.顺序栈的存储方式

同一般线性表的顺序存储结构完全相同:
利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素栈底一般在低地址端。

  • 附设top指针指示栈顶元素在顺序栈中的位置
  • 另设base指针指示栈底元素在顺序栈中的位置
  • 另外,用stacksize表示栈可使用的最大容量

但是,为了方便操作,通常top指向真正的栈顶元素 之上的 下标地址,如下图
在这里插入图片描述

3.顺序栈的相关基础操作汇总

  • 初始化操作:操作结果:构造一个空栈 S。
InitStack(SqStack* s)
  • 判定S是否为空栈:
    初始条件:栈S 已存在。
    操作结果:若栈S为空栈,则返回TRUE,否则 FALSE.
StackEmpty(SqStack s)
  • 求栈的长度
    初始条件:栈S 已存在。
    操作结果:返回S的元素个数,即栈的长度
StackLength(SqStack s)
  • 栈置空操作:
    初始条件:栈S 已存在。
    操作结果:将S清为空栈。
ClearStack(SqStack * s)
  • 销毁栈操作:
    初始条件:栈S 已存在。
    操作结果:栈S 被销毁。
DestroyStack(SqStack *s)
  • 入栈操作(重点)
    初始条件:栈S已存在且未满
    操作结果:插入元素e为新的栈顶元素。
Push(SqStack* s, SElemType e)
  • 出栈操作(重点)
    初始条件:栈S 已存在且非空:
    操作结果:删除S的栈顶元素a.,并用e返回其值。
Pop(SqStack* s, SElemType* e)
  • 取栈顶元素
    初始条件:栈S 已存在且非空。
    操作结果:用e返回S的栈顶元素。
GetTop(SqStack s, SElemType* e)
  • 从栈顶开始输出整栈
    初始条件:栈S 已存在且非空。
    操作结果:从栈顶输出栈中所有元素。
printStack(SqStack s)

4.整栈操作模拟与异常分析

4.1操作模拟:

由于本篇中顺序栈含栈顶,栈底指针并且栈顶指针指向栈顶元素的下一个位置
在这里插入图片描述
所以空栈与栈满的判断条件也有所不同:
在这里插入图片描述

4.2异常处理:

使用数组作为顺序栈存储方式的特点:
在这里插入图片描述
而这里我们要注意:
上溢是一种错误,使问题的处理无法进行;
而下溢一般认为是一种结束条件,即问题处理结束。

5.顺序栈的整表创建(含栈底,栈顶指针)

5.1顺序栈的结构定义:
typedef struct Sqstack
{
	SElemType* base;//栈底指针
	SElemType* top;//栈顶指针

	int stacksize;//栈可用的最大容量
}SqStack;
  • 在结构定义中,一个顺序栈里包含了栈底指针栈顶指针,以及栈可用的最大容量这三个部分
  • 而别名SqStack用来定义顺序栈
    SqStack* 用来表示指向栈的指针
5.2顺序栈的初始化

注意:传入参数时,需传入栈的指针,即&s,这样才能修改栈中的数据

bool InitStack(SqStack* s)
5.2.1算法步骤:

(1)为顺序栈初始化空间,同时让栈底指针(base)指向被初始化的空间
(2)初始化栈顶指针 指向栈底位置
(3)初始化该顺序栈的最大容量

在这里插入图片描述

//2.顺序栈的初始化
//注意:传入参数时,需传入栈的指针,即&s,这样才能修改栈中的数据
bool InitStack(SqStack* s)
{
	//[1]为顺序栈初始化空间,同时让栈底指针指向被初始化的空间
	s->base = (SElemType *)malloc(sizeof(SElemType) * MAXSIZE);

	if (s->base == NULL)
	{
		printf("内存分配失败!\n");
		exit(-1);
	}

	//[2]初始化栈顶指针 指向栈底位置
	s->top = s->base;

	//[3]初始化该顺序栈的最大容量
	s->stacksize = MAXSIZE;
	return true;
}
5.3判断顺序栈是否为空

注意:传入参数时,不需要传入栈的指针,即&s,因为判空操作只需要访问栈顶指针与栈底指针,并不做修改

bool StackEmpty(SqStack s)
5.3.1算法步骤:

(1)若栈顶指针与栈底指针相同,说明栈空;否则栈非空

在这里插入图片描述

//3.判断顺序栈是否为空
//注意:传入参数时,不需要传入栈的指针,即&s,因为判空操作只需要访问栈顶指针与栈底指针,并不做修改
bool StackEmpty(SqStack s)
{

	//[1]若栈顶指针与栈底指针相同,说明栈空
	if (s.top == s.base)
	{
		return true;
	}
	else
	{
		return false;
	}
}
5.4求顺序栈的长度

注意:传入参数时,不需要传入栈的指针,即&s,因为求长度只需要计算栈顶指针与栈底指针之差,并不做修改

int StackLength(SqStack s)
5.4.1算法步骤:

(1)栈顶指针 与 栈底指针的 差值即为顺序栈的长度

这里直接使用指针的差值,不需要"/sizeof(SqElemType)";因为两个指针的基类型为同一类型,其相减结果即为顺序栈的长度
在这里插入图片描述

//4.求顺序栈的长度
//注意:传入参数时,不需要传入栈的指针,即&s,因为求长度只需要计算栈顶指针与栈底指针之差,并不做修改
int StackLength(SqStack s)
{
	//栈顶指针 与 栈底指针的 差值即为顺序栈的长度
	return s.top - s.base;
}
5.5清空顺序栈

注意:传入参数时,需要传入栈的指针,即&s,因为清空栈需要修改栈顶指针,即s.top

bool ClearStack(SqStack * s)
5.5.1算法步骤:

(1)判断栈内存是否分配(通过判断栈底指针是否为空来实现)
(2)修改栈顶指针指向栈底位置即为清空(由于进栈时值会覆盖,故不需要删除元素值)

在这里插入图片描述
在这里插入图片描述

//5.清空顺序栈
//注意:传入参数时,需要传入栈的指针,即&s,因为清空栈需要修改栈顶指针,即s.top
bool ClearStack(SqStack * s)
{
	//[1]判断栈内存是否分配
	if (s->base == NULL)
	{
		printf("栈不存在!\n");
		return false;
	}

	//[2]修改 栈顶指针 指向 栈底位置,即为清空
	//(由于进栈时值会覆盖,故不需要删除元素值)
	s->top = s->base;
	return true;
}
5.6销毁顺序栈

注意:传入参数时,需要传入栈的指针,即&s,因为销毁栈需要修改清空内存,并置空栈中指针以及栈大小

bool DestroyStack(SqStack *s)
5.6.1算法步骤:

(1)若当前顺序栈存在,则先释放内存,再置空栈大小以及栈指针
<1>通过栈底指针释放内存
<2>置空栈大小以及栈指针(防止悬挂指针问题)

最终栈里除了stacksize,base和top被置空以外,其余部分均被销毁

//6.销毁顺序栈
//注意:传入参数时,需要传入栈的指针,即&s,因为销毁栈需要修改清空内存,并置空栈中指针以及栈大小
bool DestroyStack(SqStack *s)
{
	//[1]若当前顺序栈存在,则先释放内存,再置空栈大小以及栈指针
	if (s->base != NULL)
	{
		//<1>通过栈底指针释放内存
		free(s->base);
		
		//<2>置空栈大小以及栈指针
		s->stacksize = 0;

		s->base = NULL;
		s->top = NULL;
	}
	return true;
}
5.7顺序栈的入栈(核心1)

注意:传入参数时,需要传入栈的指针,即&s,因为入栈操作需要 更改栈顶指针以及 添加栈顶元素

bool Push(SqStack* s, SElemType e)
5.7.1算法步骤:

(1)判断栈是否已满(即 栈顶指针 与 栈底指针 之差 是否等于 栈的最大容量)
(2)入栈操作:
<1>先将元素e赋值给栈顶指针当前指向的位置
<2>然后栈顶指针自增1,指向当前 栈顶元素的 下一个位置

入栈操作可以浓缩为一步:
*s->top++ = e;

在这里插入图片描述

//7.核心1:顺序栈的入栈
//注意:传入参数时,需要传入栈的指针,即&s,因为入栈操作需要 更改栈顶指针以及 添加栈顶元素
bool Push(SqStack* s, SElemType e)
{
	//[1]判断栈是否已满(即 栈顶指针 与 栈底指针 之差 是否等于 栈的最大容量)
	if (s->top - s->base == s->stacksize)
	{
		printf("栈满!\n");
		return false;
	}

	//[2]入栈操作:
	//<1>先将元素e赋值给栈顶指针当前指向的位置
	*(s->top) = e;
	
	//<2>然后栈顶指针自增1,指向当前 栈顶元素的 下一个位置
	(s->top)++;
	//等价于 *s->top++ = e;先赋值,再向下移动

	return true;

}
5.8顺序栈的出栈(核心2)

注意:传入参数时,需要传入栈的指针,即&s,因为出栈操作需要 更改栈顶指针以及 带出栈顶元素

bool Pop(SqStack* s, SElemType* e)
5.8.1算法步骤:

(1)判断是否栈空(即栈顶指针 是否与 栈底指针指向相同)
(2)出栈操作:
<1>先将栈顶指针自减1,让其指向当前栈顶元素
<2>再将当前栈顶指针指向的栈顶元素 赋值给e
出栈操作可以浓缩为一步:

*e= *(–s->top);

在这里插入图片描述

//8.核心2:顺序栈的出栈
//注意:传入参数时,需要传入栈的指针,即&s,因为出栈操作需要 更改栈顶指针以及 带出栈顶元素
bool Pop(SqStack* s, SElemType* e)
{
	//[1]判断是否栈空(即栈顶指针 是否与 栈底指针指向相同)
	if (s->base == s->top)
	{
		printf("栈空!\n");
		return false;
	}

	//[2]出栈操作:
	//<1>先将栈顶指针自减1,让其指向当前栈顶元素
	--s->top;

	//<2>再将当前栈顶指针指向的栈顶元素 赋值给e
	*e = *(s->top);
	//等价于:*e=*(--s->top);先向底部移动栈顶指针,再取出栈顶元素
	return true;
}
5.9取栈顶元素

注意:传入参数时,不需要传入栈的指针,即&s,因为只取元素,不修改栈的数据

bool GetTop(SqStack s, SElemType* e)
5.9.1算法步骤:

(1)判断栈是否为空
(2)获取栈顶元素(注意是s.top - 1处的元素)

//9.取栈顶元素
//注意:传入参数时,不需要传入栈的指针,即&s,因为只取元素,不修改栈的数据
bool GetTop(SqStack s, SElemType* e)
{
	//[1]判断栈是否为空
	if (s.base == s.top)
	{
		printf("栈空!\n");
		return false;
	}

	//[2]获取栈顶元素:
	*e = *(s.top - 1);
	return true;
}
5.10输出顺序栈中的所有元素(从顺序栈顶开始输出)
bool printStack(SqStack s)
5.10.1算法步骤:

(1)判断该顺序栈是否为空
(2)定义临时指针指向当前栈顶元素(s.top - 1处的元素)
(3)p从栈顶开始,向栈底移动并依次输出栈中的元素

//10.输出顺序栈中的所有元素(从顺序栈顶开始输出)
bool printStack(SqStack s)
{
	//[1]判断该顺序栈是否为空
	if (s.base == s.top)
	{
		printf("顺序栈为空!\n");
		return false;
	}

	//[2]定义临时指针指向当前栈顶元素
	SElemType* p = s.top - 1;

	//[3]p从栈顶开始,向栈底移动并依次输出栈中的元素
	while (p>=s.base)
	{
		printf("%d-->", *(p));
		p--;
	}

	printf("end\n");
	return true;
}

21.所有操作如下:

//顺序栈的基本操作与实现(1.为了操作方便,栈顶指针指向栈顶元素的下一位置)
                     //(2.直接使用指针来定义栈顶,栈底指针)
#include<stdio.h>
#include<stdlib.h>


#define bool int
#define true 1
#define false 0

typedef int SElemType;//栈中数据元素的类型定义     


#define MAXSIZE 100//顺序栈的最大容量


//1.顺序栈的结构(这里直接使用指针来  定义栈顶指针  与  栈底指针)
//实际上也可以使用int类型的角标来模拟栈顶,栈底指针
typedef struct Sqstack
{
	SElemType* base;//栈底指针
	SElemType* top;//栈顶指针

	int stacksize;//栈可用的最大容量
}SqStack;


//2.顺序栈的初始化
//注意:传入参数时,需传入栈的指针,即&s,这样才能修改栈中的数据
bool InitStack(SqStack* s)
{
	//[1]为顺序栈初始化空间,同时让栈底指针指向被初始化的空间
	s->base = (SElemType *)malloc(sizeof(SElemType) * MAXSIZE);

	if (s->base == NULL)
	{
		printf("内存分配失败!\n");
		exit(-1);
	}

	//[2]初始化栈顶指针 指向栈底位置
	s->top = s->base;

	//[3]初始化该顺序栈的最大容量
	s->stacksize = MAXSIZE;
	return true;
}

//3.判断顺序栈是否为空
//注意:传入参数时,不需要传入栈的指针,即&s,因为判空操作只需要访问栈顶指针与栈底指针,并不做修改
bool StackEmpty(SqStack s)
{

	//[1]若栈顶指针与栈底指针相同,说明栈空
	if (s.top == s.base)
	{
		return true;
	}
	else
	{
		return false;
	}
}


//4.求顺序栈的长度
//注意:传入参数时,不需要传入栈的指针,即&s,因为求长度只需要计算栈顶指针与栈底指针之差,并不做修改
int StackLength(SqStack s)
{
	//栈顶指针 与 栈底指针的 差值即为顺序栈的长度
	return s.top - s.base;
}


//5.清空顺序栈
//注意:传入参数时,需要传入栈的指针,即&s,因为清空栈需要修改栈顶指针,即s.top
bool ClearStack(SqStack * s)
{
	//[1]判断栈内存是否分配
	if (s->base == NULL)
	{
		printf("栈不存在!\n");
		return false;
	}

	//[2]修改 栈顶指针 指向 栈底位置,即为清空
	//(由于进栈时值会覆盖,故不需要删除元素值)
	s->top = s->base;
	return true;
}

//6.销毁顺序栈
//注意:传入参数时,需要传入栈的指针,即&s,因为销毁栈需要修改清空内存,并置空栈中指针以及栈大小
bool DestroyStack(SqStack *s)
{
	//[1]若当前顺序栈不为空,则先释放内存,再置空栈大小以及栈指针
	if (s->base != NULL)
	{
		//<1>通过栈底指针释放内存
		free(s->base);
		
		//<2>置空栈大小以及栈指针
		s->stacksize = 0;

		s->base = NULL;
		s->top = NULL;
	}
	return true;
}


//7.核心1:顺序栈的入栈
//注意:传入参数时,需要传入栈的指针,即&s,因为入栈操作需要 更改栈顶指针以及 添加栈顶元素
bool Push(SqStack* s, SElemType e)
{
	//[1]判断栈是否已满(即 栈顶指针 与 栈底指针 之差 是否等于 栈的最大容量)
	if (s->top - s->base == s->stacksize)
	{
		printf("栈满!\n");
		return false;
	}

	//[2]入栈操作:
	//<1>先将元素e赋值给栈顶指针当前指向的位置
	*(s->top) = e;
	
	//<2>然后栈顶指针自增1,指向当前 栈顶元素的 下一个位置
	(s->top)++;
	//等价于 *s->top++ = e;先赋值,再向下移动

	return true;

}

//8.核心2:顺序栈的出栈
//注意:传入参数时,需要传入栈的指针,即&s,因为出栈操作需要 更改栈顶指针以及 带出栈顶元素
bool Pop(SqStack* s, SElemType* e)
{
	//[1]判断是否栈空(即栈顶指针 是否与 栈底指针指向相同)
	if (s->base == s->top)
	{
		printf("栈空!\n");
		return false;
	}

	//[2]出栈操作:
	//<1>先将栈顶指针自减1,让其指向当前栈顶元素
	--s->top;

	
	//<2>再将当前栈顶指针指向的栈顶元素 赋值给e
	*e = *(s->top);
	//等价于:*e=*(--s->top);先向底部移动栈顶指针,再取出栈顶元素
	return true;
}


//9.取栈顶元素
//注意:传入参数时,不需要传入栈的指针,即&s,因为只取元素,不修改栈的数据
bool GetTop(SqStack s, SElemType* e)
{
	//[1]判断栈是否为空
	if (s.base == s.top)
	{
		printf("栈空!\n");
		return false;
	}

	//[2]获取栈顶元素:
	*e = *(s.top - 1);
	return true;
}




//10.输出顺序栈中的所有元素(从顺序栈顶开始输出)
bool printStack(SqStack s)
{
	//[1]判断该顺序栈是否为空
	if (s.base == s.top)
	{
		printf("顺序栈为空!\n");
		return false;
	}

	//定义临时指针指向当前栈顶元素
	SElemType* p = s.top - 1;

	//p从栈顶开始,向栈底移动并依次输出栈中的元素
	while (p>=s.base)
	{
		printf("%d-->", *(p));
		p--;
	}

	printf("end\n");
	return true;
}



int main()
{
	SqStack s1;
	InitStack(&s1);  // 初始化栈

	// 入栈
	Push(&s1, 10);  
	Push(&s1, 20);
	Push(&s1, 30);
	Push(&s1, 31);
	Push(&s1, 32);

	printf("当前栈的长度: %d\n", StackLength(s1));
	printf("\n");

	// 获取栈顶元素
	SElemType ee;
	GetTop(s1, &ee);
	printf("当前栈顶元素为:%d\n", ee);

	printf("\n");
	printf("从当前栈顶元素向下输出:\n");
	printStack(s1);

	// 出栈
	printf("\n");
	SElemType e[10];
	for (int i = 0; i < 3; i++)
	{
		Pop(&s1, &e[i]);
		printf("出栈元素: %d\n", e[i]);
	}

	printf("\n");
	printf("从当前栈顶元素向下输出:\n");
	printStack(s1);

	// 清空栈
	ClearStack(&s1); 
	
	printf("栈是否为空: \n");
	if (StackEmpty(s1))
	{
		printf("栈为空!\n");
	}

	// 销毁栈
	if (DestroyStack(&s1))
	{
		printf("销毁成功!\n");
	}

	return 0;
}

在这里插入图片描述

  • 22
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值