C语言实现数据结构——栈(Stack)

栈的定义及原理

概述

  • 栈是一个先进后出的数据结构,类似于一个弹匣,栈中的数据就相当于弹匣中的子弹
  • 在栈中进行操作的时候 只预留了一个端口进行数据的存取操作,即无论是向数据结构中添加新的数据还是将其中的已有数据删除,只能从栈的一段进行操作

图解

  1. 数据入栈示意图
    在这里插入图片描述
    先将数据压入目前栈顶,也就是TOP指针指向的位置,然后再将指针向上移动,这样就完成了一个数据入栈的操作
    在这里插入图片描述

由上图可以看出栈进行数据存储时的特点为:数据从栈顶进入,且一次只能进入一个数据,同理可知们进行数据出栈操作的时候,元素也只能从栈顶离开,即离开栈的每个元素在离开前必须是栈顶部的元素
所以出栈原理也就如下图所示

  1. 数据出栈示意图
    在这里插入图片描述
    先将TOP指针向下移动
    在这里插入图片描述
    然后将当前TOP指向的元素出栈就行
    在这里插入图片描述

优缺点

  1. 优点:存取速度比堆要快,仅次于直接位于cpu中的寄存器,另外,栈数据是可以共享的

  2. 缺点:存在栈中的数据大小和生存期必须是确定的,缺乏灵活性

栈的主要操作

栈的数据操作同其他数据结构相同,都支持数据的增、删、遍历等操作

  1. 栈的初始化
InitStack(SqStack* S);
  1. 栈的销毁(包括释放内存)
DestoryStack(SqStack* S);
  1. 栈的数据清空(不释放内存)
ClearStack(SqStack* S);
  1. 判断栈是否为空
StackEmpty(SqStack* S);
  1. 返回栈中有效元素的数量
StackLength(SqStack* S);
  1. 返回栈顶元素
Gettop(SqStack* S,SElement *e);
  1. 压栈
Push(SqStack* S, SElement* e);
  1. 出栈
Pop(SqStack* S, SElement* e);
  1. 栈的遍历
StackTraverse(SqStack* S, void(Visit)(SElement));

实现代码

声明:为了保证代码的可读性和可移植性,编写了一个用于宏定义的Status.h的头文件,进行代码中所有需要用到的变量,望理解

1. Status.h文件代码

/*
 * 注:
 * 本次修订的目的包括降低耦合,争取每个模块都可以单独运行
 * 但是Status这个模块会被所有其他模块引用,引用次数很多。
 * 如果直接将Status模块复制到其它模块中,则会导致太多重复代码,
 * 因此这里生成一个公共静态库让其它模块共享比较划算
 */

#ifndef STATUS_H
#define STATUS_H

#include <stdio.h>

 /* 状态码 */
#define TRUE        1   // 真/是
#define FALSE       0   // 假/否
#define OK          1   // 通过/成功
#define ERROR       0   // 错误/失败

//系统中已有此状态码定义,要防止冲突
#ifndef OVERFLOW
#define OVERFLOW    -2  //堆栈上溢
#endif

//系统中已有此状态码定义,要防止冲突
#ifndef NULL
#define NULL ((void*)0)
#endif

/* 状态码类型 */
typedef int Status;

/* 布尔类型 */
typedef int Boolean;


// 读取数据
int ReadData(FILE* fp, char* format, ...);

// 摁下回车键以继续运行
void PressEnterToContinue();

// 函数暂停一段时间,time不代表具体的时间
void Wait(long time);

// 跳过输入端的行分割符,如'\r'、'\n'、'\r\n'
void skipLineSeparator(FILE* fp);

#endif

2. SqStack.h文件代码

#ifndef SQSTACK_H
#define SQSTACK_H

#include<stdio.h>
#include<stdlib.h>
#include"Status.h"

#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10

typedef int SElement;

typedef struct		//使用结构体来声明一个栈的数据结构
{
	SElement* base;
	SElement* top;
	int stacksize;
}SqStack;

//初始化一个栈
Status InitStack(SqStack* S);

//销毁结构,释放顺序栈的空间内存
Status DestoryStack(SqStack* S);

//将栈中的数据置空,不释放内存空间
Status ClearStack(SqStack* S);

//判断栈是否为空
Status StackEmpty(SqStack* S);

//返回栈中有效元素的数量
int StackLength(SqStack* S);

//返回栈顶的元素,用e进行接收
Status Gettop(SqStack* S,SElement *e);

//压栈
Status Push(SqStack* S, SElement* e);

//出栈
Status Pop(SqStack* S, SElement* e);

//遍历
Status StackTraverse(SqStack* S, void(Visit)(SElement));

#endif

3. SqStack.c函数实现文件代码

#include "SqStack.h"

Status InitStack(SqStack* S)
{
	
	if (S == NULL)		//无论哪个函数,都要判断栈为空的情况,并返回ERROR
	{
		return ERROR;
	}
	S->base = (SElement*)malloc(STACK_INIT_SIZE * sizeof(SElement));	//初始化的malloc和后面重新分配的realloc都是给base 分配空间
	if (S->base == NULL)												//分配后都要判断是否分配成功
	{
		exit(OVERFLOW);
	}
	S->top = S->base;		//初始化的时候,top和base是指向一起的,再falsh动画中很明显
	S->stacksize = STACK_INIT_SIZE;	//将目前栈的可用空间设定为最大空间

	return OK;
}

Status DestoryStack(SqStack* S)		
{
	if (S == NULL)
	{
		return ERROR;
	}
	free(S->base);		//释放base的空间
	S->base = NULL;		
	S->top = NULL;		//base 与top全部指空
	S->stacksize = 0;	//可用空间置零
}

Status ClearStack(SqStack* S)
{
	if (S = NULL || S->base == NULL)	//栈为空或者是base为空都要返回ERROR
	{
		return ERROR;
	}
	S->top = S->base;
	return OK;
}

Status StackEmpty(SqStack* S)			
{
	if (S->top == S->base)
	{
		return TRUE;
	}
	else return FALSE;
}

int StackLength(SqStack* S)		//长度直接返回top与base的差
{
	if (S->base == NULL)
	{
		return 0;
	}
	return (int)(S->top - S->base);
}

Status Gettop(SqStack* S, SElement* e)
{
	if (S->base == NULL || S->top == S->base)
	{
		return 0;
	}
	*e = *(S->top - 1);		//top指针的指向是为空的,他的-1后指向的位置才有数据
							//元素e传递的是指针类型,所以要使用*e才能传递它的值
	return OK;
}

Status Push(SqStack* S, SElement e)
{
	if (S == NULL || *(S->base) == NULL)
	{
		return ERROR;
	}

	//如果栈已经满了,就将存储空间扩容
	if (S->top - S->base >= S->stacksize){
		S->base = (SElement*)realloc(S->base, (S->stacksize + STACKINCREMENT) * sizeof(SElement));
		if (S->base == NULL)
		{
			exit(OVERFLOW);
		}
		S->top = S->base + S->stacksize;
		S->stacksize = S->stacksize + STACKINCREMENT;

	}
	
	*(S->top++) = e;	//进栈先赋值,栈顶指针再自增,先将top指向为空间的值设为传入的值,再移动top指针
	return OK;
}

Status Pop(SqStack* S, SElement* e)
{
	if (S == NULL || S->base == NULL)
	{
		return ERROR;
	}
	if (S->top == S->base)
	{
		return ERROR;
	}

	*e = *(--(*S).top);	//与push不同,先移动指针再操作指针指向的值,因为由上面可知,top是指空的
	return OK;
}

Status StackTraverse(SqStack *S, void(Visit)(SElement))
{
	SElement* p = S->base;
	
	if (S->base == NULL)
	{
		return ERROR;
	}
	while (p < S->top)	//同样由上面可知,top指空的,所以一直遍历到top下面的元素
	{
		Visit(*p);
		p = p + 1;
	}
	printf("\n");
	return OK;
}

4. SqStack_main功能测试主函数代码

#include<stdio.h>
#include "SqStack.h"
#include "Status.h"
typedef int SElemType;
void PrintElem(SElement e);
void PrintElem(SElement e)
{
	printf("%d", e);
}


//进行功能测试
int main()
{
	SqStack s;
	int i = 0;
	SElement e;

	printf("函数InitStack \n");
	{
		printf("初始化顺序栈 s . . .\n");
		InitStack(&s);
	}
	

	printf("函数StackEmpty \n");
	{
		StackEmpty(&s) ? printf("s为空") : printf("s不为空");

	}
	

	printf("函数push \n");
	{
		for (int i = 1; i <= 6; i++)
		{
			Push(&s, 2 * i);
			printf("将 \"%2d\" 压入栈s . . . \n", 2 * i);
		}
	}

	printf("打印栈元素");
	StackTraverse(&s,PrintElem);

	return 0;
}

该主题文章将持续更新,后面会陆续发布《数据结构C语言(严蔚敏版)》中的所有数据结构的代码实现,以及部分算法习题的详解,求个关注

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值