careercup-栈与队列 3.4

3.4 在经典问题汉诺塔中,有3根柱子及N个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自底向上从大到小依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时有以下限制:

每次只能移动一个盘子;

盘子只能从柱子顶端滑出移到下一根柱子;

盘子只能叠在比它大的盘子上。

请运用栈,编写程序将所有盘子从第一根柱子移到最后一根柱子上。

使用递归的方法实现如下:

#include<iostream>
#include<stack>
using namespace std;

struct op
{
    int begin;
    int end;
    char A;
    char B;
    char C;
    op(int start,int end,int A,int B,int C):begin(start),end(end),A(A),B(B),C(C) {}
};

void hanoi(int start,int end,char A,char B,char C)
{
    stack<op> st;
    op tmp(start,end,A,B,C);
    st.push(tmp);
    while(!st.empty())
    {
        tmp=st.top();
        st.pop();
        if(tmp.begin!=tmp.end)
        {
            st.push(op(tmp.begin,tmp.end-1,tmp.B,tmp.A,tmp.C));
            st.push(op(tmp.end,tmp.end,tmp.A,tmp.B,tmp.C));
            st.push(op(tmp.begin,tmp.end-1,tmp.A,tmp.C,tmp.B));
        }
        else
            cout<<"move "<<tmp.begin<<" from "<<tmp.A<<" to "<<tmp.C<<endl;
    }
}
int main()
{
    hanoi(1,6,‘A‘,‘B‘,‘C‘);
}

汉诺塔的递归解法讲完了,可是这并不是题目要求的。题目要求用栈来解决这个问题。 递归解法其实也是用到了栈的,在每次递归调用自己的时候, 将中间的状态参数压入栈中。不过这些操作都是系统隐式进行的, 所以你不用去关心它具体是怎么压栈出栈的。如果我们要用栈自己来实现这个过程, 就不得不考虑这其中的细节了。

接下来,我们就显式地用栈来实现递归过程中,这些状态参数的压栈出栈过程。首先, 我们需要定义一个数据结构来保存操作过程中的参数。

struct op{
    int begin, end;
    char src, bri, dst;
    op(){

    }
    op(int pbegin, int pend, int psrc, int pbri, int pdst):begin(pbegin), end(pend), src(psrc), bri(pbri), dst(pdst){

    }
};

其中的5个参数表示,在柱子src上有一叠圆盘,标号从begin到end, 要将它们从src移动到dst,中间可借助柱子bri。end其实相当于递归解法中的n, src,bri,dst与递归解法中的对应。那为什么还要定义begin这个变量呢? 为了判断柱子上是否只剩下一个盘子。如果begin等于end, 说明柱子上只剩下“最后”一个圆盘,可以进行移动。当然了, 用另外一个布尔变量来表示是否只剩下一个圆盘也是可以的,效果一样。 讲递归方法的时候,说到从初始状态到最终状态一共要经过以下几个状态:

(1~n, 0, 0) (n, 1~n-1, 0) (0, 1~n-1, n) (0, 0, 1~n) 

这些过程我们现在需要自己压栈出栈处理。压栈的时候不做处理,出栈时进行处理。因此, 压栈的时候需要与实际要操作的步骤相反。一开始,我们将最终想要完成的任务压栈。 听起来怪怪的,其实就是往栈中压入一组参数:

stack<op> st; st.push(op(1, n, src, bri, dst)); 

这组参数表示,柱子src上有1~n个圆盘,要把它移动到dst上,可以借助柱子bri。 当栈st不为空时,不断地出栈,当begin和end不相等时,进行三个push操作 (对应上面四个状态,相邻状态对应一个push操作,使状态变化), push与实际操作顺序相反(因为出栈时才进行处理,出栈时顺序就正确了), 如果,begin与end相等,则剩下当前问题规模下的“最后”一个圆盘,直接打印移动方案, hanoi代码如下:

C++实现代码:

#include<iostream>
#include<stack>
using namespace std;

struct op
{
    int begin;
    int end;
    char A;
    char B;
    char C;
    op(int start,int end,int A,int B,int C):begin(start),end(end),A(A),B(B),C(C) {}
};

void hanoi(int start,int end,char A,char B,char C)
{
    stack<op> st;
    op tmp(start,end,A,B,C);
    st.push(tmp);
    while(!st.empty())
    {
        tmp=st.top();
        st.pop();
        if(tmp.begin!=tmp.end)
        {
            st.push(op(tmp.begin,tmp.end-1,tmp.B,tmp.A,tmp.C));
            st.push(op(tmp.end,tmp.end,tmp.A,tmp.B,tmp.C));
            st.push(op(tmp.begin,tmp.end-1,tmp.A,tmp.C,tmp.B));
        }
        else
            cout<<"move "<<tmp.begin<<" from "<<tmp.A<<" to "<<tmp.C<<endl;
    }
}
int main()
{
    hanoi(1,5,‘A‘,‘B‘,‘C‘);
}

运行结果:

参考:http://www.cricode.com/304.html

时间: 2024-08-18 05:12:47

careercup-栈与队列 3.4的相关文章

快速记忆数组栈和队列函数push()和shift()

在js中,对数组的操作是比较常见的,有时候,我们需要模拟栈和队列的特性才能实现需求,今天来给大家用通俗易懂.简洁明了的几行文字,来告诉大家栈和队列的几个函数,如何快速记住. 首先,概念还是要知道的: 栈(stack)又名堆栈,它是一种运算受限的线性表.其限制是仅允许在表的一端进行插入和删除运算.这一端被称为栈顶,相对地,把另一端称为栈底.向一个栈插入新元素又称作进栈.入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素:从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻

3-3-行编辑程序-栈和队列-第3章-《数据结构》课本源码-严蔚敏吴伟民版

课本源码部分 第3章  栈和队列 - 行编辑程序 ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑        本源码引入的文件  链接? SequenceStack.c        相关测试数据下载  链接? 无数据

用栈实现队列的效果

用两个栈实现队列的效果,可以入栈,出栈,判空等... 实现的栈基本功能 lstack.h #ifndef _LSTACK_H #define _LSTACK_H #include <stdexcept> using namespace std; // 基于链式表的堆栈 class Stack { public: // 构造过程中初始化为空堆栈 Stack (void) : m_top (NULL) {} // 析构过程中销毁剩余的节点 ~Stack (void) { for (Node* ne

javascript中的栈、队列。

                       javascript中的栈.队列 栈方法     栈是一种LIFO(后进先出)的数据结构,在js中实现只需用到2个函数 push()  接受参数并将其放置数组尾,并返回修改后的数组长度. pop()  移除数组尾的最后一项,并返回移除项的值. 事例: var colors = new Array();var count = colors.push("red","green"); count = colors.push(&

数据结构之栈和队列

数据结构学习继续向前推进,之前对线性表进行了学习,现在我们进入栈和队列的学习.同样我们先学习一些基本概念以及堆栈的ADT. 栈和队列是两种中重要的线性结构.从数据结构角度看,栈和队列也是线性表,只不过是受限的线性表.因此可以称为限定性数据结构.但从数据类型来看,他们是和线性表大不相同的两类重要的抽象数据类型. 栈:(stack)是限定仅在表尾进行相应插入和删除操作的线性表.因此,对栈来说,表尾有其特殊含义,称为栈顶,表头称为栈底,不含元素的空表称为空栈.栈一个重要特性就是后进先出.OK,我们来看

图解堆算法、链表、栈与队列(Mark)

原文地址: 图解堆算法.链表.栈与队列(多图预警) 堆(heap),是一类特殊的数据结构的统称.它通常被看作一棵树的数组对象.在队列中,调度程序反复提取队列中的第一个作业并运行,因为实际情况中某些时间较短的任务却可能需要等待很长时间才能开始执行,或者某些不短小.但很重要的作业,同样应当拥有优先权.而堆就是为了解决此类问题而设计的数据结构.--

第三章:1.栈和队列 -- 栈的表示及实现

前言: 栈和队列 是两种重要的线性结构.从数据结构角度来看,栈和队列也是线性表,它的特殊性在于其操作是线性表的子集,是操作受限的线性表,因此可以称作限定性的数据结构. (限定性:如.人为的规定线性表只能从表尾插入和删除结点数据元素,那么这样的线性表就是栈) 目录: 1.栈 2.栈的应用举例 3.栈与递归的实现 4.队列 5.离散事件模型 正文: 栈的定义 栈(stack) 如上所说,就是限定只能在表尾进行插入和删除的线性表.表尾 称为 栈顶(top), 表头 称为 栈底 (bottom),没有数

数据结构和算法分析(9)表栈和队列的实际应用(一)

    在接下来的几篇博文中,将介绍表.栈.队列在编程实践中的应用.     (1)表达式求值:     输入一个中缀表达式,操作符包括(+ - * / ^).转化为后缀表达式之后并计算表达式的值: 要求: 1.输入的中缀表达式必须是一个完整的字符串: 2.不限制数字的位数和正负,负数用()括起来: 代码如下: 1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 5 #define EmptyT

用两个栈实现队列-剑指Offer

用两个栈实现队列 题目描述 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 思路 一个栈的顺序是“后进先出”,再用一个栈把顺序颠倒过来就满足队列的“先进先出”规则了 用两个stack实现,stack1负责进队列,然后从stack2弹栈出队列,若stack2为空,再从stack1弹出到stack2 代码 import java.util.Stack; public class Solution { Stack<Integer> stack1 = new St

(hdu step 8.1.1)ACboy needs your help again!(STL中栈和队列的基本使用)

题目: ACboy needs your help again! Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 73 Accepted Submission(s): 57   Problem Description ACboy was kidnapped!! he miss his mother very much and is very