栈与递归

合集下载

递归的概念递归过程与递归工作栈递归与回溯广义表

递归的概念递归过程与递归工作栈递归与回溯广义表
else { Hanoi ( n-1, A, C, B ); cout << " move " << A << " to " << C << endl; Hanoi ( n-1, B, A, C );
} }
递归过程与递归工作栈
递归过程在实现时,需要自己调用自己。 层层向下递归,退出时的次序正好相反:
}
递归找含x值的结点
f
x

fff
问题的解法是递归的
例如,汉诺塔(Tower of Hanoi)问题的解法: 如果 n = 1,则将这一个盘子直接从 A 柱移到
C 柱上。否则,执行以下三步: ① 用 C 柱做过渡,将 A 柱上的 (n-1) 个盘子移 到 B 柱上: ② 将 A 柱上最后一个盘子直接移到 C 柱上; ③ 用 A 柱做过渡,将 B 柱上的 (n-1) 个盘子移 到 C 柱上。
递归调用
n! (n-1)! (n-2)!
1! 0!=1
返回次序
主程序第一次调用递归过程为外部调用;
递归过程每次递归调用自己为内部调用。
它们返回调用它的过程的地址不同。
递归工作栈
每一次递归调用时,需要为过程中使用的 参数、局部变量等另外分配存储空间。
每层递归调用需分配的空间形成递归工作 记录,按后进先出的栈组织。
while ( n >= 0 ) { cout << "value " << A[n] << endl;
n--;
} }
递归与回溯 常用于搜索过程
n皇后问题 在 n 行 n 列的国际象棋棋盘上,

必备算法:递归!无论你是前端开发,还是后端开发,都需要掌握它!

必备算法:递归!无论你是前端开发,还是后端开发,都需要掌握它!

必备算法:递归!⽆论你是前端开发,还是后端开发,都需要掌握它!递归是⼀种⾮常重要的算法思想,⽆论你是前端开发,还是后端开发,都需要掌握它。

在⽇常⼯作中,统计⽂件夹⼤⼩,解析xml⽂件等等,都需要⽤到递归算法。

它太基础太重要了,这也是为什么⾯试的时候,⾯试官经常让我们⼿写递归算法。

本⽂呢,将跟⼤家⼀起深⼊挖掘⼀下递归算法~什么是递归?递归,在计算机科学中是指⼀种通过重复将问题分解为同类的⼦问题⽽解决问题的⽅法。

简单来说,递归表现为函数调⽤函数本⾝。

在知乎看到⼀个⽐喻递归的例⼦,个⼈觉得⾮常形象,⼤家看⼀下:❝递归最恰当的⽐喻,就是查词典。

我们使⽤的词典,本⾝就是递归,为了解释⼀个词,需要使⽤更多的词。

当你查⼀个词,发现这个词的解释中某个词仍然不懂,于是你开始查这第⼆个词,可惜,第⼆个词⾥仍然有不懂的词,于是查第三个词,这样查下去,直到有⼀个词的解释是你完全能看懂的,那么递归⾛到了尽头,然后你开始后退,逐个明⽩之前查过的每⼀个词,最终,你明⽩了最开始那个词的意思。

❞来试试⽔,看⼀个递归的代码例⼦吧,如下:递归的特点实际上,递归有两个显著的特征,终⽌条件和⾃⾝调⽤:✿⾃⾝调⽤:原问题可以分解为⼦问题,⼦问题和原问题的求解⽅法是⼀致的,即都是调⽤⾃⾝的同⼀个函数。

✿终⽌条件:递归必须有⼀个终⽌的条件,即不能⽆限循环地调⽤本⾝。

结合以上demo代码例⼦,看下递归的特点:递归与栈的关系其实,递归的过程,可以理解为出⼊栈的过程的,这个⽐喻呢,只是为了⽅便读者朋友更好理解递归哈。

以上代码例⼦计算sum(n=3)的出⼊栈图如下:为了更容易理解⼀些,我们来看⼀下函数sum(n=5)的递归执⾏过程,如下:✿计算sum(5)时,先sum(5)⼊栈,然后原问题sum(5)拆分为⼦问题sum(4),再⼊栈,直到终⽌条件sum(n=1)=1,就开始出栈。

✿ sum(1)出栈后,sum(2)开始出栈,接着sum(3)。

✿最后呢,sum(1)就是后进先出,sum(5)是先进后出,因此递归过程可以理解为栈出⼊过程啦~递归的经典应⽤场景哪些问题我们可以考虑使⽤递归来解决呢?即递归的应⽤场景⼀般有哪些呢?✿阶乘问题✿⼆叉树深度✿汉诺塔问题✿斐波那契数列✿快速排序、归并排序(分治算法体现递归)✿遍历⽂件,解析xml⽂件递归解题思路解决递归问题⼀般就三步曲,分别是:✿第⼀步,定义函数功能✿第⼆步,寻找递归终⽌条件✿第⼆步,递推函数的等价关系式这个递归解题三板斧理解起来有点抽象,我们拿阶乘递归例⼦来喵喵吧~1、定义函数功能定义函数功能,就是说,你这个函数是⼲嘛的,做什么事情,换句话说,你要知道递归原问题是什么呀?⽐如你需要解决阶乘问题,定义的函数功能就是n的阶乘,如下:2、寻找递归终⽌条件递归的⼀个典型特征就是必须有⼀个终⽌的条件,即不能⽆限循环地调⽤本⾝。

递归栈溢出解决方法

递归栈溢出解决方法

递归栈溢出解决方法递归是一种常见的解决问题的方法,但是它也容易引起栈溢出的问题,特别是当递归调用层次深或者问题规模较大时。

栈溢出通常发生在递归函数中,因为每次递归调用会将相关的数据存储在调用栈中,当递归调用层次过深时,栈的内存空间可能会耗尽,导致栈溢出的错误。

下面是一些解决递归栈溢出问题的方法:1.优化递归算法:在解决问题时,优先考虑优化递归算法,尽量减少递归调用次数和递归深度。

可以尝试使用迭代或其他非递归的方法来解决问题。

2.增加栈空间:如果递归调用确实无法避免,可以通过增加栈的大小来增加递归调用的容量。

一些编程语言或者编译器提供了设置栈大小的选项,可以在程序运行时调整栈的大小。

3.尾递归优化:尾递归是指递归函数中递归调用是函数最后一步操作的情况。

一些编译器或解释器支持尾递归优化,在优化过程中会将递归调用转化为迭代,从而避免栈溢出的问题。

4.分而治之:将大问题分解为多个小问题,在每个小问题中进行递归调用。

这样可以减少递归深度,缩小每个递归调用的规模,从而减少栈溢出的可能性。

5.动态规划:有些问题可以使用动态规划的方法解决,它通过保存中间结果来避免重复计算,从而减少递归调用的次数。

6.使用循环代替递归:在一些情况下,可以使用循环代替递归来解决问题。

循环通常比递归更高效,因为它不会占用大量的栈空间。

7.减少内存使用:除了减少递归调用的次数和递归深度外,还可以考虑减少每个递归调用所占用的内存空间。

可以通过优化数据结构的使用和算法的实现来减少内存使用。

总结起来,解决递归栈溢出问题的方法可以分为两类:一是通过优化递归算法和减少递归调用次数来避免栈溢出,二是通过增加栈空间、尾递归优化、分而治之、动态规划、使用循环代替递归和减少内存使用等方法来解决栈溢出的问题。

具体选择哪种方法取决于具体情况和问题的特点。

在实际应用中,我们可以综合考虑这些方法,根据具体情况选择适合的解决方案。

栈在递归中的作用

栈在递归中的作用

栈在递归中的作用栈是一种具有特殊性质的线性数据结构,在其中元素的插入和删除操作只能在栈的顶部进行。

栈的特点是元素按照后进先出的顺序进行处理,即最后插入到栈中的元素最先被访问到。

递归是一种程序设计技巧,通过一个函数在其定义中调用自身来解决问题。

递归函数在解决问题时以一种分而治之的办法,将原始问题划分为较小的子问题,并通过解决子问题来解决原始问题。

那么,栈在递归中起到了什么作用呢?一、存储临时变量:递归函数在每一次调用自身时都会入栈,该栈用来保存每个递归调用时的临时变量。

在递归函数内部定义的变量会保存在栈中,每次函数调用时,这些局部变量都会被压入栈中。

当函数的递归调用完成后,栈中保存的该函数的局部变量会被弹出,以便为下一个递归调用或其他操作提供内存空间。

这样,栈起到了一个保存临时变量的作用。

二、存储函数调用的返回地址:在递归调用时,每次调用后都需要返回到上一层调用处。

栈的另一个作用是存储函数调用的返回地址。

当一个函数调用了自身,并进行了递归调用时,当前函数的上下文信息(包括函数指针、参数和局部变量等)都会被保存在栈中,然后在递归调用完成后,栈中保存的上下文信息将被弹出,返回到上一层函数的下一条执行指令的位置,继续执行下去。

三、维护递归层次关系:递归调用时,每次调用自身都需要将当前的状态保存在栈中,这样可以保留每一次递归调用的上下文信息。

栈的深度也反映了递归的层次关系。

当递归调用层数很大时,栈的深度也会相应增加。

四、确保函数调用的正确性:栈在递归中还发挥了确保函数调用的正确性的作用。

每一次递归调用都会将当前的状态保存在栈中,包括参数、局部变量、返回地址等信息。

这样,即使在递归调用过程中发生了其他函数的调用,当递归调用完成后,栈中保存的状态信息都能够正确恢复,确保程序的正确执行。

总结来说,栈在递归中起到了存储临时变量、存储函数调用的返回地址、维护递归层次关系以及确保函数调用的正确性等作用。

栈的使用使递归函数能够按照正确的顺序进行递归调用,并在递归调用完成后正确返回上一层函数的下一条执行指令的位置。

国家开放大学《数据结构》课程实验报告(实验3 ——栈、队列、递归设计)参考答案

国家开放大学《数据结构》课程实验报告(实验3 ——栈、队列、递归设计)参考答案
{
x=Pop(s); /*出栈*/
printf("%d ",x);
InQueue(sq,x); /*入队*/
}
printf("\n");
printf("(10)栈为%s,",(StackEmpty(s)?"空":"非空"));
printf("队列为%s\n",(QueueEmpty(sq)?"空":"非空"));
ElemType Pop(SeqStack *s); /*出栈*/
ElemType GetTop(SeqStack *s); /*取栈顶元素*/
void DispStack(SeqStack *s); /*依次输出从栈顶到栈底的元素*/
void DispBottom(SeqStack *s); /*输出栈底元素*/
} SeqQueue; /*定义顺序队列*/
void InitStack(SeqStack *s); /*初始化栈*/
int StackEmpty(SeqStack *s); /*判栈空*/
int StackFull(SeqStack *s); /*判栈满*/
void Push(SeqStack *s,ElemType x); /*进栈*/
sq=(SeqQueue *)malloc(sizeof(SeqQueue));
InitQueue(sq);
printf("(8)队列为%s\n",(QueueEmpty(sq)?"空":"非空"));
printf("(9)出栈/入队的元素依次为:");

递归树形结构的替代方案

递归树形结构的替代方案

递归树形结构的替代方案
1. 迭代算法,在某些情况下,可以使用迭代算法来替代递归。

迭代算法通常更高效,因为它们不会涉及到递归函数调用的开销。

例如,可以使用循环来遍历树结构,而不是使用递归。

2. 栈或队列,在处理树形结构时,可以使用栈或队列来代替递归。

这种方法通常被称为"迭代深度优先搜索"或"迭代广度优先搜索"。

通过维护一个栈或队列来跟踪待处理的节点,可以避免递归调用。

3. 并查集,在一些特定的场景下,可以使用并查集来代替递归
树形结构。

并查集是一种数据结构,用于维护元素之间的等价关系,通常用于解决连通性和等价性的问题。

4. 线索化二叉树,对于二叉树结构,可以使用线索化技术来代
替递归。

线索化二叉树是一种对普通二叉树进行改造,使得可以在
不使用递归的情况下进行中序遍历。

5. 哈希表或索引结构,在某些情况下,可以使用哈希表或其他
索引结构来代替递归树形结构。

这种方法通常适用于需要快速查找
和检索节点的场景。

总之,替代递归树形结构的方案取决于具体的问题和需求,需要根据实际情况进行选择。

在一些情况下,递归可能是最简洁和直观的解决方案,但在性能要求较高或者存在栈溢出风险的情况下,可以考虑使用上述的替代方案。

栈的出队顺序

栈的出队顺序

栈的出队顺序一、栈的出队顺序——先进后出的数据结构二、栈的基本操作——入栈和出栈栈的基本操作包括入栈和出栈。

入栈是指将元素添加到栈的顶部,出栈是指将栈顶的元素移除。

入栈和出栈是栈的两个基本操作,它们是栈的核心功能。

通过这两个操作,我们可以实现对栈中元素的添加和删除。

三、栈的应用——逆波兰表达式求值逆波兰表达式是一种不需要括号来标识优先级的数学表达式表示方法。

在逆波兰表达式中,操作符位于操作数的后面,这样可以避免使用括号来改变运算的顺序。

逆波兰表达式求值是栈的一个典型应用场景。

通过使用栈来保存操作数,我们可以按照逆波兰表达式的顺序依次计算出结果。

四、栈的应用——括号匹配括号匹配是栈的另一个重要应用场景。

在编程中,经常需要对括号进行匹配判断,以确保代码的正确性。

使用栈可以方便地实现对括号的匹配判断。

当遇到左括号时,将其入栈;当遇到右括号时,与栈顶元素进行匹配判断。

如果匹配成功,则将栈顶元素出栈;如果匹配失败,则表明括号不匹配。

五、栈的应用——浏览器的前进和后退功能浏览器的前进和后退功能是栈的又一个典型应用。

当我们在浏览器中点击前进按钮时,当前页面的URL将被压入栈中;当我们点击后退按钮时,栈顶元素将被弹出并打开对应的页面。

通过使用栈来保存浏览历史记录,我们可以方便地实现浏览器的前进和后退功能。

六、栈的应用——实现递归递归是一种常见的编程技巧,它可以简化代码的实现。

在递归过程中,每一次递归调用都会创建一个新的栈帧,用于保存函数的局部变量和返回地址。

通过使用栈来保存每个栈帧,我们可以实现递归的执行。

七、栈的应用——系统调用和中断处理在操作系统中,系统调用和中断处理是栈的重要应用场景。

当发生系统调用或中断时,当前的程序状态将被保存到栈中,包括程序计数器、寄存器的值和局部变量等。

通过使用栈来保存这些信息,操作系统可以在中断处理或系统调用结束后恢复程序的执行。

八、栈的应用——迷宫求解迷宫求解是一个经典的问题,可以通过使用栈来解决。

数据结构实验报告2栈、队列、递归程序设计

数据结构实验报告2栈、队列、递归程序设计
计算机科学与技术(本科)《数据结构》实验报告
日期:学号:姓名:
实验名称:实验报告二栈、队列、递归程序设计
实验目的与要求:
2.1栈和队列的基本操作
(1)正确理解栈的先进后出的操作特点,建立初始栈,通过相关操作显示栈底元素。
(2)程序中要体现出建栈过程和取出栈底元素后恢复栈的入栈过程,按堆栈的操作规则打印结果栈中的元素
{
return(s->top==-1);
}
//---出栈函数
int Pop(SeqStack *&s,ElemType &e)
{
if (s->top==-1)
return 0;
e=s->data[s->top];
s->top--;
return 1;
}
//---初始队列函数
void InitQueue(SqQueue *&q)
q->rear=(q->rear+1)%MaxSize;
q->elem[q->rear]=e;
return 1;
}
//---出队列函数
int OutQueue(SqQueue *&q,ElemType &e)
{
if (q->front==q->rear) //队空
return 0;
q->front=(q->front+1)%MaxSize;
printf("(10)栈为%s,",(StackEmpty(s)?"空":"非空"));
printf("队列为%s\n",(QueueEmpty(q)?"空":"非空"));

栈的应用及特性

栈的应用及特性

栈的应用及特性栈是计算机科学中一种非常重要的数据结构,具有广泛的应用和独特的特性。

下面将详细介绍栈的应用及特性。

一、栈的应用:1. 函数调用:在程序执行过程中,函数的调用和返回通常采用栈进行管理。

当一个函数被调用时,函数的参数和局部变量被压入栈中,函数执行完毕后,这些信息会被弹出栈恢复到调用函数的状态。

2. 表达式求值:在编程语言中,栈可用于表达式求值、中缀表达式转换为后缀表达式等相关操作。

通过利用栈的先进后出特性,可以方便地实现这些功能。

3. 递归算法:递归算法中的递归调用也可以通过栈来实现。

当算法需要递归调用时,将函数和相关变量的信息压入栈中,等到递归结束后,再从栈中弹出恢复状态。

4. 括号匹配:栈也常用于判断表达式中的括号是否匹配。

遍历表达式,遇到左括号时压入栈,遇到右括号时弹出栈顶元素,如果匹配则继续,不匹配则判定为括号不匹配。

5. 浏览器的前进后退:浏览器的前进后退功能可以使用栈实现。

每次浏览一个网页时,将该网页的URL压入栈中,点击后退按钮时,再从栈中弹出上一个URL,即可实现返回上一个网页的功能。

6. 撤销操作:在图形界面软件中,通常会有撤销操作。

使用栈可以将每一步操作的状态依次压入栈中,当用户需要撤销时,再从栈中弹出最近的状态,恢复到之前的操作状态。

二、栈的特性:1. 先进后出:栈是一种后进先出(LIFO)的数据结构,即最新添加的元素最先被访问或者删除。

这一特性使得栈能够方便地实现函数调用和返回等操作。

2. 只能操作栈顶元素:由于栈的特性,只能访问或者修改栈顶元素,无法直接访问或者修改栈中的其他元素。

需要先将栈顶元素弹出后,才能访问或者修改下一个栈顶元素。

3. 顺序存储结构:栈可以使用数组或者链表实现。

使用数组实现时,需要指定栈的最大容量,而使用链表实现时,没有容量限制。

4. 操作复杂度:栈的插入和删除操作只涉及栈顶元素,所以其操作复杂度为O(1)。

但是栈的搜索和访问操作需要从栈顶开始遍历,所以其操作复杂度为O(n)。

栈的运用实验报告

栈的运用实验报告

一、实验目的1. 理解栈的基本概念、特点及逻辑结构;2. 掌握栈的顺序存储和链式存储结构;3. 熟练掌握栈的基本操作,如入栈、出栈、判断栈空等;4. 理解栈在递归算法中的应用;5. 探究栈在实际问题中的应用。

二、实验内容1. 栈的定义与特点2. 栈的顺序存储结构3. 栈的链式存储结构4. 栈的基本操作5. 栈在递归算法中的应用6. 栈在实际问题中的应用三、实验步骤1. 栈的定义与特点(1)栈是一种后进先出(LIFO)的数据结构;(2)栈的元素只能从一端(栈顶)进行插入和删除操作;(3)栈具有两个基本操作:入栈和出栈。

2. 栈的顺序存储结构(1)使用数组来实现栈的顺序存储结构;(2)定义一个数组作为栈的存储空间;(3)定义栈顶指针top,初始值为-1;(4)定义栈的最大容量maxSize。

3. 栈的链式存储结构(1)使用链表来实现栈的链式存储结构;(2)定义一个链表节点,包含数据域和指针域;(3)定义栈顶指针top,初始时指向链表头节点。

4. 栈的基本操作(1)入栈操作:将元素插入到栈顶,栈顶指针向上移动;(2)出栈操作:删除栈顶元素,栈顶指针向下移动;(3)判断栈空:判断栈顶指针是否为-1,是则栈空,否则栈非空。

5. 栈在递归算法中的应用(1)斐波那契数列的递归算法;(2)汉诺塔问题;(3)迷宫问题。

6. 栈在实际问题中的应用(1)括号匹配问题;(2)表达式求值问题;(3)递归函数的调用栈。

四、实验结果与分析1. 栈的定义与特点通过本次实验,我们深入理解了栈的基本概念、特点及逻辑结构,掌握了栈的后进先出特性。

2. 栈的顺序存储结构使用数组实现栈的顺序存储结构,操作简单高效。

在实验过程中,我们实现了栈的基本操作,如入栈、出栈、判断栈空等。

3. 栈的链式存储结构使用链表实现栈的链式存储结构,具有灵活性和扩展性。

在实验过程中,我们实现了栈的基本操作,如入栈、出栈、判断栈空等。

4. 栈的基本操作通过实验,我们熟练掌握了栈的基本操作,如入栈、出栈、判断栈空等,为后续递归算法和实际问题中的应用奠定了基础。

链表逆序的三种方法

链表逆序的三种方法

链表逆序的三种方法链表是一种常用的数据结构,由一个个节点通过指针连接而成。

在实际编程中,经常需要对链表进行逆序操作,以满足特定需求。

本文将介绍链表逆序的三种常用方法,分别是迭代法、递归法以及使用栈的方法。

迭代法:迭代法是一种比较直观的逆序方法,通过调整节点之间的指针指向来实现。

具体步骤如下:1. 定义三个指针,分别为当前节点(cur)、前一个节点(prev)和下一个节点(next)。

2. 将当前节点的下一个节点保存到next指针中,以免链表断开。

3. 将当前节点的next指针指向前一个节点,完成逆序操作。

4. 将当前节点赋值给prev指针,以备下一次迭代使用。

5. 将next指针赋值给cur指针,继续下一次迭代。

若next指针为空,则说明已到达链表尾部,逆序完成。

递归法:递归法是一种更为简洁的逆序方法,通过递归调用实现链表逆序。

具体步骤如下:1. 首先判断链表是否为空或只有一个节点,若是则无需逆序,直接返回。

2. 若链表有多个节点,则递归调用逆序函数对除第一个节点外的子链表进行逆序。

3. 将头节点(首节点)的指针指向调用逆序函数后的新链表的尾节点。

4. 将尾节点的指针指向头节点,使得整个链表逆序完成。

使用栈的方法:栈是一种后进先出(LIFO)的数据结构,可以利用栈的特性进行链表逆序操作。

具体步骤如下:1. 遍历链表,将链表中的节点依次压入栈中。

2. 弹出栈中的节点,按照出栈顺序重新构建链表。

弹出的第一个节点是原链表的尾节点,成为逆序链表的头节点。

3. 将每个弹出的节点的next指针指向下一个被弹出的节点,完成逆序操作。

4. 最后一个被弹出的节点成为逆序链表的尾节点,将其next指针置为空,表示逆序链表的尾部。

以上是三种常见的链表逆序方法。

在实际应用中,可以根据具体情况选择合适的方法来实现链表逆序。

迭代法适合逆序链表并保持链表结构的情况;递归法适用于逆序链表不要求保持原结构的情况;使用栈的方法适用于逆序链表并重新构建链表结构的情况。

三种括号识别算法

三种括号识别算法

三种括号识别算法括号识别算法是文本处理和编程中常用的一种算法,用于识别和处理括号的匹配关系。

在此,我将介绍三种常见的括号识别算法:栈算法、递归算法和有限自动机算法。

1.栈算法:栈算法是最常用的括号识别算法之一、该算法使用一个栈数据结构来存储左括号,并通过栈的特性来判断右括号是否与栈顶的左括号匹配。

算法步骤:-创建一个空栈,用于存储左括号。

-从左到右遍历文本中的每个字符。

-如果遇到左括号(如'{'、'['、'('),则将其入栈。

-如果遇到右括号(如'}'、']'、')'),则判断栈是否为空。

若为空,则该右括号无匹配的左括号,识别失败。

若非空,则取出栈顶的左括号,并判断右括号与栈顶左括号是否匹配。

若匹配,则继续遍历下一个字符;若不匹配,则识别失败。

-遍历结束后,若栈为空,则识别成功;若栈非空,则有左括号没有匹配的右括号,识别失败。

栈算法的时间复杂度为O(n),其中n为文本的长度。

2.递归算法:递归算法是另一种常见的括号识别算法。

该算法使用递归的方式来判断括号的匹配关系。

算法步骤:-从左到右遍历文本中的每个字符。

-如果遇到左括号(如'{'、'['、'('),则寻找与之匹配的右括号。

具体做法是,在遇到右括号之前,统计遇到的左括号的数量,直到左括号数量与右括号数量相等,并且右括号与最后一个遇到的左括号匹配。

若找到匹配的右括号,则继续遍历下一个字符;若不匹配,则识别失败。

-遍历结束后,如果找到了与每个左括号匹配的右括号,则识别成功;否则,识别失败。

递归算法的时间复杂度和栈算法类似,也是O(n)。

3.有限自动机算法:有限自动机算法是一种使用状态机的方式来识别括号的算法。

该算法使用有限状态机的转移来处理括号的匹配关系。

算法步骤:-定义括号匹配的有限状态机,包括起始状态、接受状态和转移规则。

栈与递归的关系

栈与递归的关系

栈与递归的关系姓名:郭小兵学号:1007010210专业:信息与计算科学院系:理学院指导老师:彭长根2012年10月17日栈与递归的关系郭小兵摘要递归是计算机科学中一个极为重要的概念,许多计算机高级语言都具有递归的功能,对于初学计算机者来讲,递归是一个简单易懂的概念,但真正深刻理解递归,正确自如的运用递归编写程序却非易事,本文通过一些实例来阐述递归在计算机内的实现及递归到非递归的转换,也许使读者能加深对递归的理解。

关键词栈递归非递归引言递归是一种程序设计的方式和思想。

计算机在执行递归程序时,是通过栈的调用来实现的。

栈,从抽象层面上看,是一种线性的数据结构,这中结构的特点是“先进后出”,即假设有a,b,c三个元素,依次放某个栈式存储空间中,要从该空间中拿到这些元素,那么只能以c、b、a的顺序得到。

递归程序是将复杂问题分解为一系列简单的问题,从要解的问题起,逐步分解,并将每步分解得到的问题放入“栈”中,这样栈顶是最后分解得到的最简单的问题,解决了这个问题后,次简单的问题可以得到答案,以此类推。

分解问题是进栈(或者说压栈)的过程,解决问题是一个出栈的过程。

科学家对栈与递归都做了很多深入的研究,研究表明“递归算法和栈都有后进先出这个性质,基本上能用递归完成的算法都可以用栈完成,都是运用后进先出这个性质的”这个性质可用于进制的转换。

与汇编程序设计中主程序和子程序之间的链接及信息交换相类似,在高级语言编制的程序中,调用函数和被调用函数之间的链接及信息交换需过栈来进行。

递归是计算科学中一个极为重要的概念。

许多计算机高级语言都具有递归的功能,本文将通过一些是例来阐述递归在计算机内的实现及递归到非递归的转换,也许能加深对递归的理解。

递归是某一事物直接或间接地由自己完成。

一个函数直接或间接地调用本身,便构成了函数的递归调用,前者称之为直接递归调用,后者为间接递归调用。

递归会使某些看起来不容易解决的问题变得容易解决。

第3章 限定性线性表——栈和队列

第3章  限定性线性表——栈和队列

两栈共享技术(双端栈):
主要利用了栈“栈底位置不变,而栈顶位置动态变
化”的特性。首先为两个栈申请一个共享的一维数 组空间S[M],将两个栈的栈底分别放在一维数组的 两端,分别是0,M-1。
共享栈的空间示意为:top[0]和top[1]分别为两个 栈顶指示器 。
Stack:0
M-1
top[0]
top[1]
(1)第i号栈的进栈操作 int pushi(LinkStack top[M], int i, StackElementType x) { /*将元素x进入第i号链栈*/
LinkStackNode *temp; temp=(LinkStackNode * )malloc(sizeof(LinkStackNode)); if(temp==NULL) return(FALSE); /* 申请空间失败 */ temp->data=x; temp->next=top[i]->next; top[i]->next=temp; /* 修改当前栈顶指针 */ return(TRUE); }
case 1:if(S->top[1]==M) return(FALSE);
*x=S->Stack[S->top[1]];S->top[1]++;break;
default: return(FALSE);
}
return(TRUE);
返回主目录
}
【思考题】
说明读栈顶与退栈顶的处理异同,并标明将已知 的退栈顶算法改为读栈顶算法时应做哪些改动。
返回主目录
链栈的进栈操作
int Push(LinkStack top, StackElementType x)

栈的两个典型应用

栈的两个典型应用

栈的两个典型应⽤最开始先来介绍⼀下栈的定义:栈(stack)是限定仅在表尾进⾏插⼊和删除操作的线性表。

允许插⼊和删除的⼀端称为栈顶(top),另⼀端称为栈底(bottom),不含任何数据元素的栈称为空栈。

栈⼜称为后进先出(Last in First out)的线性表,简称LIFO结构。

栈的插⼊操作叫做进栈(push),类似⼦弹⼊弹夹;删除操作叫做出栈(pop),类似⼦弹出弹夹。

和⼤多数数据结构⼀样,栈也分成顺序存储结构和链式存储结构。

栈的典型应⽤⼀:递归所谓递归即是指直接调⽤⾃⼰或者通过⼀系列操作间接调⽤⾃⼰。

对于递归函数,最重要的是要有合适的退出条件,否则可能就会陷⼊永不结束的⽆穷递归中,那么程序就飞啦~递归能让程序结构更加清晰和简介,可读性更⾼,但是⼤量的递归调⽤会占⽤⼤量的运⾏时间和内存,使⽤过程中要合理利⽤递归。

说了这么多,那么递归和栈⼜有什么联系呢?递归过程在不断的调⽤⾃⾝函数之后,当到达退出条件后会,会按照它前⾏顺序的逆序执⾏退回。

在前⾏阶段,对于每⼀层递归,函数的局部变量、参数值和返回地址被压⼊栈中。

在退回阶段,位于栈顶的局部变量、参数值和返回地址被弹出,⽤于返回调⽤层次中执⾏代码的其余部分。

这些需求很符合栈的数据结构,所以现在的编译器⼤多通过栈来实现递归操作。

栈的典型应⽤⼆:四则运算表达式求值使⽤C语⾔来实现对同时存在括号和四则运算符的表达式求值⼀直是个难题,直到逻辑学家们借助栈和后缀表达法才解决这⼀难题。

后缀表达法(⼜名逆波兰表达式),叫后缀的原因是所有的符号都要在运算符号的后⾯出现。

那么由我们常⽤的数学表达式(中缀表达式)转换为后缀表达式的规则是什么?从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的⼀部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,⼀直到最终输出后缀表达式为⽌。

c语言中如何返回之前的步骤

c语言中如何返回之前的步骤

c语言中如何返回之前的步骤在C语言中,要返回之前的步骤,可以使用函数的递归调用或者栈的数据结构来实现。

下面分别介绍这两种方法。

一、递归调用递归调用是一种函数调用自身的方式。

通过递归调用,可以实现函数返回之前的步骤。

1.递归调用的基本原理递归调用的基本原理是在函数内部调用自身,通过在每一次递归调用中传递不同的参数,让函数按照不同的路径执行,最终返回之前的步骤。

2.递归调用的步骤(1)定义递归函数:在函数内部定义一个递归函数,用于实现递归调用。

(2)设置递归终止条件:在递归函数的开头设置一个递归终止条件,当满足此条件时,不再进行递归调用,直接返回。

(3)设置递归调用:在递归函数内部,根据条件判断是否进行递归调用,若进行递归调用,则传入不同的参数。

(4)返回值:在递归函数中,根据需要返回相应的值。

3.递归调用的示例下面以计算阶乘的函数为例,介绍递归调用的实现过程。

```c#include <stdio.h>int factorial(int n)if(n == 0)return 1; // 终止条件elsereturn n * factorial(n-1); // 递归调用int mainint num;printf("请输入一个非负整数:");scanf("%d", &num);printf("%d的阶乘为%d\n", num, factorial(num));return 0;```以上代码中,factorial函数是一个递归函数,根据n的不同值,通过递归调用来实现计算阶乘的功能。

当n为0时,满足递归终止条件,函数直接返回1;否则,函数通过递归调用返回n * factorial(n-1)的结果。

二、栈的数据结构栈是一种后进先出(LIFO)的数据结构,可以通过栈来实现返回之前的步骤。

1.栈的基本操作(1)入栈(push):将元素压入栈顶。

二叉树的先序,中序,后序遍历的递归工作栈的关系

二叉树的先序,中序,后序遍历的递归工作栈的关系

二叉树的先序,中序,后序遍历的递归工作栈的关系在计算机科学中,二叉树是一种非常重要的数据结构,它在很多算法和数据处理中都有着广泛的应用。

而二叉树的先序、中序、后序遍历以及它们与递归和工作栈的关系更是程序员面试中常见的问题。

本文将从深度和广度两个方面,按照先序、中序、后序的顺序逐步展开对这个主题的探讨。

一、先序遍历先序遍历是指先访问根节点,然后递归地先序遍历左子树,最后递归地先序遍历右子树。

在实际的计算机算法中,我们可以使用递归或者栈来实现先序遍历。

1.1 递归实现当我们使用递归来实现先序遍历时,可以很容易地写出下面这段代码:```pythondef preorderTraversal(root):if not root:return []return [root.val] + preorderTraversal(root.left) + preorderTraversal(root.right)```这段代码非常简洁明了,但是在实际执行时,会使用工作栈来保存递归中间结果。

因为递归本质上就是一个栈结构,在调用递归函数时,会将当前函数的局部变量和参数压入栈中,直到递归结束,栈中的内容才会依次出栈执行。

1.2 栈实现除了递归之外,我们也可以使用显式栈来实现先序遍历。

这种方法通常会更加高效一些,因为递归会有一定的性能损耗。

栈的实现思路是,我们首先将根节点压入栈中,然后弹出栈顶节点并访问它,接着先将右子节点压入栈中,再将左子节点压入栈中。

重复上述操作直到栈为空。

这样就可以保证先访问根节点,再访问左子树,最后访问右子树,符合先序遍历的要求。

二、中序遍历中序遍历是指先递归地中序遍历左子树,然后访问根节点,最后递归地中序遍历右子树。

中序遍历同样可以用递归或者显式栈来实现。

2.1 递归实现递归实现中序遍历同样非常简单:```pythondef inorderTraversal(root):if not root:return []return inorderTraversal(root.left) + [root.val] + inorderTraversal(root.right)```在这个递归函数中,同样使用了递归的工作栈来保存中间结果。

栈的概念与特点

栈的概念与特点

栈的概念与特点栈是一种数据结构,它可以用来存储数据和实现一些特定的操作。

栈的概念和特点可以通过以下几个方面来阐述。

首先,栈是一种线性数据结构,其特点是数据元素按照线性顺序排列,且只能在一端进行操作。

这一端通常称为栈顶,另一端称为栈底。

栈的结构类似于我们平常使用的一对叠盘子,只能从上面取盘子或者放盘子。

其次,栈的特点是“后进先出”,即最后一个入栈的元素最先出栈,而最先入栈的元素最后出栈。

这与我们日常生活中的一些场景相符,比如堆积东西或书籍时,我们通常会先放上面的物品,而需要使用时则先取出上面的物品。

这种特点在计算机科学中应用广泛,有助于解决一些问题。

再次,栈只能在一端进行操作,即在栈的顶部进行插入元素、删除元素或者查看栈顶元素等操作。

这种特点决定了在栈中只有栈顶元素可见,其他元素是不可见的。

这也是栈的一个重要特性,它限制了对栈内数据的访问方式,在某些情况下能够提高程序的效率。

此外,栈还具有一种重要的性质,即拥有“局部性原理”。

局部性原理指的是在程序执行过程中,往往会存在一些临时的变量或者子程序的调用,这些变量或者子程序的执行过程通常是连续的,也就是说它们的连续执行是非常频繁的。

而栈的特点正好满足了这一需求,可以将这些临时变量或者子程序的返回地址存储在栈中,以实现快速的跳转和恢复。

另外,栈还具有动态分配内存空间的能力。

在使用栈时,一般会预先确定栈的最大容量,但实际使用时可能需要动态地分配栈的空间。

这是因为在程序执行过程中,数据的个数或者大小是不确定的,可能会有增加或者减少的情况。

而栈可以通过动态地改变栈顶指针的位置来实现空间的动态分配和释放。

此外,栈还可以通过递归来实现一些复杂的问题。

递归是一种函数调用自身的方法,它可以通过栈的特点实现函数的嵌套调用和返回。

递归在解决一些具有递归结构的问题时非常有用,并且可以通过栈的特性来实现递归的过程管理和结果返回。

除了以上几个方面,栈还有一些其他的应用场景,比如括号匹配、表达式求值、函数调用和返回等。

递归调用详解,分析递归调用的详细过程

递归调用详解,分析递归调用的详细过程

递归调⽤详解,分析递归调⽤的详细过程⼀、栈在说函数递归的时候,顺便说⼀下栈的概念。

栈是⼀个后进先出的压⼊(push)和弹出(pop)式。

在程序运⾏时,系统每次向栈中压⼊⼀个对象,然后栈指针向下移动⼀个位置。

当系统从栈中弹出⼀个对象时,最近进栈的对象将被弹出。

然后栈指针向上移动⼀个位置。

程序员经常利⽤栈这种数据结构来处理那些最适合⽤后进先出逻辑来描述的编程问题。

这⾥讨论的程序中的栈在每个程序中都是存在的,它不需要程序员编写代码去维护,⽽是由运⾏是系统⾃动处理。

所谓的系统⾃动维护,实际上就是编译器所产⽣的程序代码。

尽管在源代码中看不到它们,但程序员应该对此有所了解。

再来看看程序中的栈是如何⼯作的。

当⼀个函数(调⽤者)调⽤另⼀个函数(被调⽤者)时,运⾏时系统将把调⽤者的所有实参和返回地址压⼊到栈中,栈指针将移到合适的位置来容纳这些数据。

最后进栈的是调⽤者的返回地址。

当被调⽤者开始执⾏时,系统把被调⽤者的⾃变量压⼊到栈中,并把栈指针再向下移,以保证有⾜够的空间存储被调⽤者声明的所有⾃变量。

当调⽤者把实参压⼊栈后,被调⽤者就在栈中以⾃变量的形式建⽴了形参。

被调⽤者内部的其他⾃变量也是存放在栈中的。

由于这些进栈操作,栈指针已经移动所有这些局部变量之下。

但是被调⽤者记录了它刚开始执⾏时的初始栈指针,以他为参考,⽤正或负的偏移值来访问栈中的变量。

当被调⽤者准备返回时,系统弹出栈中所有的⾃变量,这时栈指针移动了被调⽤者刚开始执⾏时的位置。

接着被调⽤者返回,系统从栈中弹出返回地址,调⽤者就可以继续执⾏了。

当调⽤者继续执⾏时,系统还将从栈中弹出调⽤者的实参,于是栈指针回到了调⽤发⽣前的位置。

可能刚开始学的⼈看不太懂上⾯的讲解,栈涉及到指针问题,具体可以看看⼀些数据结构的书。

要想学好编程语⾔,数据结构是⼀定要学的。

⼆、递归递归,是函数实现的⼀个很重要的环节,很多程序中都或多或少的使⽤了递归函数。

递归的意思就是函数⾃⼰调⽤⾃⼰本⾝,或者在⾃⼰函数调⽤的下级函数中调⽤⾃⼰。

递归算法要素

递归算法要素

递归算法要素一、递归算法要素递归算法呀,就像是一个神奇的魔法。

(一)基本概念递归算法简单说呢,就是一个函数自己调用自己。

这就好像是一个镜子里有镜子,无限嵌套一样。

比如说计算阶乘,n的阶乘就是n乘以(n - 1)的阶乘,一直到1的阶乘是1。

这就是一种典型的递归思想,它把一个大问题分解成小问题,小问题又继续分解,直到分解到可以直接得出结果的最小单元。

就像搭积木一样,我们先从最小的一块开始,然后一块一块搭上去,最后搭成一个大的结构。

(二)递归的终止条件这可是非常非常重要的一点哦。

要是没有终止条件,这个递归就会像一个疯狂旋转的陀螺,停不下来啦。

比如说还是阶乘那个例子,1的阶乘就是1,这就是一个终止条件。

当我们计算到1的时候,就不能再继续分解下去了,要返回这个结果。

如果没有这个终止条件,程序就会一直计算下去,最后可能就会把电脑搞崩溃啦。

这就好比是跑步比赛,到了终点就得停下来,不能一直跑下去。

(三)递归的参数传递在递归的过程中呢,参数是很关键的。

参数会随着每次递归调用而发生变化。

就像是接力赛,每一棒选手接到的任务可能有点不一样。

比如说计算斐波那契数列,斐波那契数列的第n项是第(n -1)项和第(n - 2)项的和。

在这个递归过程中,每次传递的参数n都在不断变小,直到达到终止条件。

而且这个参数的变化要符合我们解决问题的逻辑,不然就会算出错误的结果。

(四)递归的调用栈递归调用的时候会形成一个调用栈。

这个调用栈就像是一个记录员,记录着每次函数调用的状态。

每一次函数调用都会在这个栈上占用一定的空间。

如果递归的层次太深,这个栈可能就会被填满,这就是所谓的栈溢出。

就像一个小盒子,只能装一定数量的东西,装多了就会溢出来。

所以我们在写递归算法的时候,要考虑到这个调用栈的深度,尽量避免栈溢出的情况。

这就需要我们合理地设计递归算法,不要让它无限制地递归下去。

(五)递归算法的效率递归算法虽然很简洁很优雅,但是它的效率有时候可能不是很高。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

目录摘要 (1)研究背景 (2)基本概念及特性.......................................................... (2)栈的运算 (3)栈的运用举例 (5)递归原理 (6)迷宫求解 (8)栈实现迷宫问题 (8)递归实现迷宫算法 (8)参考文献 (9)附录 (9)栈与递归的关系摘要:栈(stack)又称堆栈,他是线性表中的一种特殊情况,并且也是最简单的情况之一,它是一种运算受限的线性表,其限制是仅仅允许在表的一端进行插入和删除运算。

由于栈的插入和删除运算仅在栈的一端实现,后进栈的元素必定先出栈,所以又把栈称为后进先出表。

递归是一种非常重要的概念和解决问题的方法,在计算机科学和数学领域有着广泛的应用,递归调用是计算机解决部分疑难问题特别有效,易于实现的一种算法。

比如著名的汉诺塔问题、八皇后问题、树的遍历等如果不用递归算法解决,几乎难以实现,大部分计算机语言教材都涉及到这一重要算法。

在计算机系统内,执行递归函数是通过栈来实现的,栈中的每一个元素包含有递归函数的每一参数域、每一个局部变量和调用后的返回地址域,其中引用参数域只保存传送来的实参的地址,以便按此地址访问实参的储存空间存取其值,其他的每个域是用于存储其值的实际存储空间,每次进行函数调用的时候,都要把相应的填压入栈,每次结束调用时,都按照本次返回地址返回到指定的位置进行,并且自动做一次退栈操作,使得下一层所使用的参数称为新的栈顶,继续被使用。

栈与递归都能够解决一些实际问题,主要是通过C/C++语言来实现编程运算,得到相应的结果。

递归和栈是可以相互转换的,当编写递归算法时,虽然表面上没有使用栈,但是系统执行时会自动建立和使用栈,本文中在求解迷宫问题时就充分的体现出了这一点。

关键词:栈递归C/C++语言迷宫问题一、研究背景递归调用是计算机解决部分疑难问题特别有效,易于实现的一种算法。

比如著名的汉诺塔问题、八皇后问题、树的遍历等如果不用递归算法解决,几乎难以实现,大部分计算机语言教材都涉及到这一重要算法,计算机执行递归算法时,是通过栈来实现的。

具体说来,就是在(递归过程或递归函数)开始运行时,系统首先为递归建立一个栈,该栈的元素类型(数据域)包括值参、局部变量和返回地址;在每次执行递归调用语句时之前,自动把本算法中所使用的值参和局部变量的当前值以及调用后的返回地址压栈(一般形象地称为“保存现场”,以便需要时“恢复现场”返回到某一状态),在每次递归调用结束后,又自动把栈顶元素(各个域)的值分别赋给相应的值参和局部变量(出栈),以便使它们恢复到调用前的值,接着无条件转向(返回)由返回地址所指定的位置继续执行算法。

利用栈将递归向非递归转化时所采用的方法,实质是用人工写的语句完成了本该系统程序完成的功能,即:栈空间中工作记录的保存和释放。

二、基本概念及特性1.栈的概念和特性栈(stack)是一种特殊的线性表。

作为一个简单的例子,可以把食堂里冼净的一摞碗看作一个栈。

在通常情况下,最先冼净的碗总是放在最底下,后冼净的碗总是摞在最顶上。

而在使用时,却是从顶上拿取,也就是说,后冼的先取用,后摞上的先取用。

如果我们把冼净的碗“摞上”称为进栈(压栈),把“取用碗”称为出栈(弹出),那么上例的特点是:后进栈的先出栈。

然而,摞起来的碗实际上是一个线性表,只不过“进栈”和“出栈”都在最顶上进行,或者说,元素的插入和删除操作都是在线性表的一端进行而已。

一般而言,栈是一个线性表,其所有的插入和删除操作均是限定在线性表的一端进行,允许插入和删除的一端称栈顶(Top),不允许插入和删除的一端称栈底(Bottom)。

若给定一个栈S=(a1, a2,a3,……,an),则称a1为栈底元素,an为栈顶元素,元素ai 位于元素ai-1之上。

栈中元素按a1, a2,a3,……,an的次序进栈,如果从这个栈中取出所有的元素,则出栈次序为an , an-1,……,a1。

也就是说,栈中元素的进出是按后进先出的原则进行,这是栈结构的重要特征。

因此栈又称为后进先出(LIFO—Last In First Out)表。

2.递归的概念和特性1.所谓的递归,是指函数在执行过程中自己调用了自己或者说某种数据结构在定义时又引用了自身。

这两种情况都可理解为递归。

比如:void fun(){..fun()..}//fun以上函数fun就是一个递归函数。

而针对于各种数据结构中的递归结构就更多了,如单链表,广义表,树。

在这些递归结构中,具有一个相同的特征:其中的某个域的数据类型是其结点类型本身!2.递归算法的大致结构为:a.递归出口b.递归体一个递归算法,当其问题求解的规模越来越小时必定有一个递归出口,就是不再递归调用的语句。

递归体则是每次递归时执行的语句序列。

比如以下简要描述的递归函数中:f(n)=1 (当n=0时)f(n)=n*f(n-1) (当n>0时)这个递归函数,实际是求n的阶乘。

当n=0时,不再递归调用,而当其值置为1;当n>0时,就执行n*f(n-1),这是递归调用。

从整体上理解递归算法的大致结构有利于我们在设计递归算法时,从总体上把握算法的正确性。

三、栈的运算3.1栈运算的实现栈运算操作的具体实现取决于栈的存储结构,存储结构不同,其算法描述也不同,下面分别给出栈的运算在顺序存储结构和链接存储结构上实现的具体算法。

3.1.1 栈的操作在顺序存储结构上的实现假定采用顺序存储结构定义的栈用标识符S表示,其类型为已经给出过的Stack 记录类型。

(1)初始化栈:void InitStack(Stack& S)//初始化栈S,即把它置为空{S.top=-1;}(2)把一个栈清除为空在顺序存储方式下,同初始化栈的算法相同void ClearStack(Stack& S)//清除栈S中的所有元素,使之成为一个空栈{S.top=-1;}(3)检查栈是否为空void StackEmpty(Stack& S)//判断栈S是否为空,若是则返回1,否则返回0 {returnS.top=-1;}(4)读取栈顶元素ElemTepy Peek(Stack& S)//返回栈S的栈顶元素,但不移动栈顶指针{//若栈为空则终止程序运行If (S.top= =-1){cerr <<”Stack is empty!”<<endl;exit (1);}//返回栈顶元素值return S.Stack[S.top];}(5)向栈中插入元素void Push (Stack& S,const ElemType& item)//元素item进栈,即插入到栈顶{//若栈已满则终止程序运行if (S.top = =StackMaxSize-1){cerr<<”Stack overflow!”<<endl;Exit(1)}//栈顶指针后移一个位置S.top++;//将item的值赋给新的栈顶位置S.Stack[S.top]=item;}(6)从栈中删除元素ElemType Pop(Stack& S)//删除栈顶元素并返回之{//若栈为空则终止程序运行If (S.top= =-1){cerr <<”Stack is empty!”<<endl;exit (1);}//暂存栈顶元素以便返还ElemType temp = S.Stack[S.top];//栈顶指针元素向前移动一个位置S.top--;//返回原栈顶元素的值Return temp;}从出栈算法可以看出,原栈顶元素的值没有被概念,所以可以不使用临时变量保存它,返回语句中返回S.stack[S.top+1]的值即可。

(7)检查栈是否已满int StackFull(Stack & S)//若栈已满则返回到1,否则返回到0,此函数为顺序栈所特有{return S.top = = StackMaxSize-1;}3.1.2 栈的操作在链接存储结构上的实现假定链表中的结点采用LNode结点类型,并假定栈顶指针用HS表示,下面给出对HS所指向的链栈进行每一种栈操作的算法。

(1)初始化链栈void InitStack(LNode*&HS){HS=NULL;//将链栈置空}(2)清除链栈为空void ClearStack(LNode*&HS){LNode * cp,*cp;//用cp作为指向待删除的结点,np指向cp的后继结点cp=HS;//给cp指针附初值,使之指向栈顶结点while (cp!=NULL){//从栈顶到栈底依次删除每个结点np=cp->next;delete cp;cp = np;}HS=NULL;//置链栈为空}(3)检查链栈是否为空int StackEmpty(LNode*HS)//HS为值参或引用形参均可{return HS= =NULL;}(4)读取栈顶元素ElemType Peek(LNode * HS)//HS为值参或引用形参均可{if (HS = = NULL){cerr < < “linked stack is empty !”<<endl;Exit (1);}Return HS- >data;}(5)向链栈中插入一个元素void Push (LNode * & HS ,const ElemType &item){//为插入元素获取动态结点LNode*newtr = new LNode;if (newptr = =NULL){cerr <<”Memory allocation failare !”< <endl;Exit(1);}//给新分配的结点赋值newptr - > data = item;//向栈顶插入新结点newptr ->next = HS;HS = newptr;}(6)从链栈中删除一个元素ElemType Pop (LNode * & HS){if(HS = = NULL){cerr <<”Linked stack is empty !”<<endl;exit(1);}LNode * p=HS;//暂存栈顶结点HS=HS->next;//使栈顶指针指向其后继结点ElemType temp = p - > data ;//暂存原栈顶元素delete p;Return temp;//返回原栈顶元素}四、栈的应用举例下面就简单举两个例子来说明一下栈的应用例1、从键盘上输入一批整数,然后按照相反的次序打印出来。

相关文档
最新文档