数据结构与算法&堆栈工具

一、堆栈是什么?

1.定义:堆栈是一种数据结构。堆栈都是一种数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除。

在这里插入图片描述

2.特征

1)先进后出,后进先出。
2)单入口、单出口、出入同口。
像一个子弹匣,第一颗子弹放进去,一定是锃亮锃亮的。因为最后一发射出的子弹可能是留给自己的。

3.堆栈其他的基本属性

堆栈的控制头:
1)数据空间(真正的堆栈空间)
2)容量 (capacity)
3)栈底指针(bottom)(可以不要)
4)栈顶指针(top)

堆栈的基本操作:
1)入栈
2)出栈

堆栈的表示:
1)线性存储结构----数组
2)非线性存储结构----链表

二、堆栈工具

既然堆栈是·一种数据存储结构,那么,要有工具性,起码这个存储的数据类型可以自定义的、多类型的。
在上一篇线性表工具里,采用了用户自定义USER_TYPE这种方式。还有其他方法吗?

1.堆栈数据存储空间实现

思考: 由于数据类型是用户自定义的,所以直接申请这类数据空间是不行的。那么如果将“数据的存储空间的首地址”存储起来可不可以?
这种想法有这些优点
1)不论数据类型多复杂,多长,仅保存其首地址,使得数组中每个元素长度固定为4b;
2)不论用户数据类型是什么,其首地址的都可以看成void* !
3)在允许void * 的值(数组元素的值, 即数据首地址的值)相同的情况下,可以不用再申请void*元素,节省一定内存空间。

所以:使用的数据类型是 void **data;

//解释
	typedef struct STU {
		int score;
		...
	}STU;
	void **data = NULL;
	data = (void **)calloc(sizeof(void *), n);
	int num = 30;
	char str[8] = "12345678";
	STU stu1 = {...};
	data[0] = #
	data[1] = str;  (&str[0] <=> &*(str + 0) <=> str)
	data[2] = stu1;
//下面是图片
	

在这里插入图片描述
所以,控制头就产生了:

typedef struct STACK {
	void **stackData;
	int capacity;
	int top;
}STACK;

编程好习惯:boolean值。

typedef unsigned char boolean;
#define		TRUE		1
#define		FALSE		0

初始化堆栈空间如下:

boolean initStack(STACK **stack, int capacity) {
	if (NULL == stack || NULL != *stack 
		|| capacity <= 0 || capacity > MAX_STACK_CAPACITY) {
		//分析: STACK stack 是一个结构体,也可以看成第一个空链
		//STACK *stack 是结构体指针,4b空间。即结构体首地址值。
		//STACK **stack 是指向结构体指针的指针,4b空间,即结构体指针的地址值
		//NULL == stack, 结构体指针不存在,
		//NULL != *stack  结构体指针指向的空间存在,说明已经申请了结构体,无需再初始化
		return FALSE; //初始化失败
	}
	(*stack) = (STACK *)calloc(sizeof(STACK), 1);//申请一个堆栈控制空间
	if (NULL == *stack) {
		return FALSE; //防止申请失败
	}
	(*stack)->stackData = (void **)calloc(sizeof(void *), capacity);//申请堆栈数据存储空间
	if (NULL == (*stack)->stackData) { //申请失败
		free(*stack); //销毁堆栈控制空间
		*stack = NULL;// 堆栈控制空间指针变为0,销毁
		return FALSE;
	}
	(*stack)->capacity = capacity;
	(*stack)->top = 0;

	return TRUE; //申请成功
}	

有初始化,就必须有销毁:注意:顺序

//销毁堆栈空间
void destoryStack(STACK **stack) {
	if (NULL == stack || NULL == *stack) {
		return; //销毁过了
	}
	free((*stack)->stackData);//必须先销毁堆栈数据存储空间
	free(*stack);//销毁堆栈控制空间
	*stack = NULL;// 堆栈控制空间指针变为0,销毁
}

如果先销毁堆栈控制空间,那么数据存储空间的首地址就不存在了,无法销毁了。

2.堆栈工具基本功能实现

1)栈的使用情况

//栈空?
boolean isStackEmpty(const STACK *stack) {
	return NULL == stack || stack->top <= 0;//栈顶指针只在最底下。栈空
}
//栈满?
boolean isStackFull(const STACK *stack) {
	return NULL == stack || stack->top >= stack->capacity;//超出容量
}

2)栈的基本操作
**这里需要注意:**你的栈顶指针只在哪个位置
这是我的栈顶指针位置:
在这里插入图片描述

//入栈
boolean push(STACK *stack, void *data) {
	if (NULL == stack || isStackFull(stack)) {
		return FALSE;
	}
	stack->stackData[stack->top++] = data;
		//滞后自增,将数据存储在栈顶指针所致空间,然后栈顶指针向上冒一个
	return TRUE;
}
//出栈
void *pop(STACK * stack) {
	if (NULL == stack || isStackEmpty(stack)) {
		return NULL;
	}
	return stack->stackData[--stack->top];
	//滞前自增,先栈顶指针向下走一个,再将栈顶元素弹出来
}
//读取栈顶元素
void *readTop(const STACK *stack) {
	if (NULL == stack || isStackEmpty(stack)) {
		return NULL;
	}
	return stack->stackData[stack->top - 1];
}

这样一来,一个堆栈工具已经基本实现。
堆栈工具可以使用的地方,比如说:表达式的运用。

在这里插入图片描述编译通过,最后一个错误的意思是缺少主函数。毕竟这是一个工具,使用者这需要obj文件就行了。

三、总结

1.这里最大的收获就是那个void **数据类型。我只要你数据的首地址,不管你的数据类型。很好很强大的解决了用户自定义数据类型。

2.结构决定其功能。

感谢指导老师:铁血教主
笔者水平有限,目前只能描述以上问题,如果有其他情况,可以留言,有错误,请指教,有继续优化的,请分享,谢谢!
完整代码如下:
stack.h代码:

#ifndef _STICK_STACK_H
#define _STICK_STACK_H

typedef unsigned char boolean;
#define		TRUE		1
#define		FALSE		0

#define MAX_STACK_CAPACITY 1000000 //堆栈空间最大容量

typedef struct STACK {
	void **stackData;
	int capacity;
	int top;
}STACK;

boolean initStack(STACK **stack, int capacity);
void destoryStack(STACK **stack);
boolean isStackEmpty(const STACK *stack);
boolean isStackFull(const STACK *stack);
boolean push(STACK *stack, void *data);
void *pop(STACK *stack);
void *readTop(const STACK *stack);

#endif

stack.c代码:

#include <stdio.h>
#include <malloc.h>

#include "stack.h"

boolean initStack(STACK **stack, int capacity) {
	if (NULL == stack || NULL != *stack 
		|| capacity <= 0 || capacity > MAX_STACK_CAPACITY) {
		//分析: STACK stack 是一个结构体,也可以看成第一个空链
		//STACK *stack 是结构体指针,4b空间。即结构体首地址值。
		//STACK **stack 是指向结构体指针的指针,4b空间,即结构体指针的地址值
		//NULL == stack, 结构体指针不存在,
		//NULL != *stack  结构体指针指向的空间存在,说明已经申请了结构体,无需再初始化
		return FALSE; //初始化失败
	}
	(*stack) = (STACK *)calloc(sizeof(STACK), 1);//申请一个堆栈控制空间
	if (NULL == *stack) {
		return FALSE; //防止申请失败
	}
	(*stack)->stackData = (void **)calloc(sizeof(void *), capacity);//申请堆栈数据存储空间
	if (NULL == (*stack)->stackData) { //申请失败
		free(*stack); //销毁堆栈控制空间
		*stack = NULL;// 堆栈控制空间指针变为0,销毁
		return FALSE;
	}
	(*stack)->capacity = capacity;
	(*stack)->top = 0;

	return TRUE; //申请成功
}
//销毁堆栈空间
void destoryStack(STACK **stack) { 
	if (NULL == stack || NULL == *stack) {
		return; //销毁过了
	}
	free((*stack)->stackData);//必须先销毁堆栈数据存储空间
	free(*stack);//销毁堆栈控制空间
	*stack = NULL;// 堆栈控制空间指针变为0,销毁
}	
//栈空?
boolean isStackEmpty(const STACK *stack) {
	return NULL == stack || stack->top <= 0;//栈顶指针只在最底下。栈空
}
//栈满?
boolean isStackFull(const STACK *stack) {
	return NULL == stack || stack->top >= stack->capacity;//超出容量
}
//入栈
boolean push(STACK *stack, void *data) {
	if (NULL == stack || isStackFull(stack)) {
		return FALSE;
	}
	stack->stackData[stack->top++] = data;
		//滞后自增,将数据存储在栈顶指针所致空间,然后栈顶指针向上冒一个
	return TRUE;
}
//出栈
void *pop(STACK *stack) {
	if (NULL == stack || isStackEmpty(stack)) {
		return NULL;
	}
	return stack->stackData[--stack->top];
	//滞前自增,先栈顶指针向下走一个,再将栈顶元素弹出来
}
//读取栈顶元素
void *readTop(const STACK *stack) {
	if (NULL == stack || isStackEmpty(stack)) {
		return NULL;
	}
	return stack->stackData[stack->top - 1];
}

2020年02.19 家

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值