IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 哈夫曼编码和汉诺塔初步了解(原理啥的也只是初步了解的程度代码如果我写的有问题的话见谅) -> 正文阅读

[数据结构与算法]哈夫曼编码和汉诺塔初步了解(原理啥的也只是初步了解的程度代码如果我写的有问题的话见谅)

一:汉诺塔问题:

一道经典问题了,我在其他博主那里找解题思路。给了我很大帮助。

博客地址:(3条消息) 汉诺塔问题——递归(时隔9个月,终于懂了)_Patience-CSDN博客_汉诺塔递归

汉诺塔问题是:汉诺塔:汉诺塔(Tower of Hanoi)源于印度传说中,大梵天创造世界时造了三根金钢石柱子,其中一根柱子自底向上叠着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。

package extra;

public class Hanois {
	public static int steps = 0;
	public void move(int id,char hole1,char hole2) {
		System.out.println(steps++ + ": plate "+id+" moves from "+hole1+ " to "+hole2);
	}
	//n个在x上的盘子通过y移动到z
	public void Hanoi(int n,char starthole,char inhole,char endhole) {//从左到右分别是盘子数,从哪个杆开始,中间杆,到哪个杆。
		if(n==0) return;
		Hanoi(n-1,starthole,endhole,inhole);
		move(n,starthole,endhole);
		Hanoi(n-1,inhole,starthole,endhole);
	}
	public static void main(String[] args) {
		Hanois ho = new Hanois();
		char a = 'a';
		char b = 'b';
		char c = 'c';
		ho.Hanoi(5,a,b,c);
		
	}

}

做完真的感觉挺神奇的,原本以为会用到很多代码,结果核心代码就那么几行,不过换做是我自己想肯定想不出来。

通过其他博主所描述的,比如你要移动64个盘,就将前面63个看作整体。这种看作整体的思想仔细想想原来也接触过,比如说就在c语言反转链表时,当使用递归的方法时,就会有化作整体的思想。

递归的关键有两个:

(1)递归的结束条件(不写会死循环,TLE)

(2)递归最后一层和其他有关系的层的关系怎样用非递归函数来表达

比如:斐波纳契亚数列,(1)当n==1和n==2的时候f(n)=1,这就是递归的终止条件。给了终止条件,计算机才能进行求解子问题并回溯,最终求出f(n)
?

关于关键中的第(2)点,这里就体现在了move函数上面,而move就表现出了和其他层的关系,并且是非递归函数。

要明白最后一步的前一步是什么,明白的话基本就赢了。

那么这一步的前一步是什么?

记住了,在求解f(n, other variables)的时候,我们直接默认f(n - 1, other variables)已经完了就可以了!这个在前面已经解释过了,在此不再鳌述。

我们将n-1个盘子当作一个整体:这就是类似于分治求解子问题的思想

那么,前一步也就是f(n - 1, other variables)显然是先将n -1 个在A柱子上的盘子通过C柱移动到B柱上,再将在A柱子上的编号为n的盘子移动到C柱上,再将B柱子上的n-1个盘子通过A柱移动到C柱上,over

二:哈夫曼编码:

哈夫曼节点类代码如下:

package huffmanTreeMyself;

public class Node {

	public Node lChild;
	public Node rChild;
	public String code;// 节点的哈夫曼编码
	public int codeSize;// 节点哈夫曼编码的长度
	public String data;// 节点的数据
	public int count;// 节点的权值
	public String config = "";//用来标记节点是左节点或者是右节点。
	
	//哈夫曼编码说白了就是用左0右1来进行表示。

	public Node() {
	}

	public Node(String data, int count) {
		this.data = data;
		this.count = count;
	}

	public Node(int count, Node lChild, Node rChild) {
		this.count = count;
		this.lChild = lChild;
		this.rChild = rChild;
	}

	public Node(String data, int count, Node lChild, Node rChild) {
		this.data = data;
		this.count = count;
		this.lChild = lChild;
		this.rChild = rChild;
	}

	public static void main(String[] args) {

	}

}

以下是huffman编码的正式代码,期间用到了图的键值对存储,最终可以获得每个节点的Huffman编码。

哦,忘了说,这里最终输出出来的话是节点本身的值(不是权值)带上哈夫曼编码。

package huffmanTreeMyself;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

public class Huffman {

	String newstr;// 经过编码后形成的huffman编码字符串
	private String readtext;// 压缩前的字符串。
	private Node root;// 哈夫曼二叉树的根节点
//	private boolean flag;// 最新的字符是否已经存在的标签
	private ArrayList<String> charList;// 存储不同字符的队列 相同字符存在同一位置
	private ArrayList<Node> NodeList;// 存储节点的队列

	public void CreateHuffman(String strs) {
		// 1:找权值。
		this.readtext = strs;
		charList = new ArrayList<>();
		NodeList = new ArrayList<>();

		boolean flag;// flag标识符标识唯一存在的情况,true表示当前唯一存在
		for (int i = 0; i < strs.length(); i++) {
			char ch = strs.charAt(i);
			flag = true;
			for (int j = 0; j < charList.size(); j++) {
				if (charList.get(j).charAt(0) == ch) {
					flag = false;
					String temp = charList.get(j) + ch;
					charList.set(j, temp);
					break;
				}
			}
			if (flag) {// 这里if一定要放在for循环外,不然根本无法触发添加的操作,会一直是0的状态。
				String temp = "" + ch;
				charList.add(charList.size(), temp);// 添加到指定位置
			}
		}

		// 接下来将产生哈夫曼树的节点。连接huffman树节点的操作在下一步进行。
		for (int i = 0; i < charList.size(); i++) {
			String temp = charList.get(i).charAt(0) + "";
			Node node = new Node(temp, charList.get(i).length());// string int
			NodeList.add(i, node);
		}

		// 接下来对Huffman树节点进行连接。(当然要使用huffman那里的编码方式)
		// 此外,需要写一个排序方法,来对权值进行排序。(这里使用冒泡排序)
		while (NodeList.size() > 1) {
			NodeSort(NodeList);
			Node temp1 = NodeList.remove(0);
			Node temp2 = NodeList.remove(0);
			int value = temp1.count + temp2.count;
			temp1.config = "0";
			temp2.config = "1";//左0右1。
			Node temp3 = new Node(value, temp1, temp2);
			NodeList.add(temp3);// 将temp3置于首位,因为之后还会排序
		}
		root = NodeList.get(0);// 需要root这个载体去承接已经创建好的哈夫曼树。(非常重要要)
	}

	public void NodeSort(ArrayList<Node> NodeList) {// 这里是从小到大排序
		for (int i = 0; i < NodeList.size() - 1; i++) {
			for (int j = i + 1; j < NodeList.size(); j++) {
				Node temp;
				if (NodeList.get(i).count > NodeList.get(j).count) {
					temp = NodeList.get(i);
					NodeList.set(i, NodeList.get(j));
					NodeList.set(j, temp);
				}
			}
		}
	}
	
	public void show(ArrayList<Node> NodeList) {
		for(int i = 0;i<NodeList.size();i++) {
			System.out.print(NodeList.get(i).count+" ");
		}
	}

	public void inOrderReverse(Node node) {
		
		if (node.lChild != null) {
			inOrderReverse(node.lChild);
		}
		System.out.print(" " + node.count);
		if (node.rChild != null) {
			inOrderReverse(node.rChild);
		}
		
	}

	public void inOrderReverse() {
		inOrderReverse(root);
	}

	public String ReadFromFiles(File location) {
		FileInputStream fis = null;
		try {//使用字节流进行对文本字符进行读取。
			fis =new FileInputStream(location);
			byte[] bytes = new byte[1024*1024];//1M每次
			readtext = "";
			int count = 0;
			while((count = fis.read(bytes))!=-1) {
				readtext += new String(bytes,0,count);
			}
			return readtext;
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			if(fis!=null) {
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return null;
		
	}//调用此方法来读取文件中的字符串究竟是多少。
	//以下方法是获得的每个节点的哈夫曼编码。
	private void GetHuffmanCodes(Node node,String goal,HashMap<String, String> hfmMap) {//goal是要查找的节点
		if(node!=null) {
			goal += node.config;
			if(node.lChild==null&&node.rChild==null) {
				hfmMap.put(node.data,goal);
			}
		}
		if(node.lChild!=null) {
			GetHuffmanCodes(node.lChild,goal,hfmMap);
		}
		if(node.rChild!=null) {
			GetHuffmanCodes(node.rChild,goal,hfmMap);
		}
		
//		if(node.data.equals(goal)==true) {//包含了树中为空的节点,不能包含。。。。。
//			return newstr;
//		}else {
//			if(node.lChild!=null) {
//				GetHuffmanCodes(node.lChild,goal);
//			}
//			else if(node.rChild!=null) {
//				GetHuffmanCodes(node.rChild,goal);
//			}
//		}
//		return null;
		
	}
	
	public void GetHuffmanCodes(String goal) {
		HashMap<String,String> hfmMap = new HashMap<String,String>();
		GetHuffmanCodes(root.lChild,goal,hfmMap);//利用图来存储键值对,最后取出需要的键值对即可。
		System.out.println(hfmMap.get("a"));
	}//最终方法输出获取的哈夫曼编码。
	
	public static void main(String[] args) {
		Huffman huf = new Huffman();
//		huf.CreateHuffman("sdfassvvdfgsfdfsdfs");
//		huf.inOrderReverse();//我这个也是对的,带权路径长度是一样的。
		
		File inputtext = new File("D:\\filetest\\temp.txt");
		//首先,对字符串文件内容进行读取。使用字节流或字符流都可以,字符流应该要简单一点。
		huf.CreateHuffman(huf.ReadFromFiles(inputtext));
		huf.inOrderReverse();
		System.out.println("");
		huf.GetHuffmanCodes("a");
	}

}
 4 8 2 4 1 2 1 19 5 11 6
a0110

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-01-28 12:10:13  更:2022-01-28 12:12:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 19:25:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码