由一个例子学习栈

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

 /*
==========================================
作者:rerli
时间:2003-12-03(修改稿)
目的:由一个例子学习栈。

栈应用详解:

栈的实现可以用数组,亦可用链表。
下面讲讲这两种实现栈结构的详细程序,并分别看看:
用栈改递归为非递归,计算Ackermann函数A(n,x,y)。
===========================================
*/

/*
===========================================
 第一种:数组
 可以看出,下面的程序并没有真正用数组去实现,
 而是使用指针。使用指针操作起来比数组稍微灵活
 一点。下面的实现你将体会到。

 栈底就是初始化后stack的首地址;
 栈顶就是最后一个入栈元素的尾地址。
 栈顶指针就是地址指针。
===========================================
*/


#include <stdlib.h>
#include <stdio.h>
#define NULL 0

typedef struct node
{
 int n;
 double x;
 double y;
}NODE;

#define LEN sizeof(NODE)

/*栈的需要变量*/
typedef enum {false,true}bool; /*定义bool类型*/
static NODE *p_stack=NULL; /*定义栈指针变量*/
static NODE *stack=NULL; /*定义一个栈*/
static unsigned int stack_size=0; /*栈的大小*/

/*
=========================================================
  栈空
|     |
|_____|
|_____|
|_____|
  NUll <---p_stack

 出栈前
|     |
|_____|<---p_stack
|__1__|
|__0__|

 出栈后
|     |
|_____|
|__1__|<---p_stack
|__0__|

从上图可知:
1、出栈前,栈顶指针没有指向任何元素;
2、出栈后,栈顶指针指向的是刚才出栈元素的首地址。
3、这种数组(或指针)栈描述显然有点不符合栈的定义,即栈顶指针并不是真正意义的指向栈顶(有点难懂,但从图中可以很快悟出)。
4、显然若我们用Pop()栈顶值后,用*p_stack取值,则必然得到Pop()出来的值一模一样。
==========================================================
*/


/*
========================
 功能:初始化栈的大小
 返回:true or false
========================
*/
bool InitStack(unsigned int size)
{
 stack=(NODE *)malloc(size*LEN); /*开辟空间*/      
 if (stack==NULL) /*开辟空间失败,则返回false*/
 {
  return false;
 }
 stack_size = size; /*保存栈空间大小值*/
 p_stack = stack; /*栈顶指针赋初值*/   
 return true; /*初始化成功,返回true*/
}

/*
======================
 功能:释放栈的内存
 返回:void
======================
*/
void FreeStack()
{
 free(stack);
 /*
   注意:这一点很重要。free()之后并不能将stack
   置为NULL,所以我们一定要自己做。这样能防止产生
   “野指针”,即地址不确定的指针。
 */
 stack = NULL; 
}

/*
==========================
 功能:判断栈是否已满
 返回:true or false
==========================
*/
bool Full()
{
 /*栈顶指针与栈的初始地址的差,如果大于等于空间值,则此时栈满*/
 return (p_stack-stack)>=stack_size;
}

/*
===========================
 功能:判断栈是否为空
 返回:true or false
===========================
*/
bool Empty()
{
 /*栈顶指针与栈的初始地址的相等,则栈空*/
 return (p_stack==stack);
}

/*
========================
 功能:入栈
 返回:true or false
========================
*/
bool Push(NODE p)
{
 if (!Full()) /*栈不满,则入栈;栈顶指针要上移*/
 {
  *p_stack = p;
  p_stack++;
  return true;
 }
 else
 {
  printf("stack is overflow !/n");
  return false;
 }
}

/*
===================
 功能:出栈
 返回:出栈元素
===================
*/
NODE Pop()
{
 if (!Empty()) /*栈不空,则出栈;栈顶指针要下移*/
 {
  return *(--p_stack);
 }
 else
 {
  printf("stack is empty !/n");  
 }
}

 

/*
===================================================
 功能:用栈改递归为非递归,计算Ackermann函数A(n,x,y)。
 返回:double 计算结果
===================================================
*/
double Ackermann(NODE node)
{
 double B;
 NODE tnode;
 
 if (!Full())
 {
  Push(node);
 }
 
 while (!Empty())
 {
  tnode = Pop();  
  while (tnode.n != 0 && tnode.y != 0) /*递推,将计算参数进栈*/
  {
   /*修改栈顶节点的字段值,如果不好理解的话,可以参考上面的图示*/
   p_stack->n--;
   p_stack->y = p_stack->x;
   p_stack->x = -1.0; /*表示x值不确定*/
   
   /*新求得的节点值进栈*/
   tnode.y -= 1.0;
   if (!Push(tnode)) /*将下一步进栈*/
   {
    return -1.0;
   }
  }
  
  if (!Empty())
  {
   tnode = Pop();
  }  
  if (tnode.n == 0)
  {
   B = tnode.x + 1.0;
  }
  else if (tnode.n == 1)
  {
   B = tnode.x;
  }
  else if (tnode.n == 2)
  {
   B = 0.0;
  }
  else if (tnode.n == 3)
  {
   B =  1.0;
  }
  else
  {
   B = 2.0;
  }

  if (!Empty())
  {
   p_stack->x = B; /*栈不为空,则栈顶节点的x值改为B*/
  }
 }
 return B;
}


void main(void)

 NODE node1 = {3,1,2};
 
 if (!InitStack(50)) /*初始化不成功,则退出*/
 {
  exit(0);
 }
 
 printf("Ackermann(%d,%d,%d) = %.2f/n",node1.n,(int)node1.x,(int)node1.y,Ackermann(node1));
 
 FreeStack(); /*注意程序退出时释放栈内存*/

 printf("/n");
 system("pause");
}

数据结构——和队列 :是一种特殊的线性表,遵守**后进先出LIFO(Last In First Out)**原则。 表的尾端称为顶,表头端称为底。 示例: 入:1,2,3,4,5,6 … 生活中的例子: 1.垒砖,砖块总是放置在已经垒好的砖块上面; 2.洗盘子,洗好的盘子总是逐个往上叠放在已经洗好的盘子上 … 实现 (1) 顺序表实现: 使用尾插操作表示 “入 ”; 使用尾删操作表示 “出 ”; 使用根据下标去元素的操作表示 “取顶元素 ”。 // 使用顺序表实现: public c 阅读详情

相关推荐

简单的两道例子

引言    两道关于的简单例子:    1.单词逆序        用进行单词逆序:输入一个字符串,然后输出原字符串顺序倒置后的字符串。        首先,字符串从输入的时候一个一个的提取出来并且压入中。接着它们依次弹出,并显示出来。因为的后进先出的特性,所以字母的顺序就颠倒过来了。/** * @Description Reverse 单词逆序-- * @author whm...

weihuiming 4754

数据结构——

的概念 :是一个种特殊的线性表,只允许在固定的一端进行插入与删除元素的操作。在进行数据插入和删除操作的一端成为顶,另一端成为底。中的元素遵守后进先出的原则。也叫先进后出。 举个例子在我们的生活中的应用是经常见到的。我们大家在小时候应该都会玩过玩具枪,玩具枪里面的弹夹大家都不陌生吧,一颗一颗的子弹压入弹夹中,最后压入的子弹是最先被发射出来的。 在软件应用中,也是非常普遍的。比如我们在用浏览器浏览东西时,不管什么浏览器都会有一个“返回键”,点击后会按照你访问的顺序逆序后退...

weixin_57525369的博客 4771

Stacksort 排序的简单例子

Stacksort // // main.cpp // T2_StackSort // // Created by apple on 2019/2/18. // Copyright © 2019 apple. All rights reserved. // #include &amp;amp;lt;iostream&amp;amp;gt; #include &amp;amp;lt;stack&amp;amp;gt; #include &amp;amp;lt;v

PzLu's Blog 1838

数据结构:

(Stack) 1. 概念 :一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作 进行数据插入和删除操作的一端称为顶,另一端称为中的数据元素遵守后进先出LIFO(Last In First Out)的原则 压的插入操作叫做进/压/入,入数据在顶 出的删除操作叫做出。出数据在的常用方法: 方法 解释 E push(E item) 压 E pop() 出 E peek() 查看顶元素 ..

qq_55996124的博客 672

数据结构-

下面我用模拟一下我们拿书的过程:现在我们要拿三国演义这本书:第一步:取出水浒传,放一边第二步:取出西游记,放一边第三步:取出三国演义第四步:把西游记和水浒传放回书箱内。

small_ze_career的博客 921

的几个实例应用

简单括号匹配 问题描述:括号的使用必须遵循 “平衡”规则,即 首先,每个开括号要恰好对应一个闭括号; 其次,每对开闭括号要正确的嵌套 正确的括号:(()()()()),(((()))), (()((())())) 错误的括号:((((((()),())),(()()(() 对括号是否正确匹配的识别,是很多语言编译器的基础算法 解题思路:从左到右扫描括号串,最新打开的左括号,应该匹配最先遇到的右括号 这样,第一个左括号(最早打开),就应该匹配 最后一个右括号(最后遇到) 这种次序反转的识别,正好符合的特性

heitong_fu的博客 4856

一个例子学习(续)

/*=================================================================作者:rerli时间:2003-12-03(修改稿)目的:由一个例子学习应用详解:的实现可以用数组,亦可用链表。下面讲讲这两种实现结构的详细程序,并分别看看:用改递归为非递归,计算Ackermann函数A(n,x,y)。=============

rerli的专栏 2230

和队列的入门

一、的基本概念 1、定义 :是只允许在一端进行插入或删除的线性表。首先是一种线性表,但限定这种线性表只能在某一端进行插入和删除操作。 顶(Top):线性表允许进行插入删除的那一端。 底:固定的,不允许进行插入和删除的另一端。 空:不含任何元素的空表。又称为后进先出(Last In First Out)的线性表,简称LIFO结构 2、的常见基本操作 Push(&S, x):进的插入操作),若S未满,则将x加入使之成为新顶。 Pop(&S, &x...

amuranus的博客 343

关于C语言中printf()的出入顺序问题

关于C语言中printf函数参数调用顺序的探究实验

LJR_LJRRR的博客 532

一个例子

 import java.lang.*;public class MyStack{ private Object[] obj = new Object[100]; private int size = 0;//数组里面元素的个数 public MyStack(){}//构造方法 public boolean empty(){//判断是否为空  return size==0; } p

soundyrose的专栏 857

的最后一个例子

 import java.lang.*;import java.util.*;public class zhang{ public static void main(String[] args) {  String str1 = new String("ANGEL");  String str2 = new String("fangfang");  String str3 = new String

soundyrose的专栏 468

回溯法的一个例子

代码转自看雪论坛【驱动防火墙的一个例子】,直接复制过来的,看起来比较乱,不过还是很容易看懂的 看了几个例子,一般都是在ExAllocatePoolWithTag这里挂钩啊,根据MemoryTag来判断,以后再发现发现有没有更精准的挂钩位置 #include #include #include #include #include "MmLoadSystemImage.h" #defi

kedebug 2702

如何自己实现一个

前言 是一种应用广泛的数据结构,例如函数的调用就需要使用,其实我们在介绍《快速排序优化详解》的时候也使用到了结构。最鲜明的特点就是后进先出,一碟盘子就是类似这样的结构,最晚放上去的,可以最先拿出来。本文将介绍的是如何自己实现一个结构。 的操作 的常见操作有出(POP),从中弹出一个元素;入(PUSH),将一个元素压入中,访问顶元素(TOP),判断是否为空等。 的...

守望的博客-编程珠玑 8808

一个的入序列为ABCDEF,则不可能的出序列是

技术之瞳 阿里巴巴技术笔试心得习题2.65: 一个的入序列为ABCDEF,则不可能的出序列是(D)   A、DEFCBA       B、DCEFBA       C、FEDCBA   D、FECDBA       E、ABCDEF       F、ADCBFE 分析:   该题主要是考虑的核心思想是先进后出,并且需要注意入和出的顺序是未知的,例如你可以先入ABCD,然后出D,然后...

qq_38769551的博客 7458

洗碗工问题 一个例子

洗碗工 Python一个例子 前言 Python一个例子学习python的数据结构与算法时,在这一章节有一道洗碗工的问题,很有意思,有一定的难度,在csdn上找到的好几个代码中很多都考虑的不太全面,所以我将b站陈斌老师的作业讲解的代码稍加修改 代码如下: 一.先需要手写一个.py的的class: class Stack: def __init__(self): self.items = [] def isEmpty(self): r

liulisss的博客 1027

一个实现另一个的排序_用两个实现的排序

问题 把一个变成一个递增 例子 思路 方法1 辅助是递减 每次从中弹出数a,如果a<=辅助顶元素,直接把a放进辅助 否则,把辅助数中<=a的都弹出并放进,最后把a放进辅助 最后,辅助成了一个递减,依次弹出并放入,则就成了递增 代码 //方法1 public static void getSort(Stack<Integer>...

puspos的博客 714

】用一个来排序另一个

题目描述 一个中元素的类型为整型,现在想将该从顶到底按从大到小的顺序排序,只许申请一个。除此之外,可以申请新的变量,但不能申请额外的数据结构。如何完成排序? 输入描述: 第一行输入一个N,表示中元素的个数 第二行输入N个整数 aia_iai​ 表示顶到底的各个元素 输出描述: 输出一行表示排序后的顶到底的各个元素。 示例1 输入 5 5 8 4 3 6 输出 8 6 5 ...

在所不辞的博客 2229

一个实现另一个的排序

一个实现另一个的排序

『愚』的博客 1053

一个例子让你秒懂机器学习

近年来,机器学习和大数据领域的突破进展使人工智能急速回温,训练计算机模拟甚至实现人类的学习行为则是目前人工智能领域最受关注的研究课题之一。 很多人都难以想象,看似冷冰冰的机器如何能在短时间内学得一身本领的? 大数据、分析、物联网、云技术……最近的几年里,没有这些术语你就无法参与到关于科技的讨论和对话中。它们已经成了科技中主要的参与者,影响着商务的方方面面。 变化似

servicehot的博客 5363
上一篇: 由一个例子学习栈(续)
下一篇: 单向链表操作详解(一)
rerli
博客等级 码龄24年 20粉丝 7原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值