动态顺序表实现栈

前言

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

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。 出栈:栈的删除操作叫出栈,出数据也是在栈顶(也就是只有一个口,即作入口又作出口)

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的 代价比较小。虽然单链表的头作栈顶,入栈出栈的效率也和数组一样高,但毕竟链表要多存一个指针,空间浪费较大,再者数组的的缓存命中率更高

因为顺序表的尾插尾删不用挪动前面的数据,而头插头删,需要挪动后面的大量数据,所以顺序表更适合尾插尾删,所以用数组实现栈时,一般用顺序表的尾作为栈顶,此时栈的数据的插入和删除,就是用顺序表的尾插尾删

因为单链表的尾插尾删需要取找尾,时间复杂度是O(n),所以单链表更适合头插头删,所以用单链表实现栈,一般用头节点作为栈顶,这样栈的数据的删除和插入就是单链表的头删头插,如果是双向循环链表则无所谓

stack.h文件

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>//在c语言中不支持直接使用bool类型,必须先引此头文件

//以下静态数组栈一般不实用,一般都用动态数组栈
//typedef int STDataType;
//#define N 10
//typedef struct Stack
//{
//	STDataType _a[N];
//	int _top; // 栈顶
//}Stack;


typedef int STDataType;
//创建动态数组栈结构体模板
typedef struct Stack
{
	STDataType* a;
	int top;//栈顶,类似栈内有效元素个数的统计
	int capacity;//栈的容量
}ST;

//动态数组栈的初始化
void StackInit(ST* ps);

//动态数组栈的销毁,释放动态申请的空间
void StackDestroy(ST* ps);

//往栈顶放数据:入栈
void StackPush(ST* ps, STDataType x);

//删除栈顶元素:一般和StackTop函数配合使用,称为出栈
void StackPop(ST* ps);//一般在循环语句中起迭代作用

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

//获取栈内有效元素个数
int StackSize(ST* ps);

//判断栈是否为空
bool StackEmpty(ST* ps);

stack.c文件

#define _CRT_SECURE_NO_WARNINGS 1
#include "Stack.h"

void StackInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->top = 0; // 类似栈内有效元素个数的统计
	ps->capacity = 0;
}

void StackDestroy(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}

void StackPush(ST* ps, STDataType x)
{
	assert(ps);
	//判断是否需要扩容
	if (ps->top == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//如果容量为0,则增容为4,如果不是,则直接增容为原容量的2倍
		STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity);
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);//如果扩容失败就终止程序
		}

		ps->a = tmp;
		ps->capacity = newCapacity;
	}

	ps->a[ps->top] = x;
	ps->top++;
}

void StackPop(ST* ps)//也就在循环结构中起迭代的作用
{
	assert(ps);
	assert(!StackEmpty(ps));//栈不为空才能删除数据

	ps->top--;//和顺序表一样,实际上并未删除数据,只是后面我们通过top当作数组下标来访问栈内数据,给人造成数据被删除了的假象,
			  //只有后面调用StackDestroy才是真的清空数据了
}

STDataType StackTop(ST* ps)//取栈顶数据
{
	assert(ps);
	assert(!StackEmpty(ps));//数组栈不为空才能访问栈顶元素

	return ps->a[ps->top - 1];//注意数组下标是从0开始的。所以这里下标是有效元素个数top-1
}

int StackSize(ST* ps)
{
	assert(ps);

	return ps->top;//有效元素个数
}

bool StackEmpty(ST* ps)
{
	assert(ps);

	/*if (ps->top == 0)
	{
		return true;
	}
	else
	{
		return false;
	}*/
	return ps->top == 0;
}

test.c文件

#define _CRT_SECURE_NO_WARNINGS 1
#include "Stack.h"

void TestStack1()
{
	ST st;
	StackInit(&st);

	StackPush(&st, 1);
	StackPush(&st, 2);
	StackPush(&st, 3);
	StackPush(&st, 4);

	StackPop(&st);
	StackPop(&st);
	StackPop(&st);
	StackPop(&st);
	//StackPop(&st);
	//printf("%d", StackTop(&st));

	StackDestroy(&st);
}

void TestStack2()
{
	ST st;
	StackInit(&st);

	StackPush(&st, 1);
	StackPush(&st, 2);
	StackPush(&st, 3);
	StackPush(&st, 4);

	printf("%d ", StackTop(&st));
	StackPop(&st);
	printf("%d ", StackTop(&st));
	StackPop(&st);

	StackPush(&st, 5);
	StackPush(&st, 6);

//遍历数组栈内元素,必须遵循栈的特性:后进先出。也就是每次都访问栈顶数据
//就是StackPop函数一般和StackTop函数一起使用,称为出栈
	while (!StackEmpty(&st))//栈不为空才能访问
	{
		printf("%d ", StackTop(&st));//打印栈顶元素
		//删除栈顶元素(并未实际删除,只是top--了)才能让下一个元素成为新的栈顶,才能访问到下一个元素
		StackPop(&st);//实际上就是迭代的作用
	}

	StackDestroy(&st);
}

int main()
{
	TestStack2();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值