前言 - stack 设计思路

  先说说设计 stack 结构的原由. 以前我们再释放查找树的时候多数用递归的后续遍历去释放.

其内部隐含了运行时的函数栈, 有些语言中存在爆栈风险. 所以想运用显示栈来替代隐式函数栈.

这就是我们设计 stack 的背景.  而我们这里的 stack 设计思路也比较直白, 运用可变数组进行尾

部压入和尾部弹出操作. 具体可见下图. 从左到右式弹出过程,

从右到左就是压入过程.

正文 - stack 详细设计

  话不多说, 先看实现 code

stack.hhttps://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 未来展望

  Friendhttps://music.163.com/#/song?id=523560 

  错误是难免的, 欢迎交流提升 ~

  基于当前 stack 设计, 未来展望具体从两方面处理. 复杂方面, 可以优化一下内存相关操作, 初始化,

扩容, 缩容等. 简单方面, 大家也看出来了, 这个栈代码极其少, 纯追求性能都可以直接放弃封装, 内嵌到

需要使用的地方和大业务混为一体. 那今天就到这里了, 2019/08/25 21:50 Dota2 OG 王朝真强

C基础 stack 设计的更多相关文章

  1. (2.15)Mysql之SQL基础——开发设计最佳规范

    (2.15)Mysql之SQL基础——开发设计最佳规范 关键字:mysql三大范式,mysql sql开发规范 分析: show profile.mysqllsla.mysqldrmpslow.exp ...

  2. 小D课堂 - 新版本微服务springcloud+Docker教程_2_04微服务下电商项目基础模块设计

    笔记 4.微服务下电商项目基础模块设计     简介:微服务下电商项目基础模块设计 分离几个模块,课程围绕这个基础项目进行学习             小而精的方式学习微服务 1.用户服务       ...

  3. SpringCloud Alibaba实战(3:存储设计与基础架构设计)

    1.存储设计 在上一章中,我们已经完成了基本业务流程的梳理和服务模块的划分,接下来,开始设计数据存储. 虽然在微服务的理论中,没有对数据库定强制性的规范,但一般,服务拆分之后,数据库也会对应的拆分. ...

  4. Swift基础之设计折线坐标图

    最近添加了折线视图的样式,所以在这里用Swift语言重新再使用设计一下 首先设置纵坐标的数值是:体重 //体重        let weightLabel = UILabel.init(frame: ...

  5. 网页基础:网页设计(我所知道的所有的html和css代码(含H5和CSS3)),如有错误请批评指正

    最基础的网页设计,就是给你一个图片你做成一个网页,当然,我的工作是C#,个人网页的功底不是很高首先先认识一下网页的一些相关知识: 一般的,现在一个html网页一般包含html文件,css文件,js文件 ...

  6. 赢友网络通用框架V10.0.0(WinuAppSoft) 基础框架设计表

    /* * 版权所有:赢友网络(http://www.winu.net/) * 开发人员:新生帝(JsonLei) * 设计名称:赢友网络通用框架V10.0.0(WinuAppSoft) * 设计时间: ...

  7. WCF基础之设计和实现服务协定

    本来前面还有一个章节“WCF概述”,这章都是些文字概述,就不“复制”了,直接从第二章开始. 当然学习WCF还是要些基础的.https://msdn.microsoft.com/zh-cn/hh1482 ...

  8. C++标准库分析总结(五)——<Deque、Queue、Stack设计原则>

    本节主要总结标准库Deque的设计方法和特性以及相关迭代器内部特征 1.Deque基本结构 Deque(双向队列)也号称连续空间(其实是给使用者一个善意的谎言,只是为了好用),其实它使用分段拼接起来的 ...

  9. 一、基础篇--1.1Java基础-MVC设计思想

    MVC简介: MVC(Model View Controller) 是模型(model)-视图(view)-控制器(controller)的缩写.一种软件设计典范,用一种业务逻辑.数据.界面显示分离的 ...

随机推荐

  1. luogu P1550 [USACO08OCT]打井Watering Hole

    题目背景 John的农场缺水了!!! 题目描述 Farmer John has decided to bring water to his N (1 <= N <= 300) pastur ...

  2. 洛谷 P4149 [IOI2011]Race-树分治(点分治,不容斥版)+读入挂-树上求一条路径,权值和等于 K,且边的数量最小

    P4149 [IOI2011]Race 题目描述 给一棵树,每条边有权.求一条简单路径,权值和等于 KK,且边的数量最小. 输入格式 第一行包含两个整数 n, Kn,K. 接下来 n - 1n−1 行 ...

  3. 【XR-4】题

    题面 题解 由题,所求为方程\(y^2 = x^2 + ax + b\)的整数解数量. 两边同乘\(4\),可得\((2y)^2 = 4x^2 + 4ax + 4b\). 配方后得\((2y)^2 = ...

  4. 分布式id的生成方式——雪花算法

    雪花算法是twitter开源的一个算法. 由64位0或1组成,其中41位是时间戳,10位工作机器id,12位序列号,该类通过方法nextID()实现id的生成,用Long数据类型去存储. 我们使用id ...

  5. redis三种模式对比

    模式类型 主从模式(redis2.8版本之前的模式).哨兵sentinel模式(redis2.8及之后的模式).redis cluster模式(redis3.0版本之后) 主从模式原理 同Mysql主 ...

  6. 第1001次安kali

    第1001次安kali 由于VMware跟win10有仇等原因,最终投入了VirtualBox的怀抱 主要参考这个博客Kali Linux安装教程--VirtualBox 参考Kali安装教程(Vir ...

  7. 大牛总结的MySQL锁优化【转】

    MySQL 就是其中之一,它经历了多个版本迭代.数据库锁是 MySQL 数据引擎的一部分,今天我们就一起来学习 MySQL 的数据库锁和它的优化. MySQL 锁分类 当多个事务或者进程访问同一个资源 ...

  8. Refused to execute script from '...' because its MIME type ('') is not executable, and strict MIME type checking is enabled.

    写在前面 部署项目到weblogic上启动首页访问空白, 浏览器控制台报如题错误. web.xml中把响应头添加防止攻击的报文过滤器禁用就行了(仅仅是为了启动), 以下为转载内容, 可以根据需要自行测 ...

  9. Cookie的Secure属性和HttpOnly属性

    基于安全的考虑,需要给cookie加上Secure和HttpOnly属性,HttpOnly比较好理解,设置HttpOnly=true的cookie不能被js获取到,无法用document.cookie ...

  10. 自己写的一个 CGBLIB 动态代理【原创】

    CGLIB代理类,用CGLIB来实现一个代理类.大致原理描述如下: 1.使用Enhancer类来生成一个继续于被代理类的子类,此子类会重写被代理类(父类)中所有的非final的public方法: 2. ...