首页 > 其他分享 >数据结构 ——— C语言实现数组栈

数据结构 ——— C语言实现数组栈

时间:2024-10-25 14:18:23浏览次数:8  
标签:C语言 top 栈顶 ST 数组 STDataType 数据结构 void pst

目录

栈的概念以及示意图

链式栈和数组栈

链式栈:

数组栈:

数组栈的结构

实现数组栈的准备工作

实现数组栈

初始化数组栈

入栈(尾插)

出栈(尾删)

访问栈顶数据

判断栈是否为空

栈数据的总数

访问栈的所有数据

释放栈

Stack.h 的所有代码

Stack.c 的所有代码


栈的概念以及示意图

栈是一种特殊的线性表,只允许在固定的一端进行插入和删除元素的操作
进行数据插入和删除操作的一端称为栈顶,另一端称为栈底,栈中的数据元素遵守先进后出的原则

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
出栈:栈的删除操作叫做出栈,出数据也在栈顶

栈结构示意图:


链式栈和数组栈

链式栈:

使用单链表实现栈的话就要用头节点做栈顶,这样出栈和压栈的效率才能达到O(1)
否则用尾节点当作栈顶的话,那么出栈和压栈时还要先找到尾节点,效率就低到了O(N)
且使用双向带头循环链表的话就会多使用一个指针,且和栈的使用逻辑不匹配 

数组栈:

数组也就是顺序表,顺序表这种结构更加符合栈的出栈、压栈等操作,因为将顺序表尾部当作栈顶,那么出栈和压栈操作也就是尾删和尾插,效率为O(1)
唯一的缺陷就是当空间不够时,需要扩容,每次以原容量的 2 倍进行扩容,那么到后面会越扩越慢,申请扩容的效率也并不是很低
而且顺序表的CPU高速缓存效率比链式栈更高,所以选择实现数组栈


数组栈的结构

// 数据类型
typedef int STDataType;

typedef struct Stack
{
	STDataType* a; //指向栈底的指针

	int top; //栈顶元素的下标

	int capaicty; //容量
}ST;

注意:top 是指向栈顶元素的位置,而不是栈顶元素的下一个位置 


实现数组栈的准备工作

创建3个文件

test.c 文件:用来测试增删查改功能是否完善

Stack.h 文件:用来声明动态顺序表的结构以及声明增删查改函数 

Stack.c 文件:用来实现动态顺序表的增删查改及功能函数


实现数组栈

初始化数组栈

void STInit(ST* pst)
{
	assert(pst);

	pst->a = NULL;
	pst->top = -1;
	pst->capaicty = 0;
}

top 初始化为 -1 的原因是:top 指向的是栈顶元素,那么对于数组来说,top 也就是数组最后一个元素的下标
当没有数据时,top 为 -1,当栈中有一个数据时,先将 top 自增 1,再放入数据,那么 a[top] 就是栈顶元素,top 也就是栈顶元素的下标,所以要初始化为 -1 
且如果这样设计的话,那么后续的函数都要根据 top 的初始化为标准,大家也可以设计成 top 指向栈顶元素的下一个位置,这两种设计都可以


入栈(尾插)

void STPush(ST* pst, STDataType x)
{
	// 数据入栈前判断是否需要扩容
	if (pst->capaicty == (pst->top + 1))
	{
		// 扩容
		int newCapaicty = pst->capaicty == 0 ? 4 : pst->capaicty * 2;
		ST* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newCapaicty);

		// 判断是否扩容成功
		if (tmp == NULL)
		{
			perror("realloc fail");
		}

		pst->a = tmp;
		pst->capaicty = newCapaicty;
	}

	// 存放数据
	pst->a[++pst->top] = x;
}

栈这个结构只有入栈时才会存放数据,所以不需要将扩容的逻辑额外封装成函数
且因为 top 是指向栈顶元素,所以判断是否需要扩容时要加 1
最后存放数据时要先将 top 自增 1,再存放数据

测试代码:


出栈(尾删)

void STPop(ST* pst)
{
	// 当栈内无数据时
	if (pst->top == -1)
	{
		printf("无数据可出栈\n");
		return;
	}

	pst->top--;
}

测试代码:


访问栈顶数据

STDataType STTop(ST* pst)
{
	assert(pst);

	// 当栈内无数据时
	if (pst->top == -1)
	{
		printf("无数据可访问\n");
		return;
	}

	return pst->a[pst->top];
}

测试代码:


判断栈是否为空

bool STEmpty(ST* pst)
{
	assert(pst);

	return pst->top == -1;
}

栈数据的总数

int STSize(ST* pst)
{
	assert(pst);

	return (pst->top + 1);
}

访问栈的所有数据

printf("栈顶<-");
while (!STEmpty(&st))
{
	// 访问当前栈顶元素
	printf("%d<-", STTop(&st));

	// 移除当前栈顶元素
	STPop(&st);
}
printf("栈底\n");

测试代码: 


释放栈

void STDestroy(ST* pst)
{
	assert(pst);

	free(pst->a);
	
	pst->a = NULL;
	pst->capaicty = 0;
	pst->top = -1;
}

Stack.h 的所有代码

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

// 数据类型
typedef int STDataType;

typedef struct Stack
{
	STDataType* a; //指向栈底的指针

	int top; //栈顶元素的下标

	int capaicty; //容量
}ST;

// 初始化
void STInit(ST* pst);

// 打印
void STPrint(ST* pst);

// 入栈(尾插)
void STPush(ST* pst, STDataType x);

// 出栈(尾删)
void STPop(ST* pst);

// 访问栈顶元素
STDataType STTop(ST* pst);

// 判断栈是否为空
bool STEmpty(ST* pst);

// 栈数据的总数
int STSize(ST* pst);

// 释放栈
void STDestroy(ST* pst);


Stack.c 的所有代码

#define _CRT_SECURE_NO_WARNINGS 1

#include"Stack.h"

// 初始化
void STInit(ST* pst)
{
	assert(pst);

	pst->a = NULL;
	pst->top = -1;
	pst->capaicty = 0;
}

// 打印
void STPrint(ST* pst)
{
	assert(pst);

	printf("栈底->");

	for (int i = 0; i <= pst->top; i++)
	{
		printf("%d->", pst->a[i]);
	}

	printf("栈顶\n\n");
}

// 入栈(尾插)
void STPush(ST* pst, STDataType x)
{
	// 数据入栈前判断是否需要扩容
	if (pst->capaicty == (pst->top + 1))
	{
		// 扩容
		int newCapaicty = pst->capaicty == 0 ? 4 : pst->capaicty * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, sizeof(STDataType) * newCapaicty);

		// 判断是否扩容成功
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}

		pst->a = tmp;
		pst->capaicty = newCapaicty;
	}

	// 存放数据
	pst->a[++pst->top] = x;
}

// 出栈(尾删)
void STPop(ST* pst)
{
	// 当栈内无数据时
	if (pst->top == -1)
	{
		printf("无数据可出栈\n");
		return;
	}

	pst->top--;
}

// 访问栈顶元素
STDataType STTop(ST* pst)
{
	assert(pst);

	// 当栈内无数据时
	if (pst->top == -1)
	{
		printf("无数据可访问\n");
		return -1;
	}

	return pst->a[pst->top];
}

// 判断栈是否为空
bool STEmpty(ST* pst)
{
	assert(pst);

	return pst->top == -1;
}

// 栈数据的总数
int STSize(ST* pst)
{
	assert(pst);

	return (pst->top + 1);
}

// 释放栈
void STDestroy(ST* pst)
{
	assert(pst);

	free(pst->a);
	
	pst->a = NULL;
	pst->capaicty = 0;
	pst->top = -1;
}

标签:C语言,top,栈顶,ST,数组,STDataType,数据结构,void,pst
From: https://blog.csdn.net/weixin_55341642/article/details/143101559

相关文章

  • 数据结构有哪些
    数据结构分类涉及多方面,主要包括:1、线性结构、2、树形结构、3、图形结构、4、集合结构、5、文件结构。在这些种类中,线性结构是最基本、也是最为广泛使用的一种,它包括数组、链表、栈和队列等数据结构,通过线性的方式组织数据元素。以数组为例,它以连续的内存空间顺序存储数据,通过索引......
  • 基础数据结构(1)
    单链表与双链表的用处单链表单链表的存储:单链表的几种操作在表头插入一个数:先将这个数指向head指向的数,再将head指向这个数在表中的第k位后面插入一个数:先将这个数指向第k位指向的数,再将第k位指向这个数在表中删除一个数:让这个数直接指向下一个数的下一个数代码实现:/......
  • C语言中的作用域规则
    文章的开头段落:在C语言中,作用域规则是一个非常重要的部分,主要涉及变量和函数的可见性和生命周期。根据作用域的界限,可将C语言的作用域分为四种:文件作用域、函数作用域、块作用域和函数原型作用域。它们分别规定了变量或函数在程序中的可见区域和生存期长度。每种作用域各有其特......
  • 数据结构 - 树,三探之代码实现
    数据结构-树,三探之代码实现 本文介绍了使用数组和链表两种方式实现二叉树,包括初始化、节点操作(如获取、添加、删除)、以及遍历方法(前序、中序、后序、层次遍历)。测试代码已上传至代码库。 书接上回,今天和大家一起动手来自己实现树。相信通过前面的章节学习,大家已经明白树......
  • 编程语言有哪些分类?C语言和其他编程语言的区别?到底什么是高级语言,什么是低级语言?C
    编程语言有哪些分类?编程语言发展有打孔卡片、机器语言、汇编语言和高级语言这几种形态。高级语言对于程序员更友好,发展的形态五花八门。从编程方式看,有命令式、函数式和逻辑式三种。命令式以常见的C/C++/Java/C#/Py......
  • 无限可能|为什么C语言如此强大?探索应用领域+职业方向
    随着科技的不断进步和发展,计算机科学领域的就业前景也越来越广阔。而在这个快速发展的行业中,学习C语言将打开更多的职业大门。C语言作为一种强大的编程语言,在各个领域都有着广泛的应用,为互联网从业者提供了丰富多彩的职业选择。一、 ‌C语言的主要应用领域C语言具有良好的......
  • 数据结构 - 堆
    今天我们将学习新的数据结构-堆。01、定义堆是一种特殊的二叉树,并且满足以下两个特性:(1)堆是一棵完全二叉树;(2)堆中任意一个节点元素值都小于等于(或大于等于)左右子树中所有节点元素值;小根堆,根节点元素永远是最小值,即堆中每个节点元素值都小于等于左右子树中所有节点元素值;大根......
  • 如何在C语言中使用多线程
    首段:在C语言中使用多线程可以通过调用标准线程库(POSIXthreads,也叫做Pthreads)的相关API函数实现。Pthreads库中包括了创建线程、线程同步(锁与条件变量)、线程间通信、线程清理等多种功能的API,这些功能为开发者提供了并行处理能力,从而可以大大优化程序的性能。要在C语言中使用多......
  • C语言基础入门(小白)三种方法解决幽灵换行符问题
    首先,相信很多读者读到题目都会产生一个共同的疑问:什么是幽灵换行符???    幽灵换行符是指:在C语言中,当用scanf函数时,想要输入几个字符,比如:当输入‘a’之后按下回车键,运行自动结束,而不是等待输入第二个字符,第二个字符就像幽灵般消失了,这是为什么呢??    其实,原因......
  • 刷c语言练习题12(牛客网)
    1、在上下文和头文件正常的情况下,以下代码输出的值是:12345678910111213int x = 4;void incre() {    static int x = 1;    x *= x + 1;    printf("%d", x);}int _tmain(int argc, _TCHAR *argv[]) {    int i;......