1. 汉诺塔问题:

(a)通过递归的方式解决:https://blog.csdn.net/zj1131190425/article/details/85156570

// 汉诺塔问题: 递归解决方案
void movedisk(int n, char fromTower, char toTower, char auxTower)
{if(n==1){cout << "Move disk " << n << " from " << fromTower << " to " << toTower << endl;}else{movedisk(n-1, fromTower, auxTower, toTower);    // 前n-1个盘子从A移到C,B作为辅助 cout << "Move disk " << n << " from " << fromTower << " to " << toTower << endl;   // 第n个盘子从A到B movedisk(n-1, auxTower, toTower, fromTower);    // n-1个盘子从C到B,A作为辅助 }
} 

递归法的时间复杂度:

按照递归的方法计算,递归的时间复杂度为

假设每次移动后要显示每个塔的布局:

每座塔移动碟子是按照 last in first out的次序进行的,可以把每座塔表示为一个栈。

复杂度问题:

三座塔上的盘子总数为n,如果使用链表形式的,则需要n个元素空间。如果使用数组形式的栈,则塔A需要n个元素空间,塔B需要n个元素空间,C需要n-1个元素空间,所以总共需要3n-1个元素空间。

虽然所需的空间不同,但是数组形式的栈运行速度更快。

思路依然是使用递归的方式,但是使用的是栈来存储数据:

代码:

#include <iostream>
#include "E:\back_up\code\c_plus_code\sparseMatrix\external_file\arraystack.h"
#include <string>
using namespace std;// 对盘子进行编号 arrayStack<int> tower[4];   // ABC塔// 显示塔的状态
void showState()
{cout << "===============================" << endl; cout << "Stack A: " << endl;tower[1].print_stack();cout << "Stack B: " << endl;tower[2].print_stack();cout << "Stack C: " << endl;tower[3].print_stack();
}// 递归的方案
//函数moveAndShow(n, x, y, z)  // (x,y,z)=(1,2,3)
// 将n个盘子从x移动到y,z作为辅助
void moveAndShow(int n, int x, int y, int z)
{if(n>0){moveAndShow(n-1, x, z, y);int tmp = tower[x].top();tower[x].pop();tower[y].push(tmp);showState();moveAndShow(n-1, z, y, x);}
} void Hanio_tower(int n)  // 初始化三座塔
{for(int i=n; i>0; i--){tower[1].push(i);}moveAndShow(n, 1, 2, 3);   // 将盘子从塔1移动到塔2,塔3作为辅助
} int main(int argc, char *argv[])
{Hanio_tower(3);
}

运行结果:

-------------------------------------------分割线---------------------------------------------------------

2. 列车车厢重排问题

H1,H2,H3缓冲轨道(相当于一个FILO的结构)

问题描述:
将入轨道上车厢的编号,通过借助缓冲轨道,排列成出轨道上的顺序

问题分析:

1, 在入轨道上拿一个车厢,如果车厢编号满足条件,直接放入出轨道,接着找缓冲轨道上是否有满足条件的车厢,直到找完所有满足条件的,接着判断入轨道上的下一个车厢。

2. 否则放入缓冲轨道

3.放入缓冲轨道按照如下原则:

优先向非空的缓冲轨道放入,如果有多个满足条件的非空轨道,则选择编号相距最近的轨道

如果非空的都不满足条件,则放入空的缓冲轨道。

4. 返回 步骤1

代码:

#include <iostream>
#include "E:\back_up\code\c_plus_code\sparseMatrix\external_file\arraystack.h"
#include <string>
using namespace std;// 对盘子进行编号 arrayStack<int> H[3];   // 缓冲轨道
arrayStack<int> in_rail;
arrayStack<int> out_rail;void show_rail_state()
{cout << "============================" << endl;cout << "In rail state: ";in_rail.print_stack();cout << "H1 state: ";H[0].print_stack();cout << "H2 state: ";H[1].print_stack();cout << "H3 state: ";H[2].print_stack();cout << "Out rail state: ";out_rail.print_stack();} // 定义一个递归函数
// 参数cnt_number为引用传递,因为涉及到在函数内部修改它的值且需要保存下来
void cache_rail_process(int& cnt_num, int n1=10)
{if(cnt_num<=n1){for(int j=0; j<3; j++)   // 遍历三个缓冲轨道 {if(!H[j].empty())   //  如果缓冲轨道非空,则判断是否为满足条件的车厢{if(H[j].top()==cnt_num){out_rail.push(H[j].top());H[j].pop();//train_number_cnt++;//cnt_num++;cache_rail_process(++cnt_num); }} } }
} void rail(int train_number[], int n)
{// train_number是车厢的初始排列顺序 for(int i=0; i<n; i++){in_rail.push(train_number[i]);   // 初始化入轨道  }int train_number_cnt = 1;   // 要找的车厢编号  while(!in_rail.empty())     {int tmp_number = in_rail.top();in_rail.pop();if(tmp_number==train_number_cnt)   // 如果车厢编号满足条件,直接放入出轨道 {out_rail.push(tmp_number);train_number_cnt++;// 将下面的函数修改为递归的形式// 因为在栈中需要不断的选找满足条件的编号,所以需要递归进行 cache_rail_process(train_number_cnt, n);// 接着再看缓冲轨道里面有没有满足条件的车厢/*for(int j=0; j<3; j++)   // 遍历三个缓冲轨道 {if(!H[j].empty())   //  如果缓冲轨道非空,则判断是否为满足条件的车厢{if(H[j].top()==train_number_cnt){out_rail.push(H[j].top());H[j].pop();train_number_cnt++;}} }*/}else{   // 优先放到非空的轨道 if(H[0].empty() && H[1].empty() && H[2].empty())  // 三个缓冲轨道均为空 {H[0].push(tmp_number);     // 随便放入一个轨道即可 }else   // 否则优先放置到非空的缓冲轨道上 {int trace_flag[3];   // 三个缓冲轨道的标志位 for(int j=0; j<3; j++){//if(!H[j].empty() && (H[j].top()>tmp_number))if(!H[j].empty()){trace_flag[j] = H[j].top() - tmp_number;   // trace_flag[j]>0,第j个轨道可以放置, trace_flag[j]<0,第j个轨道不可以放置} else{trace_flag[j] = 0;    // 第j个轨道为空 }}// 判断可放置的位置 int place_cnt = 0; for(int j=0; j<3; j++){if(trace_flag[j] > 0)place_cnt++;} if(place_cnt==0)  // 非空的位置都不合适{for(int k=0; k<3; k++)  // 则放入空位置 {//if(H[k].empty())if(trace_flag[k]==0) {H[k].push(tmp_number);break; }}} else if(place_cnt==1)  // 只有一个非空位置能放入,则放入到这个位置 {for(int k=0; k<3; k++){if(trace_flag[k]>0){H[k].push(tmp_number);break;}} }else    // 两个或者三个非空的位置可以放置,选择最优的位置 {int cmp=100;int cmp_index = 0;for(int k=0; k<3; k++){if(trace_flag[k]<cmp && trace_flag[k]>0){cmp = trace_flag[k];cmp_index = k;   // 找到最优的位置 }} H[cmp_index].push(tmp_number); }} }show_rail_state(); }// show_rail_state();
} int main(int argc, char *argv[])
{int number[] = {5,8,1,7,4,2,9,6,3};int nn = 9;rail(number, nn);
}

输出的结果:

复杂度分析:

改进的版本:

现在可以设置缓冲轨道的个数为任意多个:

修改程序的输入参数:

所需缓冲轨道的数量与车厢数有关,与车厢的排列顺序是否有关呢:

#include <iostream>
#include "E:\back_up\code\c_plus_code\sparseMatrix\external_file\arraystack.h"
#include <string>
using namespace std;// 对盘子进行编号 int cache_trace_num = 5;
arrayStack<int>* H = new arrayStack<int>[cache_trace_num];//arrayStack<int> H[3];   // 缓冲轨道
arrayStack<int> in_rail;
arrayStack<int> out_rail;void show_rail_state()
{cout << "============================" << endl;cout << "In rail state: ";in_rail.print_stack();/*cout << "H1 state: ";H[0].print_stack();cout << "H2 state: ";H[1].print_stack();cout << "H3 state: ";H[2].print_stack();*/for(int i=0; i<cache_trace_num; i++){cout << "H" << (i+1) << " state: ";H[i].print_stack();}cout << "Out rail state: ";out_rail.print_stack();} // 定义一个递归函数
// 参数cnt_number为引用传递,因为涉及到在函数内部修改它的值且需要保存下来
void cache_rail_process(int& cnt_num, int n1=10)
{if(cnt_num<=n1){for(int j=0; j<cache_trace_num; j++)   // 遍历三个缓冲轨道 {if(!H[j].empty())   //  如果缓冲轨道非空,则判断是否为满足条件的车厢{if(H[j].top()==cnt_num){out_rail.push(H[j].top());H[j].pop();//train_number_cnt++;//cnt_num++;cache_rail_process(++cnt_num);   }} } }
} void rail(int train_number[], int n)
{// train_number是车厢的初始排列顺序 for(int i=0; i<n; i++){in_rail.push(train_number[i]);   // 初始化入轨道  }int train_number_cnt = 1;   // 要找的车厢编号  while(!in_rail.empty())     {int tmp_number = in_rail.top();in_rail.pop();if(tmp_number==train_number_cnt)   // 如果车厢编号满足条件,直接放入出轨道 {out_rail.push(tmp_number);train_number_cnt++;// 将下面的函数修改为递归的形式// 因为在栈中需要不断的选找满足条件的编号,所以需要递归进行 cache_rail_process(train_number_cnt, n);// 接着再看缓冲轨道里面有没有满足条件的车厢/*for(int j=0; j<3; j++)   // 遍历三个缓冲轨道 {if(!H[j].empty())   //  如果缓冲轨道非空,则判断是否为满足条件的车厢{if(H[j].top()==train_number_cnt){out_rail.push(H[j].top());H[j].pop();train_number_cnt++;}} }*/}else{   // 优先放到非空的轨道 bool all_empty = true;   for(int i=0; i<cache_trace_num; i++)   // 判断所有轨道是否为空 {if(!H[i].empty()){all_empty = false;}}if(all_empty){H[0].push(tmp_number);}else   // 否则优先放置到非空的缓冲轨道上 {int trace_flag[cache_trace_num];   // 三个缓冲轨道的标志位 for(int j=0; j<cache_trace_num; j++){//if(!H[j].empty() && (H[j].top()>tmp_number))if(!H[j].empty()){trace_flag[j] = H[j].top() - tmp_number;   // trace_flag[j]>0,第j个轨道可以放置, trace_flag[j]<0,第j个轨道不可以放置} else{trace_flag[j] = 0;    // 第j个轨道为空 }}// 判断可放置的位置 int place_cnt = 0; for(int j=0; j<cache_trace_num; j++){if(trace_flag[j] > 0)place_cnt++;} if(place_cnt==0)  // 非空的位置都不合适{for(int k=0; k<cache_trace_num; k++)  // 则放入空位置 {//if(H[k].empty())if(trace_flag[k]==0) {H[k].push(tmp_number);break; }}} else if(place_cnt==1)  // 只有一个非空位置能放入,则放入到这个位置 {for(int k=0; k<cache_trace_num; k++){if(trace_flag[k]>0){H[k].push(tmp_number);break;}} }else    // 两个或者多个非空的位置可以放置,选择最优的位置 {int cmp=100;int cmp_index = 0;for(int k=0; k<cache_trace_num; k++){if(trace_flag[k]<cmp && trace_flag[k]>0){cmp = trace_flag[k];cmp_index = k;   // 找到最优的位置 }} H[cmp_index].push(tmp_number); }} }show_rail_state(); }// show_rail_state();
} int main(int argc, char *argv[])
{int number[] = {3,8,6,10,14,1,11,15,4,2,9,13,7,12,5};int nn = 15;//int number[] = {5,8,6,7,4,2,9,1,3,11,10}; //int nn = 11;rail(number, nn);
}

车厢数增加到15个,顺序是随机排列

至少需要5个缓冲轨道才能完成排序:打印过程

数据结构与算法 汉诺塔问题和列车车厢重排问题相关推荐

  1. 数据结构课设——汉诺塔游戏演示

    源代码下载地址:数据结构课设--汉诺塔游戏演示 一. 问题描述 汉诺塔游戏问题中的数据元素具有如下形式: lchild:左孩子结点 rchild:右孩子结点 num:该移动步骤需要移动的盘子的编号 s ...

  2. 分治算法——汉诺塔(HanoiTower)

    分治算法--汉诺塔 介绍 分治算法是一种很重要的算法.字面上的解释是"分而治之",就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题···直到最后子 ...

  3. hanoi java_java算法汉诺塔(hanoi)

    [实例简介]java算法汉诺塔(hanoi) [核心代码] public class Hanoi { /** * Hanoi塔问题 */ public static void main(String[ ...

  4. 三十三、分治算法---汉诺塔问题

    一.分治算法的介绍 分治法是一种很重要的算法.字面上的解释是"分而治之",就是把一个复杂的问题分成两个或更多的相同或 相似的子问题,再把子问题分成更小的子问题--直到最后子问题可以 ...

  5. 分治算法---汉诺塔

    思路分析 代码实现 package com.atguigu.dac;public class Hanoitower {public static void main(String[] args) {h ...

  6. 二分查找、分治算法——汉诺塔问题

    一.二分查找算法(非递归) 1)二分查找法只适用于从有序的数列中进行查找(比如数字和字母等),将数列排序后在进行查找 2)二分查找算法的运行时间为对数时间,即查找到需要的目标位置最多只需要log以2为 ...

  7. 分治算法(汉诺塔游戏)

    分治算法 分治算法就是将原问题分解成n个规模较小,并且结构与原问题相似的子问题,再去递归地解决这些子问题,然后这些子问题,然后再合并其结果,就可以得到原问题的解. 分治算法的递归实现,每一层递归都会涉 ...

  8. 玩游戏写算法——汉诺塔

    玩了个汉诺塔的flash游戏,总结下算法 四五层就不说了,太长,4层要15步,每步一截屏就刷死了,其实要想归纳出规律,最好还是玩四五层看看,多了才出规律. 上小下大,一个压一个,想把最底下的第 n 个 ...

  9. 算法 汉诺塔-java详解

    第一次看到这个算法时,很懵逼,是在栈那里.想了半天没想到半点跟栈有关系的解法.最后看了答案,是用的递归.但是看了答案还是很懵逼,下面就是博主自己对汉诺塔的一些了解. 有三根木桩,第一根上有n个盘子,最 ...

最新文章

  1. WCF学习之旅—WCF服务的WAS寄宿(十二)
  2. pytorch方法测试——卷积(二维)
  3. 根据关键字检索相关视频
  4. 销售抬头文本配置方法
  5. 管理mysql表知识点_数据库复习提纲(必考知识点整理)
  6. LeetCode 133. 克隆图(图的BFS/DFS)
  7. java不同进程的相互唤醒_Java多线程(二)同步与等待唤醒
  8. Problem C: 默认参数:求圆面积
  9. 【报告分享】2022跨境电商行业趋势报告.pdf(附下载链接)
  10. 微信联系人一键导出的方法在这里
  11. [论文] Feature Squeezing:Detecting Adversarial Examples in Deep Neural Networks
  12. 年薪百万阿里前端工程师分享——Web应用实例:音频可视化
  13. sql server 自定义背景、字体及显示行数
  14. 亿图图示----组织架构图----市场组织架构和公司架构图及家庭架构图
  15. 键盘鼠标是计算机标准输入输出设备,微型计算机输入输出设备之键盘和鼠标(ppt 32页).ppt...
  16. C++常用功能汇总-文件读写 计时 随机数
  17. iOS12-Swift5-Xcode10 Buildtime错误:/xx/Pods/Target Support Files/Pods-xx/Pods-xx.d
  18. Spring Cloud Stream Rabbit 3.1.3 入门实践
  19. android自定义sidebar,Sidebar - WiFi、GPS、手电筒们都到这里来! - Android 应用 - 【最美应用】...
  20. archlinux - W3af

热门文章

  1. 数据库工作笔记009---linux 导入导出postgresql数据库
  2. Android学习笔记---15_采用Pull解析器解析和生成XML内容
  3. 在caffe中添加样本扩增的功能
  4. 图的深度优先搜索(DFS)
  5. 导入已有项目到svn
  6. cocos2d-x之 利用富文本控件解析xhml标签(文字标签,图片标签,换行标签,标签属性)...
  7. C++类成员属性的一种简洁实现
  8. verilog 学习记(mac安装iverilog和gtkwave)
  9. 微型计算机体系结构的主要特点,高性能微型计算机体系结构:奔腾、酷睿系列处理器原理与应用技术...
  10. php获取当前页面select的值,关于JS获取select的值