第三章解决堆栈的编程问题

第三章      解决堆栈的编程问题

堆栈是一种特殊的线性表,是一种只允许在表的一端进行插入或删除操作的线性表。

堆栈的主要特点是后进先出

用一片连续的存储空间来存储栈中的元素,这样的栈称为顺序栈

用链式存储结构存储的栈称为链栈

汉诺塔问题

汉诺塔问题来自一个古老的传说:在世界刚刚被创建的时候有一座砖石宝塔(A),其上有64个金蝶。所有按从大到小的顺序从塔底堆放至塔顶。紧挨着这座塔有两个砖石塔(B和C)。从世界创始之日起,婆罗门的牧师们就一直在试图把A塔上的碟子移动到B上去,其间借助于C的帮助。由于碟子非常重,因此,每次只能移动一个碟子。另外,任何时候都不能把一个碟子放在比它小的碟子上面。按照这个传说,当牧师们完成所有的任务之后,世界末日也就到了。

在汉诺塔问题中,已知n个碟子和3座塔。初始时所有的碟子按从大到小的次序从塔A的底部堆放至顶部,现在需要把碟子都移动到B塔,每次移动一个碟子,而且任何时候都不能把大碟子放到小碟子上面。

【基本要求】

(1)      编写一个算法实现将A塔上的碟子移动到B塔上,大碟子在下,小碟子在上。

(2)      将移动的过程显示出来

思路:

由上可知,要想把n个碟子从A移动到目标塔(不妨设为B),则需要将n-1个碟子移动到缓冲塔(C),然后将最大的碟子放到B;

再往前迭代,即以A为缓冲塔,只需将n-2个碟子移动到B,然后将次大的移动到C;

……

直到最后只需移动一个碟子到指定的塔。

汉诺塔碟子的移动次数为:2n-1

C#代码实现如下:

1)  封装栈结点:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace LinkStack

{

class StackNode<T>

{

private T data;

privateStackNode<T> next;

public StackNode()

{

data = default(T);

next = null;

}

public StackNode(Tval)

{

data = val;

next = null;

}

public StackNode(Tval, StackNode<T> p)

{

data = val;

next = p;

}

public T Data

{

get

{

return data;

}

set

{

data = value;

}

}

publicStackNode<T> Next

{

get

{

return next;

}

set

{

next = value;

}

}

}

}

2)  栈操作接口:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace LinkStack

{

interface IStack<T>

{

void Push(T item);//压栈

T Pop();//出栈

bool isEmpty();

void Clear();

}

}

3)  链栈封装:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace LinkStack

{

classLStack<T>:IStack<T>

{

privateStackNode<T> top;

private int count;

private string name =string.Empty;

public int Count

{

get { returncount; }

}

public string Name

{

get { return name;}

set { name =value; }

}

public LStack()

{

top = null;

count = 0;

}

public LStack(stringname)

{

this.name = name;

top = null;

count = 0;

}

public void Push(Titem)

{

StackNode<T> tnode = newStackNode<T>(item);

if (top == null)

{

top = tnode;

}

else

{

tnode.Next =top;

top = tnode;

}

count++;

}

public T Pop()

{

if (top == null&& count == 0)

{

throw newException("栈为空!");

}

StackNode<T>tnode = top;

top = top.Next;

count--;

return tnode.Data;

}

public bool isEmpty()

{

if (top == null&& count == 0)

{

return true;

}

return false;

}

public void Clear()

{

top = null;

count = 0;

}

}

}

4)  算法实现:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace LinkStack

{

class Program

{

/// <summary>

/// 解决汉诺塔问题

/// </summary>

/// <paramname="args"></param>

static voidMain(string[] args)

{

//三根塔柱

LStack<int>tln_A =new LStack<int>("A");

LStack<int>tln_B = new LStack<int>("B");

LStack<int>tln_C = new LStack<int>("C");

Console.WriteLine("请输入汉诺塔中上碟子的个数");

string nstr =Console.ReadLine();

int n;

if(!int.TryParse(nstr, out n))

{

Console.WriteLine("请输入有效的整数!");

}

for (int i = n;i>=1; i--)

{

tln_A.Push(i);

}

MoveTa(n, tln_B,tln_A, tln_C);

Console.WriteLine("B塔元素依次为:");

for (int i = 0; i< n;i++ )

{

Console.Write(tln_B.Pop() + "   ");

}

Console.ReadKey();

}

static void MoveTa(intn, LStack<int> desT, LStack<int> srcT,LStack<int> bufT)

{

if (n == 1)

{

int t =srcT.Pop();

desT.Push(t);

string str="将金碟"+t+"从塔" + srcT.Name + "移动到" +desT.Name;

Console.WriteLine(str);

}

else

{

MoveTa(n - 1,bufT,srcT,desT);

//移动最大的金蝶

int t =srcT.Pop();

desT.Push(t);

string str ="将金碟" + t + "从塔" + srcT.Name + "移动到" +desT.Name;

Console.WriteLine(str);

MoveTa(n - 1,desT, bufT, srcT);

}

}

}

}

时间: 2024-08-06 20:07:04

第三章解决堆栈的编程问题的相关文章

第九章 解决图的编程问题

第九章      解决图的编程问题 图的定义: 图是由一系列定点(结点)和描述定点之间的关系边(弧)组成.图是数据元素的集合,这些数据元素被相互连接以形成网络.其形式化定义为: G=(V,E) V={(Vi|Vi∈某个数据元素集合)} E={(Vi,Vj)|Vi+Vj∈V^P(Vi,Vj)} 其中,G表示图:V是顶点集合:E是边或弧的集合.在集合E中,P(Vi,Vj)表示顶点Vi和顶点Vj之间有边或弧相连 相关术语 顶点集:图中具有相同特性的数据元素的集合成为顶点集 边(弧):边是一对顶点间的路

第七章解决二叉树的编程问题

第七章      解决二叉树的编程问题 二叉树是n(≥0)个有限元素的集合,该集合或者为空,或者由一个称为根的元素及两个不相交的,被称为左子树和右子树的二叉树组成.当集合为空时,称该二叉树为空二叉树,在二叉树中一个元素也称为一个结点. 二叉树是有序的,即将其左右子树颠倒,就成为另一个不同的二叉树. 结点的度,结点所拥有的子树的个数 叶结点,度为0的结点,也称为终端结点 分支节点,度不为0的结点,也称为非终端结点 孩子.兄弟.双亲结点,树中一个结点的子树的根节点称为这个结点的孩子.这个结点称为孩子

第三章-套接字编程

套接字结构一般从内核到进程.从进程到内核,其中从内核到进程是值-结果参数的例子 地址转换函数推荐使用inet_ntop,inet_pton适用于ipv4跟ipv6 套接字地址结构 struct sockaddr_in{ uint8_t sin_len;//长度 posix规范不需要这个 sa_family_t sin_family; //协议族,无符号短整数.一般表示AF_INET in_port_t  sin_port;//端口 struct in_addr sin_addr;//32位ip地

第四、五章解决队列和串的编程问题

第四章      解决队列的编程问题 队列是一种特殊的线性表,是一种只允许在表的一端进行插入操作而在另一端进行删除操作的线性表.把进行插入操作的表尾称为队尾,进行删除操作的头部称为对头: 队列的主要特点是:先进先出,或后进后出 用一片连续的存储空间来存储队列中的数据元素,这样的队列称为顺序队列. 将顺序队列看成是首位相接的循环结构,这种队列叫做循环队列. 第五章      解决串的编程问题 串即字符串,是由0个或多个字符组成的有限序列,是数据元素为单个字符的特殊线性表. 顺序结构存储串: 串的静

C Primer Plus (第五版) 第三章 编程练习

第三章    数据和C 编程练习: 通过实验的方法(即编写带有此类问题的程序)观察系统如何处理整数上溢.浮点数上溢和浮点数下溢的的情况. #include <stdio.h> int main(void) { /* 16位短整形 */ short int a = 32767; printf("a + 1 = %d\n", (short)(a + 1)); /* 32位整形 */ int b = 2147483647; printf("b + 1 = %d\n&qu

《大道至简》第三章读后感

在前面,我阅读了大道至简的前两章,今天我又阅读了第三章,通过阅读第三章,我对于编程和做人等方面又有了进一步的理解和认识. 第三章中主要讲的是团队以及团队的领导者.作者指出对于一个团队而言最少以三个人为规模.三个人便有了团队的一些基本特性:主从,监督和责任.一个人的开发可以成功,这取决于个人的努力.两人的小组如果能相互支撑可以获得成功的,而三个人呢就得选了领导不是要程咬金一样的牛人而是要李离一样的牛人,项目完成不了切脑袋的是倒不必做递交辞呈的勇气总是要有的.当然并不是说项目没有做成功就一定要递交辞

[笔记][Java7并发编程实战手册]第三章-线程同步辅助类-概要

[笔记][Java7并发编程实战手册]系列目录 有点着急了,没有太注重质量,自己也没有理解透,从本章起,读书和随笔笔记的质量会更好. 第三章 在本章中,我们将学习: 资源的并发访问控制 资源的多副本的并发访问控制 等待多个并发事件的完成 在集合点的同步 并发阶段任务的运行 并发阶段任务中的阶段交换 并发任务间的数据交换 回顾 在第二章中主要学习了以下接口 synchronized关键字 Lock接口以及实现类,如ReentrantLock.ReentrantReadWriteLock中的Read

Python黑帽编程3.0 第三章 网络接口层攻击基础知识

3.0 第三章 网络接口层攻击基础知识 首先还是要提醒各位同学,在学习本章之前,请认真的学习TCP/IP体系结构的相关知识,本系列教程在这方面只会浅尝辄止. 本节简单概述下OSI七层模型和TCP/IP四层模型之间的对应关系,最后是本章教程需要的几个核心Python模块. 3.0.1 TCP/IP分层模型 国际标准化组织(ISO)在1978年提出了"开放系统互联参考模型",即著名的OSI/RM模型(Open System Interconnection/Reference Model).

《Java并发编程实战》第三章 对象的共享 读书笔记

一.可见性 什么是可见性? Java线程安全须要防止某个线程正在使用对象状态而还有一个线程在同一时候改动该状态,并且须要确保当一个线程改动了对象的状态后,其它线程能够看到发生的状态变化. 后者就是可见性的描写叙述即多线程能够实时获取其它线程改动后的状态. *** 待补充   两个工人同一时候记录生产产品总数问题 1. 失效数据 可见性出现故障就是其它线程没有获取到改动后的状态,更直观的描写叙述就是其它线程获取到的数据是失效数据. 2. 非原子64位操作 3. 加锁与可见性 比如在一个变量的读取与