C基础 stack 设计
前言 - stack 设计思路
先说说设计 stack 结构的原由. 以前我们再释放查找树的时候多数用递归的后续遍历去释放.
其内部隐含了运行时的函数栈, 有些语言中存在爆栈风险. 所以想运用显示栈来替代隐式函数栈.
这就是我们设计 stack 的背景. 而我们这里的 stack 设计思路也比较直白, 运用可变数组进行尾
部压入和尾部弹出操作. 具体可见下图. 从左到右式弹出过程,

从右到左就是压入过程.
正文 - stack 详细设计
话不多说, 先看实现 code
stack.h - https://github.com/wangzhione/structc/blob/master/structc/struct/stack.h
#ifndef _STACK_H
#define _STACK_H #include "struct.h" #define INT_STACK (1 << 8) //
// struct stack 对象栈
// stack empty <=> tail = -1
// stack full <=> tail == cap
//
struct stack {
int tail; // 尾结点
int cap; // 栈容量
void ** data; // 栈实体
}; //
// stack_init - 初始化 stack 对象栈
// stack_free - 清除掉 stack 对象栈
// return : void
//
inline void stack_init(struct stack * s) {
assert(s && INT_STACK > );
s->tail = -;
s->cap = INT_STACK;
s->data = malloc(sizeof(void *) * INT_STACK);
} inline void stack_free(struct stack * s) {
free(s->data);
} //
// stack_delete - 删除 stack 对象栈
// s : stack 对象栈
// fdie : node_f push 结点删除行为
// return : void
//
inline void stack_delete(struct stack * s, node_f fdie) {
if (s) {
if (fdie) {
while (s->tail >= )
fdie(s->data[s->tail--]);
}
stack_free(s);
}
} //
// stack_empty - 判断 stack 对象栈是否 empty
// s : stack 对象栈
// return : true 表示 empty
//
inline bool stack_empty(struct stack * s) {
return s->tail < ;
} //
// stack_top - 获取 stack 栈顶对象
// s : stack 对象栈
// return : 栈顶对象
//
inline void * stack_top(struct stack * s) {
return s->tail >= ? s->data[s->tail] : NULL;
} //
// stack_pop - 弹出栈顶元素
// s : stack 对象栈
// return : void
//
inline stack_pop(struct stack * s) {
if (s->tail >= ) --s->tail;
} //
// stack_push - 压入元素到对象栈栈顶
// s : stack 对象栈
// m : 待压入的对象
// return : void
//
inline void stack_push(struct stack * s, void * m) {
if (s->cap <= s->tail) {
s->cap <<= ;
s->data = realloc(s->data, sizeof(void *) * s->cap);
}
s->data[++s->tail] = m;
} #endif//_STACK_H
INT_STACK 是拍脑门搞得 8 x 8, 唯一的损耗点可能在 stack_top 和 stack_empty 配合的时候, 需要
冗余判断一步 tail >= 0. 不过随着条件的分支预测, 实际影响不大, 也还好. 我们不妨写个业务测试.
#include <stack.h>
void stack_test(void) {
struct stack s; stack_init(&s);
char * str = NULL;
stack_push(&s, ++str);
stack_push(&s, ++str);
stack_push(&s, ++str);
// 数据输出
for (char * now; (now = stack_top(&s)); stack_pop(&s))
printf("now = %p\n", now);
stack_push(&s, ++str);
stack_push(&s, ++str);
for (char * now; (now = stack_top(&s)); stack_pop(&s))
printf("now = %p\n", now);
stack_free(&s);
}
那最终看 stack 实际运用场景吧, 运用显示栈来销毁查找树
// rtree_die - 后序删除树结点
static void rtree_die(struct $rtree * root, node_f fdie) {
struct $rtree * pre = NULL;
struct stack s; stack_init(&s);
stack_push(&s, root);
do {
struct $rtree * cur = stack_top(&s);
if ((!cur->left && !cur->right)
|| ((cur->left == pre || cur->right == pre) && pre)) {
fdie(pre = cur);
stack_pop(&s);
} else {
if (cur->right)
stack_push(&s, cur->right);
if (cur->left)
stack_push(&s, cur->left);
}
} while (!stack_empty(&s));
stack_free(&s);
}
更多细节代码可以阅读 rtree.h 对于二叉树后续非递归遍历, 压入右子树, 左子树,对比上次弹出的结点 ...
后记 - stack 未来展望
Friend- https://music.163.com/#/song?id=523560
错误是难免的, 欢迎交流提升 ~
基于当前 stack 设计, 未来展望具体从两方面处理. 复杂方面, 可以优化一下内存相关操作, 初始化,
扩容, 缩容等. 简单方面, 大家也看出来了, 这个栈代码极其少, 纯追求性能都可以直接放弃封装, 内嵌到
需要使用的地方和大业务混为一体. 那今天就到这里了, 2019/08/25 21:50 Dota2 OG 王朝真强
C基础 stack 设计的更多相关文章
- (2.15)Mysql之SQL基础——开发设计最佳规范
(2.15)Mysql之SQL基础——开发设计最佳规范 关键字:mysql三大范式,mysql sql开发规范 分析: show profile.mysqllsla.mysqldrmpslow.exp ...
- 小D课堂 - 新版本微服务springcloud+Docker教程_2_04微服务下电商项目基础模块设计
笔记 4.微服务下电商项目基础模块设计 简介:微服务下电商项目基础模块设计 分离几个模块,课程围绕这个基础项目进行学习 小而精的方式学习微服务 1.用户服务 ...
- SpringCloud Alibaba实战(3:存储设计与基础架构设计)
1.存储设计 在上一章中,我们已经完成了基本业务流程的梳理和服务模块的划分,接下来,开始设计数据存储. 虽然在微服务的理论中,没有对数据库定强制性的规范,但一般,服务拆分之后,数据库也会对应的拆分. ...
- Swift基础之设计折线坐标图
最近添加了折线视图的样式,所以在这里用Swift语言重新再使用设计一下 首先设置纵坐标的数值是:体重 //体重 let weightLabel = UILabel.init(frame: ...
- 网页基础:网页设计(我所知道的所有的html和css代码(含H5和CSS3)),如有错误请批评指正
最基础的网页设计,就是给你一个图片你做成一个网页,当然,我的工作是C#,个人网页的功底不是很高首先先认识一下网页的一些相关知识: 一般的,现在一个html网页一般包含html文件,css文件,js文件 ...
- 赢友网络通用框架V10.0.0(WinuAppSoft) 基础框架设计表
/* * 版权所有:赢友网络(http://www.winu.net/) * 开发人员:新生帝(JsonLei) * 设计名称:赢友网络通用框架V10.0.0(WinuAppSoft) * 设计时间: ...
- WCF基础之设计和实现服务协定
本来前面还有一个章节“WCF概述”,这章都是些文字概述,就不“复制”了,直接从第二章开始. 当然学习WCF还是要些基础的.https://msdn.microsoft.com/zh-cn/hh1482 ...
- C++标准库分析总结(五)——<Deque、Queue、Stack设计原则>
本节主要总结标准库Deque的设计方法和特性以及相关迭代器内部特征 1.Deque基本结构 Deque(双向队列)也号称连续空间(其实是给使用者一个善意的谎言,只是为了好用),其实它使用分段拼接起来的 ...
- 一、基础篇--1.1Java基础-MVC设计思想
MVC简介: MVC(Model View Controller) 是模型(model)-视图(view)-控制器(controller)的缩写.一种软件设计典范,用一种业务逻辑.数据.界面显示分离的 ...
随机推荐
- leetcode 数据库练习 - 1205 每月交易I和II
每月交易(一) Table: Transactions +---------------+---------+| Column Name | Type |+---------------+------ ...
- OpenFOAM——设置非均匀边界方法总结
在使用OpenFOAM求解的时候我们经常需要设置非均匀的边界,比如我们在计算层流的时候,很多时候需要入口为充分发展的入口边界,下面我们就以入口处为充分发展的层流速度分布为总结OpenFOAM当中设定不 ...
- cloudstack 安装 install for ubuntu
准备工作环境信息 修改dns配置 设置阿里源root@sh-saas-cs-manager-online-01:~# mv /etc/apt/sources.list /etc/apt/sources ...
- Java编程思想之九 接口
接口和内部为我们提供了一种将接口与实现分离的更加结构化的方法. 抽象类和抽象方法 创建一个抽象类是希望通过这个通用接口操纵一系列类. Java提供了一个叫做抽象方法的机制,这种方法是不完整的:仅声明而 ...
- MyBatis(九):Mybatis Java API批量操作(增、删、改、查)
最近工作中用到了mybatis的Java API方式进行开发,顺便也整理下该功能的用法,接下来会针对基本部分进行学习: 1)Java API处理一对多.多对一的用法: 2)增.删.改.查的用法: 3) ...
- Spring Cloud上下文:应用程序上下文服务
Spring Boot对于如何使用Spring构建应用程序有一个看法:例如它具有常规配置文件的常规位置,以及用于常见管理和监视任务的端点.Spring Cloud建立在此之上,并添加了一些可能系统中所 ...
- Armbian编译以及定制
Armbian项目地址 Github: https://github.com/armbian/build Armbian for TV Box 项目地址 Github: https://github. ...
- Python爬虫实例项目
WechatSogou [1]- 微信公众号爬虫.基于搜狗微信搜索的微信公众号爬虫接口,可以扩展成基于搜狗搜索的爬虫,返回结果是列表,每一项均是公众号具体信息字典. DouBanSpider [2]- ...
- 爬虫中采集动态HTML介绍
JavaScript JavaScript 是网络上最常用也是支持者最多的客户端脚本语言.它可以收集 用户的跟踪数据,不需要重载页面直接提交表单,在页面嵌入多媒体文件,甚至运行网页游戏. 我们可以在网 ...
- 使用CompletableFuture实现业务服务的异步调用实战代码
假如我有一个订单相关的统计接口,需要返回3样数据:今日订单数.今日交易额.总交易额. 一般的我们的做法是串行调用3个函数,把调用返回的结果返回给调用者,这3次调用时串行执行的,如果每个调用耗时1秒的话 ...