Java学习(Day 14)

学习来源:日撸 Java 三百行(21-30天,树与二叉树)_闵帆的博客-CSDN博客

Hanoi 塔问题

一、描述

有三根杆子A, B, C. A 杆上有 N 个 ( N > 1 ) 穿孔圆盘, 盘的尺寸由下到上依次变小. 要求按下列规则将所有圆盘移至 C 杆: 每次只能移动一个圆盘; 大盘不能叠在小盘上面.

提示: 可将圆盘临时置于 B 杆, 也可将从 A 杆移出的圆盘重新移回 A 杆, 但都必须遵循上述两条规则.

问: 如何移? 最少要移动多少次 ?

二、思考

在数据结构中, 一般把 Hanoi 塔放到栈这一章. 但我觉得, 将其展开更像是二叉树, 也有点三叉的味道.

最后还不是依靠递归来完成. 最简单的就是只有一个圆盘, 这样直接可以从 A 移动到 C.
当圆盘数 N 大于 1 时(N > 1)可以把只除去最后一个的剩余圆盘作为一个整体, 使它通过 C 移动到 B , 然后最后一个圆盘从 A 移动到 C. 这样问题就转换成了 N - 1 个圆盘从 B 经过 A 移动到 C 上.

三、具体实现

输入

三个字符代表杆, 一个整数代表需要移动的圆盘. 初始状态如下所示

paraSource      需要移动的圆盘所在杆 整个函数开始初始为 A 杆
paraIntermedium 移动圆盘用作缓存的杆 整个函数开始初始为 B 杆
paraDestination 圆盘最终需要到达的杆 整个函数开始初始为 C 杆
paraNumber      需要移动圆盘的数量   整个函数开始初始为 3

输出

依照 Hanoi 规则输出的圆盘移动顺序

1. 完整代码

package datastructure.tree;

/**
 * Hanoi tower.
 * 
 * @author Shihuai Wen Email:wshysxcc@outlook.com
 */
public class Hanoi {

	/**
	 *********************
	 * Move a number of plates.
	 * 
	 * @param paraSource      The source pole.
	 * @param paraIntermedium The intermediary pole.
	 * @param paraDestination The destination pole.
	 * @param paraNumber      The number of plates.
	 *********************
	 */
	public static void hanoi(char paraSource, char paraIntermediary, char paraDestination, int paraNumber) {
		if (paraNumber == 1) {
			System.out.println(paraSource + "->" + paraDestination + " ");
			return;
		} // Of if

		hanoi(paraSource, paraDestination, paraIntermediary, paraNumber - 1);
		System.out.println(paraSource + "->" + paraDestination + " ");
		hanoi(paraIntermediary, paraSource, paraDestination, paraNumber - 1);

	}// Of hanoi

	/**
	 *********************
	 * The entrance of the program.
	 * 
	 * @param args Not used now.
	 *********************
	 */
	public static void main(String args[]) {
		hanoi('A', 'B', 'C', 3);
	}// Of main

} // Of class Hanoi

2. 运行截图

Huffman 编码 (节点定义与文件读取)

一、概念

哈夫曼编码 ( Huffman Coding ), 又称霍夫曼编码, 是一种编码方式, 哈夫曼编码是可变字长编码 ( VLC ) 的一种. Huffman 于 1952 年提出一种编码方法, 该方法完全依据字符出现概率来构造异字头的平均长度最短的码字, 有时称之为最佳编码, 一般就叫做 Huffman 编码(有时也称为霍夫曼编码).

二、变量释义

每个节点的内容包括: 字符 (仅对叶节点有效)、权重 (用的整数, 该字符的个数)、指向子节点父节点的引用. 这里指向父节点的引用是必须的.

NUM_CHARS 是指 ASCII 字符集的字符个数. 为方便起见, 仅支持 ASCII.

inputText 的引入只是想把程序尽可能细分成独立的模块, 这样便于学习和调拭. 用于存储输入的字符串, 使得程序可以处理多种情况.

alphabet 仅存 inputText 出现过的字符.

alphabetLength 完全可以用 alphabet.length() 代替.

charCounts 要为所有的节点负责, 其元素对应于 HuffmanNode 里面的 weight. 为了节约, 可以把其中一个省掉.

charMapping 是为了从 ASCII 里面的顺序映射到 alphabet 里面的顺序. 这也是我只采用 ASCII 字符集 (仅 256 字符) 的原因.

huffmanCodes 将个字符映射为一个字符串, 其实应该是二进制串. 我这里不是想偷懒么.

nodes 要先把所有的节点存储在一个数组里面, 然后再链接它们. 这是常用招数.
构造方法仅初始化了 charMapping, 读入了文件.

readText 采用了最简单粗暴的方式. 还可以有其它的逐行读入的方式.

要自己弄个文本文件, 里面存放一个字符串 abcdedgsgs 之类, 或者几行英文文本.

三、本节代码

定义 Huffman 树及其节点, 编写其构造函数及其从文件读取字符串.

package datastructure.tree;

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Collectors;

/**
 * Huffman tree, encoding, and decoding. For simplicity, only ASCII characters
 * are supported.
 * 
 * @author Shihuai Wen Email:wshysxcc@outlook.com
 */
public class Huffman {
	/**
	 * An inner class for Huffman nodes.
	 */
	class HuffmanNode {
		/**
		 * The char. Only valid for leaf nodes.
		 */
		char character;

		/**
		 * Weight. It can also be double.
		 */
		int weight;

		/**
		 * The left child.
		 */
		HuffmanNode leftChild;

		/**
		 * The right child.
		 */
		HuffmanNode rightChild;

		/**
		 * The parent. It helps constructing the Huffman code of each character.
		 */
		HuffmanNode parent;

		/**
		 ******************* 
		 * The first constructor
		 ******************* 
		 */
		public HuffmanNode(char paraCharacter, int paraWeight, HuffmanNode paraLeftChild, HuffmanNode paraRightChild,
				HuffmanNode paraParent) {
			character = paraCharacter;
			weight = paraWeight;
			leftChild = paraLeftChild;
			rightChild = paraRightChild;
			parent = paraParent;
		}// Of HuffmanNode

		/**
		 ******************* 
		 * To string.
		 ******************* 
		 */
		public String toString() {
			String resultString = "(" + character + ", " + weight + ")";

			return resultString;
		}// Of toString

	}// Of class HuffmanNode

	/**
	 * The number of characters. 256 for ASCII.
	 */
	public static final int NUM_CHARS = 256;

	/**
	 * The input text. It is stored in a string for simplicity.
	 */
	String inputText;

	/**
	 * The length of the alphabet, also the number of leaves.
	 */
	int alphabetLength;

	/**
	 * The alphabet.
	 */
	char[] alphabet;

	/**
	 * The count of chars. The length is 2 * alphabetLength - 1 to include non-leaf
	 * nodes.
	 */
	int[] charCounts;

	/**
	 * The mapping of chars to the indices in the alphabet.
	 */
	int[] charMapping;

	/**
	 * Codes for each char in the alphabet. It should have the same length as
	 * alphabet.
	 */
	String[] huffmanCodes;

	/**
	 * All nodes. The last node is the root.
	 */
	HuffmanNode[] nodes;

	/**
	 *********************
	 * The first constructor.
	 * 
	 * @param paraFilename The text filename.
	 *********************
	 */
	public Huffman(String paraFilename) {
		charMapping = new int[NUM_CHARS];

		readText(paraFilename);
	}// Of the first constructor

	/**
	 *********************
	 * Read text.
	 * 
	 * @param paraFilename The text filename.
	 *********************
	 */
	public void readText(String paraFilename) {
		try {
			inputText = Files.newBufferedReader(Paths.get(paraFilename), StandardCharsets.UTF_8).lines()
					.collect(Collectors.joining("\n"));
		} catch (Exception ee) {
			System.out.println(ee);
			System.exit(0);
		} // Of try

		System.out.println("The text is:\r\n" + inputText);
	}// Of readText

	/**
	 *********************
	 * The entrance of the program.
	 * 
	 * @param args Not used now.
	 *********************
	 */
	public static void main(String args[]) {
		Huffman tempHuffman = new Huffman("D:/wenshihuai/huffmantext-small.txt");
	}// Of main

} // Of class Huffman

四、运行截图

总结

对我来说比较难理解的时读取文件那一部分. 其实就是对 JDK 的各种函数不熟悉. 读取文件那个函数也就是以字符流的形式读取文件, 然后读取每行字符串并用换行符拼接.

还是需要多写多练多熟悉.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值