前言

李柱明博客:https://www.cnblogs.com/lizhuming/p/15487342.html

栈的定义

定义

栈(stack)是限定仅在表尾进行插入和删除操作的线性表。

  • 栈首先是一个线性表,栈元素具有线性关系。为特殊的线性表。
  • 栈顶(top):允许插入和删除的一端称为栈顶。
  • 栈底(bottom):另一端称为栈底。
  • 表尾指的是栈顶,而不是栈底。
  • 空栈:不含任何数据元素的栈称为空栈。
  • LIFO:last in first out,栈又称为后进先出的线性表,简称 LIFO 结构。
  • 栈的插入操作:进栈,也称压栈、入栈。
  • 栈的删除操作:出栈,也称弹栈。
  • 用数组实现的栈叫做:顺序栈
  • 用链表实现的栈叫做:链式栈

小笔记:

  • 内存中的堆栈和数据结构堆栈不是一个概念:

    • 内存中的堆栈是真实存在的物理区。内存空间在逻辑上分为三部分:代码区、静态数据区和动态数据区,动态数据区又分为栈区和堆区。

      • 代码区 :存储方法体的二进制代码。高级调度(作业调度)、中级调度(内存调度)、低级调度(进程调度)控制代码区执行代码的切换。
      • 静态数据区 :存储全局变量、静态变量、常量,常量包括 final 修饰的常量和 String 常量。系统自动分配和回收。
      • 栈区 :存储运行方法的形参、局部变量、返回值。由系统自动分配和回收。例如 int method(int a){int b;}栈中存储参数 a、局部变量 b、返回值 temp。
      • 堆区 :new 一个对象的引用或地址存储在栈区,指向该对象存储在堆区中的真实数据。由程序员分配和回收。
    • 数据结构中的堆栈是抽象的数据存储结构。

      • :是一种连续存储的数据结构,特点是存储的数据先进后出。
      • :是一棵完全二叉树结构,特点是父节点的值大于(小于)两个子节点的值(分别称为大顶堆和小顶堆)。它常用于管理算法执行过程中的信息,应用场景包括堆排序,优先队列等。

常见应用

栈相对于数组和链表来说只有限制,是操作受限的线性表。从功能上,数组和链表也可以代替栈,但是数组或链表暴露了太多的操作接口,操作上的确灵活自由,但使用时就比较不可控,自然也就更容易出错。

栈的常见应用

  • 软件中的撤销(undo)操作,浏览器历史纪录,Android 中的最近任务,Activity 的启动模式,CPU 中栈的实现,Word 自动保存,解析计算式,解析 xml/json。

进栈出栈变化形式

出栈序列个数公式:卡特兰公式:C(2n,n)/(n+1)

  • n 为前几个数时的值:1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796 ...

栈的抽象数据类型

栈为线性表,具备线性表的操作特性。

对于栈来说,插入和删除改名为 push 和 pop。

栈的顺序存储结构及实现

栈的顺序存储结构

顺序栈

  • 栈的顺序存储也是线性表顺序存储的简化,简称为顺序栈。
  • 在数组中,用下标为 0 的一段作为栈底。
  • 栈顶 top:若存储栈长度为 stack_size,则 top 必须少于 stack_size。
  • 空栈:栈中有一个元素时,top=0。空栈时,top = -1。

顺序栈的结构定义

  • 指针式
// 指针式
typedef int se_type; /* 元素类型 */
typedef struct
{
se_type *top; /* 栈顶指针 */
se_type *bottom; /* 栈底指针 */
se_type stack_size; /* 栈的最大容量 */
}stack_t;
  • 数组式
// 数组式
typedef int se_type; /* 元素类型 */
#define STACK_SIZE 100 /* 栈元素个数 */
typedef struct
{
int top; /* 栈顶指针 */
se_type data[STACK_SIZE]; /* 栈空间 */
}stack_t;

两栈共享空间

两栈共享空间

  • 原理:两个栈底分别位于数组的始端(下标 0)和数组的末端(下标数组长度 n-1),增加元素即从两端点向中间延伸。

  • 条件:两个具有相同数据类型的栈,生长方向相反。

  • 满栈判断:

    • 一般情况:两个栈见面之时,即两个指针相差 1,top1+1 == top2 时。
    • 极端情况:stack_2 空时,top1=n-1,则 stack_1 满;stack_1 空,top2=0,则 stack_2 满。

部分代码实现

// 数组式
/* 两栈共享空间结构 */
typedef int se_type; /* 元素类型 */
#define STACK_SIZE 100 /* 栈元素个数 */
typedef struct
{
int top1; /* 栈顶指针 */
int top2; /* 栈顶指针 */
se_type data[STACK_SIZE]; /* 栈空间 */
}stack_double_t; /**
* @name stack_double_creat
* @brief
* @param
* @retval
* @author lzm
*/
stack_double_t *stack_double_creat(void)
{
stack_t *stack_double_ptr = NULL; stack_double_ptr = (stack_double_t *)malloc(sizeof(stack_double_t));
if(stack_double_ptr == NULL)
return NULL;
memset(stack_ptr, 0x00, sizeof(stack_double_t)); stack_double_ptr->top1 = -1;
stack_double_ptr->top2 = STACK_SIZE; return stack_double_ptr;
} /**
* @name stack_double_destroy
* @brief
* @param
* @retval
* @author lzm
*/
int stack_double_destroy(stack_double_t *stack)
{
if(stack != NULL)
{
free(stack);
return 0;
} return -1;
}

栈的链式存储结构及实现

栈的链式存储结构

就是基于链表实现的栈。

栈的链式存储结构:

  • 栈的链式存储结构,简称链栈。
  • 栈顶放在单链表的头部,且不需要头结点。(自主决定
  • 空栈:链表原定义为头指针指向空,故链栈的空是 top = NULL。
  • 结构:
/* 链式结构 */
typedef int se_type; /* 元素类型 */
typedef struct stack_node
{
se_type date;
struct stack_node *next;
}stack_node_t; typedef struct
{
int count;
stack_node_t *top;
}stack_link_t;

栈的应用之递归

递归的定义:

  • 把一个直接调用自己或者通过一系列的调用语句间接地调用自己的函数,称为递归函数。
  • 每个递归定义必须至少有一个条件,满足时递归不再进行,即不再引用自身而是返回值退出。(出口条件)

递归与栈结构:

  • 递归进入时,压栈。
  • 递归退出时,出栈。

代码实现

指针式顺序栈操作

/** @file         stack.c
* @brief 简要说明
* @details 详细说明
* @author lzm
* @date 2021-09-06 09:42:22
* @version v1.0
* @copyright Copyright By lizhuming, All Rights Reserved
* @blog https://www.cnblogs.com/lizhuming/
*
**********************************************************
* @LOG 修改日志:
**********************************************************
*/ #include <stdio.h>
#include <stdlib.h>
#include <string.h> // 指针式
typedef int se_type; /* 元素类型 */
typedef struct
{
se_type *top; /* 栈顶指针 */
se_type *bottom; /* 栈底指针 */
se_type stack_size; /* 栈的最大容量,元素个数。 */
}stack_pointer_t; /**
* @name stack_pointer_creat
* @brief
* @param
* @retval
* @author lzm
*/
stack_pointer_t *stack_pointer_creat(int size)
{
stack_pointer_t *stack_ptr = NULL; stack_ptr = (stack_pointer_t *)malloc(sizeof(stack_pointer_t));
if(stack_ptr == NULL)
return NULL;
memset(stack_ptr, 0x00, sizeof(stack_pointer_t)); stack_ptr->bottom = (se_type *)malloc(size * sizeof(se_type));
if(stack_ptr->bottom == NULL)
{
free(stack_ptr);
return NULL;
}
memset(stack_ptr->bottom, 0x00, size * sizeof(se_type)); stack_ptr->top = stack_ptr->bottom;
stack_ptr->stack_size = size; return stack_ptr;
} /**
* @name stack_pointer_destroy
* @brief
* @param
* @retval
* @author lzm
*/
int stack_pointer_destroy(stack_pointer_t *stack)
{
if(stack != NULL)
{
if(stack->bottom != NULL)
free(stack->bottom); free(stack); return 0;
} return -1;
} /**
* @name stack_pointer_clear
* @brief
* @param
* @retval
* @author lzm
*/
int stack_pointer_clear(stack_pointer_t *stack)
{
if(stack == NULL)
return -1; stack->top = stack->bottom; return 0;
} /**
* @name stack_pointer_empty
* @brief
* @param
* @retval
* @author lzm
*/
int stack_pointer_empty(stack_pointer_t *stack)
{
if(stack == NULL)
return -1; if(stack->top == stack->bottom)
return 1; return 0;
} /**
* @name stack_pointer_full
* @brief
* @param
* @retval
* @author lzm
*/
int stack_pointer_full(stack_pointer_t *stack)
{
if(stack == NULL)
return -1; if(stack->top == (stack->bottom + stack->stack_size * sizeof(se_type)))
return 1; return 0;
} /**
* @name stack_pointer_length
* @brief
* @param
* @retval
* @author lzm
*/
int stack_pointer_length(stack_pointer_t *stack)
{
if(stack == NULL)
return -1; return (stack->top - stack->bottom)/sizeof(se_type);
} /**
* @name stack_pointer_push
* @brief
* @param
* @retval
* @author lzm
*/
int stack_pointer_push(stack_pointer_t *stack, se_type elem)
{
if(stack_pointer_full(stack) != 0)
return -1; *stack->top = elem;
stack->top += sizeof(se_type); return 0;
} /**
* @name stack_pointer_pop
* @brief
* @param
* @retval
* @author lzm
*/
int stack_pointer_pop(stack_pointer_t *stack, se_type *elem)
{
if(stack_pointer_empty(stack) != 0)
{
elem = NULL;
return -1;
} stack->top -= sizeof(se_type);
elem = stack->top; return 0;
} int main(void)
{
;
}

数组式顺序栈操作

/** @file         stack.c
* @brief 简要说明
* @details 详细说明
* @author lzm
* @date 2021-09-06 09:42:22
* @version v1.0
* @copyright Copyright By lizhuming, All Rights Reserved
* @blog https://www.cnblogs.com/lizhuming/
*
**********************************************************
* @LOG 修改日志:
**********************************************************
*/ #include <stdio.h>
#include <stdlib.h>
#include <string.h> // 数组式
typedef int se_type; /* 元素类型 */
#define STACK_SIZE 100 /* 栈元素个数 */
typedef struct
{
int top; /* 栈顶指针 */
se_type data[STACK_SIZE]; /* 栈空间 */
}stack_t; /**
* @name stack_creat
* @brief
* @param
* @retval
* @author lzm
*/
stack_t *stack_array_creat(void)
{
stack_t *stack_ptr = NULL; stack_ptr = (stack_t *)malloc(sizeof(stack_t));
if(stack_ptr == NULL)
return NULL;
memset(stack_ptr, 0x00, sizeof(stack_t)); stack_ptr->top = -1; return stack_ptr;
} /**
* @name stack_destroy
* @brief
* @param
* @retval
* @author lzm
*/
int stack_array_destroy(stack_t *stack)
{
if(stack != NULL)
{
free(stack);
return 0;
} return -1;
} /**
* @name stack_clear
* @brief
* @param
* @retval
* @author lzm
*/
int stack_array_clear(stack_t *stack)
{
if(stack == NULL)
return -1; stack->top = -1; return 0;
} /**
* @name stack_empty
* @brief
* @param
* @retval
* @author lzm
*/
int stack_array_empty(stack_t *stack)
{
if(stack == NULL)
return -1; if(stack->top == -1)
return 1; return 0;
} /**
* @name stack_full
* @brief
* @param
* @retval
* @author lzm
*/
int stack_array_full(stack_t *stack)
{
if(stack == NULL)
return -1; if(stack->top == STACK_SIZE-1)
return 1; return 0;
} /**
* @name stack_length
* @brief
* @param
* @retval
* @author lzm
*/
int stack_array_length(stack_t *stack)
{
if(stack == NULL)
return -1; return stack->top + 1;
} /**
* @name stack_push
* @brief
* @param
* @retval
* @author lzm
*/
int stack_array_push(stack_t *stack, se_type elem)
{
if(stack_array_full(stack) != 0)
return -1; stack->top++;
stack->data[stack->top] = elem; return 0;
} /**
* @name stack_pop
* @brief
* @param
* @retval
* @author lzm
*/
int stack_array_pop(stack_t *stack, se_type *elem)
{
if(stack_array_empty(stack) != 0 || elem == NULL)
{
return -1;
} *elem = stack->data[stack->top];
stack->top--; return 0;
} /**
* @name stack_get_top
* @brief
* @param
* @retval
* @author lzm
*/
int stack_array_get_top(stack_t *stack, se_type *elem)
{
if(stack_array_empty(stack) != 0 || elem == NULL || stack->top >= STACK_SIZE)
{
return -1;
} *elem = stack->data[stack->top]; return 0;
}

链式栈

/** @file         stack.c
* @brief 简要说明
* @details 详细说明
* @author lzm
* @date 2021-09-06 22:52:12
* @version v1.0
* @copyright Copyright By lizhuming, All Rights Reserved
* @blog https://www.cnblogs.com/lizhuming/
*
**********************************************************
* @LOG 修改日志:
**********************************************************
*/ #include <stdio.h>
#include <stdlib.h>
#include <string.h> /* 链式结构 */
typedef int se_type; /* 元素类型 */
typedef struct stack_node
{
se_type date;
struct stack_node *next;
}stack_node_t; typedef struct
{
int count;
stack_node_t *top;
}stack_link_t; /**
* @name stack_link_creat
* @brief
* @param
* @retval
* @author lzm
*/
stack_link_t *stack_creat(int size)
{
stack_link_t *stack_ptr = NULL; stack_ptr = (stack_link_t *)malloc(sizeof(stack_link_t));
if(stack_ptr == NULL)
return NULL;
memset(stack_ptr, 0x00, sizeof(stack_link_t)); stack_ptr->count = 0;
stack_ptr->top = NULL; return stack_ptr;
} /**
* @name stack_link_destroy
* @brief
* @param
* @retval
* @author lzm
*/
int stack_link_destroy(stack_link_t *stack)
{
stack_node_t *stack_cur = NULL;
stack_node_t *stack_last = NULL; if(stack == NULL)
return -1; stack_cur = stack->top;
while(stack_cur)
{
stack_last = stack_cur;
stack_cur = stack_cur->next;
free(stack_last);
} free(stack); return 0;
} /**
* @name stack_link_clear
* @brief
* @param
* @retval
* @author lzm
*/
int stack_link_clear(stack_link_t *stack)
{
stack_node_t *stack_cur = NULL;
stack_node_t *stack_last = NULL; if(stack == NULL)
return -1; stack_cur = stack->top;
while(stack_cur)
{
stack_last = stack_cur;
stack_cur = stack_cur->next;
free(stack_last);
} return 0;
} /**
* @name stack_link_empty
* @brief
* @param
* @retval
* @author lzm
*/
int stack_link_empty(stack_link_t *stack)
{
if(stack == NULL)
return -1; if(stack->count == 0)
return 1; return 0;
} /**
* @name stack_link_length
* @brief
* @param
* @retval
* @author lzm
*/
int stack_link_length(stack_link_t *stack)
{
if(stack == NULL)
return -1; return (stack->count);
} /**
* @name stack_link_push
* @brief
* @param
* @retval
* @author lzm
*/
int stack_link_push(stack_link_t *stack, se_type elem)
{
stack_node_t *stack_node_ptr = NULL; stack_node_ptr = (stack_node_t *)malloc(sizeof(stack_node_t));
if(stack_node_ptr == NULL)
return -1;
memset(stack_node_ptr, 0x00, sizeof(stack_node_t)); stack_node_ptr->date = elem;
stack_node_ptr->next = stack->top;
stack->top = stack_node_ptr->next;
stack->count++; return 0;
} /**
* @name stack_link_pop
* @brief
* @param
* @retval
* @author lzm
*/
int stack_link_pop(stack_link_t *stack, se_type *elem)
{
stack_node_t *node = NULL;
if(stack_link_empty(stack) != 0 || elem == NULL)
{
return -1;
} *elem = stack->top->date;
node = stack->top;
stack->top = stack->top->next;
free(node);
stack->count--; return 0;
} /**
* @name stack_link_get_top
* @brief
* @param
* @retval
* @author lzm
*/
int stack_link_get_top(stack_link_t *stack, se_type *elem)
{
if(stack_link_empty(stack) != 0 || elem == NULL)
{
return -1;
} *elem = stack->top->date; return 0;
}

【数据结构&算法】08-栈概念&源码的更多相关文章

  1. C语言- 基础数据结构和算法 - 08 栈的应用_就近匹配20220611

    听黑马程序员教程<基础数据结构和算法 (C版本)>, 照着老师所讲抄的, 视频地址https://www.bilibili.com/video/BV1vE411f7Jh?p=1 喜欢的朋友 ...

  2. 中国象棋程序的设计与实现(六)--N皇后问题的算法设计与实现(源码+注释+截图)

    八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题. 该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列 ...

  3. <Linux内核源码>文件系统VFS内核4.0.4版本基本概念源码

    题外话:Linux内核从2.x和3.x到现在最新的4.x变化非常大,最直观的表现就是很多书上的内核代码已经无法直接继续使用,所以看看新的源码是非常有意义的! (下文中的内核源码都来自于 kernel ...

  4. 数据挖掘:关联规则的apriori算法在weka的源码分析

    相对于机器学习,关联规则的apriori算法更偏向于数据挖掘. 1) 测试文档中调用weka的关联规则apriori算法,如下 try { File file = new File("F:\ ...

  5. 数据挖掘 FP-tree算法C++实现及源码

    FP-growth挖掘算法 步骤一 扫描数据库,扫描数据库一次,得到频繁1-项集,把项按支持度递减排序,再一次扫描数据库,建立FP-tree 步骤二 对每个项,生成它的 条件模式库 步骤三 用条件模式 ...

  6. 常用限流算法与Guava RateLimiter源码解析

    在分布式系统中,应对高并发访问时,缓存.限流.降级是保护系统正常运行的常用方法.当请求量突发暴涨时,如果不加以限制访问,则可能导致整个系统崩溃,服务不可用.同时有一些业务场景,比如短信验证码,或者其它 ...

  7. 常见算法合集[java源码+持续更新中...]

    一.引子 本文搜集从各种资源上搜集高频面试算法,慢慢填充...每个算法都亲测可运行,原理有注释.Talk is cheap,show me the code! 走你~ 二.常见算法 2.1 判断单向链 ...

  8. 最快速的“高斯”模糊算法(附Android源码)

      这是一个外国人的算法,本人是搬运工.参考:http://blog.ivank.net/fastest-gaussian-blur.html   1:高斯模糊算法(参考:http://www.rua ...

  9. A*算法(附c源码)

    关于A*算法网上介绍的有很多,我只是看了之后对这个算法用c写了一下,并测试无误后上传以分享一下,欢迎指正!下面是我找的一个介绍,并主要根据这个实现的. 寻路算法不止 A* 这一种, 还有递归, 非递归 ...

随机推荐

  1. Docker系列(8)- 常用其他命令(1) | 日志、元数据、进程的查看

    后台启动容器 # 命令 docker run -d 镜像名 [root@localhost ~]# docker run -d centos #问题:docker ps,发现centos停止了 #常见 ...

  2. Linux系列(38) - 源码包安装(2)

    安装前准备 安装C语言编译器"gcc" yum -y install gcc --c 源码包语言编译器 下载源码包 安装注意事项 源代码保存位置:/usr/local/src/ 软 ...

  3. YOLO v3 & Pascal VOC数据集

    代码地址:https://github.com/YunYang1994/tensorflow-yolov3 https://hackernoon.com/understanding-yolo-f5a7 ...

  4. 送你一个Python 数据排序的好方法

    摘要:学习 Pandas排序方法是开始或练习使用 Python进行基本数据分析的好方法.最常见的数据分析是使用电子表格.SQL或pandas 完成的.使用 Pandas 的一大优点是它可以处理大量数据 ...

  5. requests接口自动化-assert断言

    断言,自动判断接口返回的结果与预期结果是否一致 from common.get_mysql import * def test_assert(): a=0 b=1 # assert a,'断言失败打印 ...

  6. 在modal中的datetimepicker插件BUG修复

    前言:因为在模态框用到datetimepicker这一日期控件,而选中日期时,会触发模态框的再次打开,导致上面表单选的值会重新加载 解决办法: 用stopPropagation() 方法阻止事件传播, ...

  7. 位运算符的用法 ----非(!),与(&),或(|),异或(^)

    位运算符的用法 ----非(!),与(&),或(|),异或(^) 三种运算符均针对二进制 非!:是一元运算符.对一个二进制的整数按位取反,输入0则输出1,输入1则输出0. 例: 0100 -( ...

  8. The art of multipropcessor programming 读书笔记-硬件基础2

    本系列是 The art of multipropcessor programming 的读书笔记,在原版图书的基础上,结合 OpenJDK 11 以上的版本的代码进行理解和实现.并根据个人的查资料以 ...

  9. mysql从零开始之MySQL 创建数据库

    MySQL 创建数据库 我们可以在登陆 MySQL 服务后,使用 create 命令创建数据库,语法如下: CREATE DATABASE 数据库名; 以下命令简单的演示了创建数据库的过程,数据名为 ...

  10. 学校选址(ArcPy实现)

    一.背景 合理的学校空间位置布局,有利于学生的上课与生活.学校的选址问题需要考虑地理位置.学生娱乐场所配套.与现有学校的距离间隔等因素,从总体上把握这些因素能够确定出适宜性比较好的学校选址区. 二.目 ...