数据结构——栈(C语言)

github代码下载

github代码:
https://github.com/Kyrie-leon/Data_Structures/tree/main/stack_queue

一、 栈的概念及结构

:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
出栈:栈的删除操作叫做出栈。出数据也在栈顶
在这里插入图片描述
在这里插入图片描述

二、栈的实现

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小,如下图所示。

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

而如果采用如下结构实现栈,尾插需要挪动数据,造成大量的计算开销。

在这里插入图片描述

2.1 栈的存储定义

静态存储的栈
使用一个静态一维数组a[N]实现,但这样做会造成太多的空间浪费或者空间不足

#define N 10
typedef int STDataType;
typedef struct Stack Stack;
struct Stack
{
	STDataType a[N];
	int _top;	//栈顶
};

支持动态增长的栈
使用一个指针_a动态开辟内存实现栈的存储

typedef int STDataType;
typedef struct Stack Stack;
//支持动态增长的栈
struct Stack
{
	STDataType * _a;
	int _top;			//栈顶
	int _capacity;		//容量
};

2.2 栈的初始化

初始化:默认为栈开辟四个STDataType大小的空间

  • capacity:栈的容量大小,默认4
  • _top: 表示栈顶,我们约定_top=0表示栈为空,之后每入栈一个元素_top加1,即_top所指向数组的下表总是比实际栈顶元素下标大1

在这里插入图片描述

在这里插入图片描述

//栈的初始化
void StackInit(Stack * ps)
{
	assert(ps);
	ps->_a = (STDataType *)malloc(sizeof(Stack) * 4);	//默认数组大小为4
	ps->_top = 0;		//栈为空,则栈顶为0
	ps->_capacity = 4;	//默认栈的容量为4
}

2.3 入栈

前面已经约定过_top所指向数组的下表总是比实际栈顶元素下标大1
入栈只需要将数据存放到_top下标的数组中,然后_top加1即可
在这里插入图片描述
在这里插入图片描述

//入栈
void StackPush(Stack * ps, STDataType data)
{
	assert(ps);
	//判断栈是否满了,满了则增容
	if (ps->_top == ps->_capacity)
	{
		ps->_capacity *= 2;	//每次扩容2倍
		STDataType * tmp = (STDataType *)realloc(ps->_a, sizeof(Stack)*ps->_capacity);
		//判断内存是否申请成功
		if (NULL == tmp)
		{
			printf("扩容失败\n");
			exit(-1);
		}
		ps->_a = tmp;
	}
	//入栈
	ps->_a[ps->_top] = data;	
	ps->_top++;
}

2.4 出栈

_top所指向数组的下表总是比实际栈顶元素下标大1
因此出栈只需将_top减1即可

在这里插入图片描述

//出栈
void StackPop(Stack * ps)
{
	assert(ps);
	assert(ps->_top>0);
	ps->_top--;
}

2.5 获取栈顶元素

_top所指向数组的下表总是比实际栈顶元素下标大1
所以栈顶元素的下标是_top-1

//获取栈顶元素
STDataType StackTop(Stack *ps)
{
	assert(ps);
	assert(ps->_top>0);

	return ps->_a[ps->_top-1];	
}

2.6 获取栈中有效元素个数

因为数组元素下标从0开始,因此_top就表示栈中有效元素个数


//获取栈中有效元素个数
int StackSize(Stack * ps)
{
	assert(ps);
	return ps->_top;
}

2.7 检测栈是否为空

通过_top的值就可以判断栈是否为空
若_top为0,表示为空,取反则返回非0
若_top为1,表示不为空,取反则返回0

//检测栈是否为空,如果为空返回非0,不为空返回0
int StackEmpty(Stack* ps)
{
	assert(ps);
	return !(ps->_top);
}

2.8 销毁栈


//销毁栈
void StackDestory(Stack * ps)
{
	assert(ps);
	free(ps->_a);
	ps->_a = NULL;
	ps->_capacity = ps->_top = 0;
}

三、栈的测试

#include "stack.h"

void TestStack()
{
	Stack ps;
	StackInit(&ps);
	StackPush(&ps, 1);
	StackPush(&ps, 2);
	StackPush(&ps, 3);
	StackPush(&ps, 4);
	StackPush(&ps, 5);
	while (!StackEmpty(&ps))
	{

		printf("%d, %d\n", StackTop(&ps),StackSize(&ps));
		StackPop(&ps);
	}

	
}

int main()
{
	TestStack();
	system("pause");
	return 0;
}

在这里插入图片描述

四、代码清单

4.1 stack.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<windows.h>

#define N 10
typedef int STDataType;
typedef struct Stack Stack;
//struct Stack
//{
//	STDataType a[N];
//	int _top;	//栈顶
//};

//支持动态增长的栈
struct Stack
{
	STDataType * _a;
	int _top;			//栈顶
	int _capacity;		//容量
};

//初始化栈
void StackInit(Stack * ps);

//入栈
void StackPush(Stack * ps, STDataType data);

//出栈
void StackPop(Stack * ps);

//获取栈顶元素
STDataType StackTop(Stack *ps);

//获取栈顶中有效元素个数
int StackSize(Stack * ps);

//检测栈是否为空,如果为空返回非0,不为空返回0
int StackEmpty(Stack* ps);

//销毁栈
void StackDestory(Stack * ps);

4.2 stack.c

#include "stack.h"

//栈的初始化
void StackInit(Stack * ps)
{
	assert(ps);
	ps->_a = (STDataType *)malloc(sizeof(Stack) * 4);	//默认数组大小为4
	ps->_top = 0;		//栈为空,则栈顶为0
	ps->_capacity = 4;	//默认栈的容量为4
}

//入栈
void StackPush(Stack * ps, STDataType data)
{
	assert(ps);
	//判断栈是否满了,满了则增容
	if (ps->_top == ps->_capacity)
	{
		ps->_capacity *= 2;	//每次扩容2倍
		STDataType * tmp = (STDataType *)realloc(ps->_a, sizeof(Stack)*ps->_capacity);
		//判断内存是否申请成功
		if (NULL == tmp)
		{
			printf("扩容失败\n");
			exit(-1);
		}
		ps->_a = tmp;
	}
	//入栈
	ps->_a[ps->_top] = data;	
	ps->_top++;
}

//出栈
void StackPop(Stack * ps)
{
	assert(ps);
	assert(ps->_top>0);
	ps->_top--;
}

//获取栈顶元素
STDataType StackTop(Stack *ps)
{
	assert(ps);
	assert(ps->_top>0);

	return ps->_a[ps->_top-1];	
}

//获取栈中有效元素个数
int StackSize(Stack * ps)
{
	assert(ps);
	return ps->_top;
}

//检测栈是否为空,如果为空返回非0,不为空返回0
int StackEmpty(Stack* ps)
{
	assert(ps);
	return !(ps->_top);
}

//销毁栈
void StackDestory(Stack * ps)
{
	assert(ps);
	free(ps->_a);
	ps->_a = NULL;
	ps->_capacity = ps->_top = 0;
}

4.3 test.c

#include "stack.h"

void TestStack()
{
	Stack ps;
	StackInit(&ps);
	StackPush(&ps, 1);
	StackPush(&ps, 2);
	StackPush(&ps, 3);
	StackPush(&ps, 4);
	StackPush(&ps, 5);
	while (!StackEmpty(&ps))
	{

		printf("%d, %d\n", StackTop(&ps),StackSize(&ps));
		StackPop(&ps);
	}

	
}

int main()
{
	TestStack();
	system("pause");
	return 0;
}
  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个C语言实验报告的模板,供您参考: # 实验名称:C语言的实现 ## 实验目的: 1. 理解的基本概念和特点。 2. 掌握的基本操作:push和pop。 3. 熟悉的应用场景。 ## 实验环境: - 操作系统:Windows 10 - 编程语言:C语言 - 开发工具:Visual Studio Code ## 实验内容: ### 1. 的定义 是一种后进先出(Last In First Out,LIFO)的数据结构,它只允许在表的一端进行插入和删除运算。根据的定义,可以使用数组来实现。 ### 2. 的基本操作 的基本操作包括push和pop。push操作将元素插入顶,pop操作将顶元素删除。 以下是的基本操作的伪代码: ``` push(S, x): if stack is full: error "stack overflow" else: top ← top + 1 stack[top] ← x pop(S): if stack is empty: error "stack underflow" else: top ← top - 1 return stack[top + 1] ``` ### 3. 的应用场景 广泛应用于编程语言的解析、函数调用、表达式求值等场景中。例如,在编程语言的解析过程中,可以使用来判断括号是否匹配。 ## 实验结果: 在实验过程中,我们成功实现了一个基于数组的,并完成了push和pop操作。通过实验,我们深入理解了的基本概念和特点,并掌握了的基本操作。同时,我们也熟悉了的应用场景,为以后的编程工作打下了基础。 ## 总结: 本次实验让我们掌握了的基本操作和应用场景,这对我们以后的编程工作非常有帮助。通过实验,我们也发现了的局限性,例如的存储空间有限,只能在顶进行插入和删除操作等。因此,在实际应用中,我们还需要结合具体场景选择合适的数据结构

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值