java实现赫夫曼树以及赫夫曼编码和解码(用byte[])

2023-11-15

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

赫夫曼编码,主要目的是根据使用频率来最大化节省字符(编码)的存储空间。(举例来说,对于一个字符串中"i like java do you like a java"中有多个重复字符,我们可以存储一次一个字符对应的编码即可,可以节省存储空间) ;网上大多数用的是char来进行字符个数的查询以及 编码和解码,其实赫夫曼编码初衷就是可以用来压缩图片等,具体在百度百科上有介绍,下文也有链接。如果用char[] 就限制到了字符串是没有体现出来的;此博客用byte数组来进行编码解码和存储;
哈夫曼编码大致过程:

  1. 将字符串转换为byte数组

  2. 检查byte数组中字符的出现次数,将字符的byte和字符出现次数保存为节点,放入集合中

  3. 构建哈夫曼树(最小带权二叉树)

  4. 设左路径为0 右路径为1 计算字符的哈夫曼编码值,存入Map集合中(以便我们用map集合来找变长编码对应的值,但是这种方式会造成一定的问题后边说)

  5. 参照Map集合,将byte数组转换为byte字符串,将其对照Map集合逐一处理,由于数据量较大,所以八位一组进行数据压缩
    步骤对应的动画演示为:
    在这里插入图片描述

对于各个步骤对应的代码加注释如下:

package binaryTree;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.junit.Test;
/***
 * 
 * 没有实现文件压缩和解压,只需要对byte[]进行一下写入就可以了(最好用ObjectOutputStream 直接写入对象)
 * 这个实现byte类型转换成对应二进制string的方法不太好而且网上方法还没有这个好
 * @author 杰夫·王盖茨
 *
 */
public class HuffmanCode {
	private Map<Byte,String> huffManCodes ;
	private StringBuilder sb;
	public HuffmanCode() {
		huffManCodes = new HashMap<>();
		sb = new StringBuilder();
	}
	public static void main(String[] args) {
		String s = "i like like like java do you like a java";
		byte[] bytes = s.getBytes();
		HuffmanCode huffmanCode = new HuffmanCode();
		/*
		 * WeightNode root = huffmanCode.getRoot(huffmanCode.getWeightNode(bytes)); //
		 * root.preList(); huffmanCode.getHuffmanCode(root, "", huffmanCode.sb);
		 * Iterator<Entry<Byte, String>> iterator =
		 * huffmanCode.huffManCodes.entrySet().iterator(); while(iterator.hasNext()) {
		 * Entry<Byte, String> next = iterator.next(); System.out.println(next); }
		 * huffmanCode.gethuffmanCode(root); Iterator<Entry<Byte, String>> iterator1 =
		 * huffmanCode.huffManCodes.entrySet().iterator(); while(iterator.hasNext()) {
		 * Entry<Byte, String> next = iterator1.next(); System.out.println(next); }
		 */
		byte[] zip = huffmanCode.zip(bytes);
		System.out.println(Arrays.toString(zip));
		byte[] unZip = huffmanCode.unZip(zip, huffmanCode.huffManCodes);
		System.out.println(new String(unZip));
	}
	/**
	 * 将byte【】 统计重复byte之后得到对应的data和权重并且将他们包装成list
	 * @param bytes
	 * @return
	 */
	public List<WeightNode> getWeightNode(byte[] bytes) {
		HashMap<Byte, Integer> hashMap = new HashMap<>();
		for(byte b : bytes) {
			if(hashMap.get(b)==null) {
				hashMap.put(b, 1);
			}else {
				hashMap.replace(b, hashMap.get(b)+1);
			}
		}
		ArrayList<WeightNode> arrayList = new ArrayList<>();
		Iterator<Entry<Byte, Integer>> iterator = hashMap.entrySet().iterator();
		while(iterator.hasNext()) {
			Entry<Byte, Integer> next = iterator.next();
			arrayList.add(new WeightNode(next.getKey(),next.getValue()));
		}
		return arrayList;
	}
	/**
	 * 将包装成的list生成一个赫夫曼树
	 * @param arrayList
	 * @return
	 */
	public WeightNode getRoot(List<WeightNode> arrayList) {
		while(arrayList.size() > 1) {
			Collections.sort(arrayList);

			WeightNode weightLeft = arrayList.get(0);
			WeightNode weightRight = arrayList.get(1);
			WeightNode parent = new WeightNode(weightLeft.weight+weightRight.weight);

			parent.left = weightLeft;
			parent.right = weightRight;

			arrayList.remove(weightRight);
			arrayList.remove(weightLeft);
			arrayList.add(parent);
		}
		return arrayList.get(0);
	}
	public Map<Byte,String> gethuffmanCode(WeightNode root){
		getHuffmanCode(root,"",sb);
		//这个sb还是""没有变
		System.out.println(sb.toString());
		System.out.println(huffManCodes);
		return huffManCodes;
	}
	/**
	 * 将给定结点下的所有叶子结点的对应的编码号作为string放入huffManCodes中
	 * @param node  结点
	 * @param code  是向左遍历还是向右遍历“0”是向左,“1”是向右
	 * @param sb  截止到上个结点处他的String
	 */
	public void getHuffmanCode(WeightNode node,String code,StringBuilder sb) {
		if(node == null) return;
		StringBuilder sb2 = new StringBuilder(sb);		
		sb2.append(code);
		if(node.data == null) {
			//向左递归
			getHuffmanCode(node.left,"0",sb2);
			//向右递归
			getHuffmanCode(node.right,"1",sb2);
		}else {
			huffManCodes.put(node.data, sb2.toString());
			System.out.print(sb2.toString());
		}
	}
	/**
	 * 给我一个最原始的byte数组我返回给你一个赫夫曼byte
	 * (这个byte是将原来byte排序后转换成相应的赫夫曼编码的数组之后再将八位一个转换成byte而形成的数组)
	 * @param bytes 最原始的byte数组
	 * @return 赫夫曼编码形成之后转byte的byte数组
	 */
	public byte[] zip(byte[] bytes) {
		StringBuilder strb = new StringBuilder();
		Map<Byte, String> gethuffmanCode = gethuffmanCode(getRoot(getWeightNode(bytes)));
		Iterator<Entry<Byte, String>> iterator = gethuffmanCode.entrySet().iterator(); 
		while(iterator.hasNext()) {
			Entry<Byte, String> next = iterator.next(); 
			System.out.println(next); 
		}
		for(byte b:bytes) {
			strb.append(gethuffmanCode.get(b));
		}
		int len = (strb.length()+7) / 8;
		byte[] huffManBytes = new byte[len];
		int index = 0;
		for(int i=0;i<strb.length();i += 8) {
			if(i+8<strb.length())
				huffManBytes[index] = (byte)Integer.parseInt(strb.substring(i, i+8),2);
			else huffManBytes[index] = (byte)Integer.parseInt(strb.substring(i),2);
			index++;
		}
		return huffManBytes;
	}
	/**
	 * 将一个byte 转成一个二进制的字符串
	 * @param flag 标志是否需要补高位如果是true ,表示需要补高位,如果是false表示不补, 如果是最后一个字节,无需补高位
	 * @param byteOne  传入的 byte
	 * @return 是该b 对应的二进制的字符串,(注意是按补码返回)
	 */
	public String huffManBinaryTonomarl(boolean flag,byte byteOne) {
		int temp = byteOne;
		String str;
		if(flag) {
			temp |= 256;
		}
		str = Integer.toBinaryString(temp);
		if (flag&&temp<0) {
			return str.substring(str.length() - 8);
		} else {
			return str;
		}
	}
	/**
	 * 给我一个最终存储形式的数组之后,我可以返回给你需要的做string 的byte数组;
	 * @param source 最终存储形式的byte数组
	 * @param huffManCodes 你的对应的赫夫曼编码集
	 * @return 解码后的byte数组,可以用来new string 来还原了;
	 */
	public byte[] unZip(byte[] source,Map<Byte,String> huffManCodes) {
		StringBuilder sb = new StringBuilder();
		//遍历数组中的每一个byte 得到用byte存储前的赫夫曼数组
		for(int i=0;i<source.length;i++) {
			byte b = source[i];
			if(i==source.length-1)
				sb.append(huffManBinaryTonomarl(false,b));
			else sb.append(huffManBinaryTonomarl(true,b));
		}
		
		//用一个新的map将之前的key和val反过来
		Map<String,Byte> result = new HashMap<>();
		for(Map.Entry<Byte, String> entry:huffManCodes.entrySet()) {
			result.put(entry.getValue(), entry.getKey());
		}
		
		//这是整个通过这赫夫曼的数组拿到编码成赫夫曼之前的数组
		Byte byteOne;
		boolean flag = true;
		ArrayList<Byte> arr = new ArrayList<>();
		System.out.println(sb.length());
		for(int i=0;i<sb.length();) {
			int count = 1;
			flag = true;
			while(flag) {
				byteOne = result.get(sb.substring(i,i+count));
				if(byteOne==null) {
					count++;
				}else {
					arr.add(byteOne);
					flag = false;
				}
			}
			i += count;
		}
		
		byte[] b = new byte[arr.size()];
		for(int i=0;i<arr.size();i++) {
			b[i] = arr.get(i);
		}
		return b;
	}
}
class WeightNode implements Comparable<WeightNode>{
	public Byte data;  //这个才是对应的数据
	public WeightNode left;
	public WeightNode right;
	public int weight;  //权重就是出现了几次
	public WeightNode(int weight) {
		this.weight = weight;
	}
	public WeightNode(byte data, int weight) {
		this.data = data;
		this.weight = weight;
	}
	public void preList() {
		System.out.println(this);
		if(this.left!=null) left.preList();
		if(this.right!=null) right.preList();
	}
	@Override
	public int compareTo(WeightNode o) {
		//使node可以排序,这边的逻辑如果换了对应的上边的get也是需要换的;
		return this.weight-o.weight;
	}
	@Override
	public String toString() {
		return "Node: ["+weight+"]";
	}
}

=============================================================
插句话:怎么打印二叉树结构类似这种在这里插入图片描述点击这里:https://blog.csdn.net/weixin_45127611/article/details/105668479

这里继续:
其中需要注意的:

  1. 解码的时候,最后一位byte转换成对应的二进制str的时候我们现有解决办法是不行的(有时候会解码错误),报错信息是对应二进制匹配不到我们已知的赫夫曼二进制str造成的索引越界异常,这个问题是韩顺平老师代码也不太完善而我也找不到解决办法(评论说的加if是不行的你可以多试验几次);总之这个问题我有自己的解决办法,网上对于赫夫曼编码大多数是char[] 的形式,没有对应于byte[]的解决办法;
  2. 赫夫曼编码出来的时候就是对应于图片了什么的压缩(有大量重复压缩效果才好),如果用char[] 就以为着我们只能对于字符串进行压缩,也就失去了他最主要的意义-压缩byte[]
  3. 上述代码没有写对于图片等其他格式文件的压缩但是只要你稍微改进(只用把byte[]源改了就可以了)就能够完成对任意文件的压缩;不过这种压缩是对于存在大量重复数据是效果最明显的,对于某些重复数据少的,压缩结果可能比原来文件还大;对于ppt这些文件的格式原本就是压缩过的,是不适用的可能会造成格式错误;
  4. 如果看过韩老师的课会发现上述代码是韩老师讲的,不过存在一定的问题,具体问题就是 1 中所描述的,我们通过例子来看一下具体错在哪个地方;
    错误举例: 当输入字符串为"i like like like java do you like a java you are lihai"时,程序会报错,错误提示为:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 186
	at java.lang.AbstractStringBuilder.substring(AbstractStringBuilder.java:933)
	at java.lang.StringBuilder.substring(StringBuilder.java:76)
	at binaryTree.HuffmanCode.unZip(HuffmanCode.java:211)
	at binaryTree.HuffmanCode.main(HuffmanCode.java:44)

原因我们一步一步分析: 按理说,我们给出的赫夫曼编码形式的(java中byte存储的是对应的补码)

000001000110001110110010111001101011011111001110101110111111
在我们的map中能够找到唯一的与之对应的key并且在循环的时候总是能够到最后一个位置完全匹配完成
32=01
97=100
100=111010
101=1111
104=111011
105=101
106=00111
107=1100
108=000
111=0010
114=00110
117=11010
118=11011
121=11100
对他进行编码 [-88, -71, -24, -71, -24, -71, -23, -26, -29, -47, 60, 45, 34, -25, -79, 60, -36, 120, 90, 97, -67, 23, -71, 1]

可是这里我们可以发现,当最后不足8个字符的时候我们进行编码例如01得到的是 1 再将1进行解码得到的结果也是 1 而正确的应该是 01,所以得到的结果跟我们想要的不一致;这样就找到了问题的来源,如果解决呢,这里我提供两个思路:

  1. 我们得到赫夫曼编码后是每八位再次进行byte编码的,最后一个可能是不足八位的,我们可以用一个变量记录下来到底是多少位,进如果过我们得到的最后位数不匹配就可以手动在其前边加"0";
  2. 我们不用Map映射的方式做,在赫夫曼编码的百度百科中,他对于此的实现(用的是C)就是根据你的二进制赫夫曼编码来对应着那颗最小权重二叉树找,如果对应不上就从头结点和下一个二进制数开始找,不过具体到这个办法我们需要保证:通过byte拿到对应的二进制编码的时候都需要是八位的 好比 1我们需要拿到00000001 然后根据树来找,对应的0000找不到就接着直到找到了01为止(可以参考百度百科上C++代码),还有一种拿到byte对应二进制的方法(结果都是八位):Integer.toBinaryString((byteOne & 0xFF) + 0x100).substring(1),如果看不懂可以参考文章:点击这里

但是我没有用java实现第二种方式,不知道有没有问题,下面贴出第一种解决办法的代码:

package binaryTree;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.junit.Test;
/***
 * 这不是一个完整的赫夫曼编码(解码不太正确) 
 * 没有实现文件压缩和解压(主要是因为解码有时候会报错)
 * 这个实现byte类型转换成对应二进制string的方法不太好而且网上方法还没有这个好
 * @author 杰夫·王盖茨
 *
 */
public class HuffmanCode {
	private Map<Byte,String> huffManCodes ;
	private StringBuilder sb;
	private int leng; //用来记录如果最后一个byte不满八位具体是多少位
	public HuffmanCode() {
		huffManCodes = new HashMap<>();
		sb = new StringBuilder();
	}
	public static void main(String[] args) {
		String s = "i like like like java do you like a java you are lihai";
		byte[] bytes = s.getBytes();
		HuffmanCode huffmanCode = new HuffmanCode();
		/*
		 * WeightNode root = huffmanCode.getRoot(huffmanCode.getWeightNode(bytes)); //
		 * root.preList(); huffmanCode.getHuffmanCode(root, "", huffmanCode.sb);
		 * Iterator<Entry<Byte, String>> iterator =
		 * huffmanCode.huffManCodes.entrySet().iterator(); while(iterator.hasNext()) {
		 * Entry<Byte, String> next = iterator.next(); System.out.println(next); }
		 * huffmanCode.gethuffmanCode(root); Iterator<Entry<Byte, String>> iterator1 =
		 * huffmanCode.huffManCodes.entrySet().iterator(); while(iterator.hasNext()) {
		 * Entry<Byte, String> next = iterator1.next(); System.out.println(next); }
		 */
		byte[] zip = huffmanCode.zip(bytes);
		System.out.println(Arrays.toString(zip));
		byte[] unZip = huffmanCode.unZip(zip, huffmanCode.huffManCodes);
		System.out.println(new String(unZip));
	}
	/**
	 * 将byte【】 统计重复byte之后得到对应的data和权重并且将他们包装成list
	 * @param bytes
	 * @return
	 */
	public List<WeightNode> getWeightNode(byte[] bytes) {
		HashMap<Byte, Integer> hashMap = new HashMap<>();
		for(byte b : bytes) {
			if(hashMap.get(b)==null) {
				hashMap.put(b, 1);
			}else {
				hashMap.replace(b, hashMap.get(b)+1);
			}
		}
		ArrayList<WeightNode> arrayList = new ArrayList<>();
		Iterator<Entry<Byte, Integer>> iterator = hashMap.entrySet().iterator();
		while(iterator.hasNext()) {
			Entry<Byte, Integer> next = iterator.next();
			arrayList.add(new WeightNode(next.getKey(),next.getValue()));
		}
		return arrayList;
	}
	/**
	 * 将包装成的list生成一个赫夫曼树
	 * @param arrayList
	 * @return
	 */
	public WeightNode getRoot(List<WeightNode> arrayList) {
		while(arrayList.size() > 1) {
			Collections.sort(arrayList);

			WeightNode weightLeft = arrayList.get(0);
			WeightNode weightRight = arrayList.get(1);
			WeightNode parent = new WeightNode(weightLeft.weight+weightRight.weight);

			parent.left = weightLeft;
			parent.right = weightRight;

			arrayList.remove(weightRight);
			arrayList.remove(weightLeft);
			arrayList.add(parent);
		}
		return arrayList.get(0);
	}
	public Map<Byte,String> gethuffmanCode(WeightNode root){
		getHuffmanCode(root,"",sb);
		//这个sb还是""没有变
		System.out.println(sb.toString());
		System.out.println(huffManCodes);
		return huffManCodes;
	}
	/**
	 * 将给定结点下的所有叶子结点的对应的编码号作为string放入huffManCodes中
	 * @param node  结点
	 * @param code  是向左遍历还是向右遍历“0”是向左,“1”是向右
	 * @param sb  截止到上个结点处他的String
	 */
	public void getHuffmanCode(WeightNode node,String code,StringBuilder sb) {
		if(node == null) return;
		StringBuilder sb2 = new StringBuilder(sb);		
		sb2.append(code);
		if(node.data == null) {
			//向左递归
			getHuffmanCode(node.left,"0",sb2);
			//向右递归
			getHuffmanCode(node.right,"1",sb2);
		}else {
			huffManCodes.put(node.data, sb2.toString());
			System.out.print(sb2.toString());
		}
	}
	/**
	 * 给我一个最原始的byte数组我返回给你一个赫夫曼byte
	 * (这个byte是将原来byte排序后转换成相应的赫夫曼编码的数组之后再将八位一个转换成byte而形成的数组)
	 * @param bytes 最原始的byte数组
	 * @return 赫夫曼编码形成之后转byte的byte数组
	 */
	public byte[] zip(byte[] bytes) {
		StringBuilder strb = new StringBuilder();
		Map<Byte, String> gethuffmanCode = gethuffmanCode(getRoot(getWeightNode(bytes)));
		Iterator<Entry<Byte, String>> iterator = gethuffmanCode.entrySet().iterator(); 
		while(iterator.hasNext()) {
			Entry<Byte, String> next = iterator.next(); 
			System.out.println(next); 
		}
		for(byte b:bytes) {
			strb.append(gethuffmanCode.get(b));
		}
		int len = (strb.length()+7) / 8;
		byte[] huffManBytes = new byte[len];
		int index = 0;
		leng = strb.length() % 8;
		for(int i=0;i<strb.length();i += 8) {
			if(i+8<strb.length())
				huffManBytes[index] = (byte)Integer.parseInt(strb.substring(i, i+8),2);
			else {System.out.println("这里"+i+strb.substring(i));huffManBytes[index] = (byte)Integer.parseInt(strb.substring(i),2);}
			index++;
		}
		return huffManBytes;
	}
	/**
	 * 将一个byte 转成一个二进制的字符串
	 * @param flag 标志是否需要补高位如果是true ,表示需要补高位,如果是false表示不补, 如果是最后一个字节,无需补高位
	 * @param byteOne  传入的 byte
	 * @return 是该b 对应的二进制的字符串,(注意是按补码返回)
	 */
	public String huffManBinaryTonomarl(boolean flag,byte byteOne) {
		int temp = byteOne;
		String str;
		if(flag) {
			temp |= 256;
		}
		str = Integer.toBinaryString(temp);
		if(temp<0) return str.substring(str.length() - 8);
		if (flag) {
			return str.substring(str.length() - 8);
		} else {
			while(str.length()<leng) {
				str = "0" + str;
			}
			return str;
		}
	}
	/**
	 * 给我一个最终存储形式的数组之后,我可以返回给你需要的做string 的byte数组;
	 * @param source 最终存储形式的byte数组
	 * @param huffManCodes 你的对应的赫夫曼编码集
	 * @return 解码后的byte数组,可以用来new string 来还原了;
	 */
	public byte[] unZip(byte[] source,Map<Byte,String> huffManCodes) {
		StringBuilder sb = new StringBuilder();
		//遍历数组中的每一个byte 得到用byte存储前的赫夫曼数组
		for(int i=0;i<source.length;i++) {
			byte b = source[i];
			if(i==source.length-1)
				sb.append(huffManBinaryTonomarl(false,b));
			else sb.append(huffManBinaryTonomarl(true,b));
		}
		
		//用一个新的map将之前的key和val反过来
		Map<String,Byte> result = new HashMap<>();
		for(Map.Entry<Byte, String> entry:huffManCodes.entrySet()) {
			result.put(entry.getValue(), entry.getKey());
		}
		
		//这是整个通过这赫夫曼的数组拿到编码成赫夫曼之前的数组
		Byte byteOne;
		boolean flag = true;
		ArrayList<Byte> arr = new ArrayList<>();
		System.out.println(sb.length());
		for(int i=0;i<sb.length();) {
			int count = 1;
			flag = true;
			while(flag) {
				byteOne = result.get(sb.substring(i,i+count));
				if(byteOne==null) {
					count++;
				}else {
					arr.add(byteOne);
					flag = false;
				}
			}
			i += count;
		}
		
		byte[] b = new byte[arr.size()];
		for(int i=0;i<arr.size();i++) {
			b[i] = arr.get(i);
		}
		return b;
	}
}
class WeightNode implements Comparable<WeightNode>{
	public Byte data;  //这个才是对应的数据
	public WeightNode left;
	public WeightNode right;
	public int weight;  //权重就是出现了几次
	public WeightNode(int weight) {
		this.weight = weight;
	}
	public WeightNode(byte data, int weight) {
		this.data = data;
		this.weight = weight;
	}
	public void preList() {
		System.out.println(this);
		if(this.left!=null) left.preList();
		if(this.right!=null) right.preList();
	}
	@Override
	public int compareTo(WeightNode o) {
		//使node可以排序,这边的逻辑如果换了对应的上边的get也是需要换的;
		return this.weight-o.weight;
	}
	@Override
	public String toString() {
		return "Node: ["+weight+"]";
	}
}

解决方式二对应的动画演示,快速版
在这里插入图片描述
制作不易,欢迎点赞

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java实现赫夫曼树以及赫夫曼编码和解码(用byte[]) 的相关文章

  • 将一种类型的对象声明为另一种类型的实例有什么好处? [复制]

    这个问题在这里已经有答案了 可能的重复 Base b2 new Child 是什么意思 表示 https stackoverflow com questions 4447924 what does base b2 new child sig
  • 如何在log4j的配置文件中为文件附加器提供环境变量路径

    我有一个log4j xml配置文件 和一个RollingFileAppender我需要提供用于存储日志的文件路径 问题是我的代码将作为可运行的 jar 部署在 Unix 机器上 所以如果我传递这样的参数 value logs message
  • GET 请求的 Spring 注解

    这两种spring GET方法有什么区别呢 哪一种是首选方法 Component Scope request Path public class TestComponent GET Path hello public String prin
  • 在命令行java中突出显示文本[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一项任务是重新创建 unix cal 程序 除了一部分之外 相当简单 今天 它突出显示了该数字 我不知道该怎么做 关于如何在 Ja
  • JavaFX 2.0 FXML 子窗口

    经过多次搜索我发现了这个问题如何创建 javafx 2 0 应用程序 MDI https stackoverflow com questions 10915388 how to create a javafx 2 0 application
  • 如何将现有的 SQLite3 数据库导入 Room?

    好吧 我在桌面上使用 SQLite3 创建了一个只需要读取的某些信息的数据库 我正在制作的应用程序不需要在此表中插入或删除信息 我在 Room 数据库层上做了相当多的谷歌搜索 所有文档都需要在构建应用程序时在 Room 中创建一个新的数据库
  • 检查 IPv4 地址是否在私有范围内

    在 Python 中 使用 IPy 模块您可以执行以下操作 gt gt gt ip iptype PRIVATE 有没有一个库或简单的方法可以在 Java 中执行相同的操作 似乎不完全是但是InetAddress有一些 isXX 方法 例如
  • 具有 CRUD 功能的基于 Spring Web 的管理工具

    在 PHP Symfony 世界里有一个工具叫 Sonata Adminhttps sonata project org https sonata project org 基于 AdminLTE 模板 这是一款一体化管理工具 具有登录 菜单
  • java中的单链表和双向链表?

    在java中 哪个集合接口可以有效地实现单链表和双向链表 请问代码示例吗 毫不奇怪 实现双向链表的正确接口是 LinkedList 看Java文档 http docs oracle com javase 8 docs api java ut
  • Android WebView文件上传

    我正在开发一个 Android 应用程序 基本上它是一个WebView和一个进度条 Facebook 的移动网站 m facebook com 已加载到WebView 当我单击 选择文件 按钮上传图像时 没有任何反应 我已经尝试了所有的解决
  • 在 Junit 测试中使用 ReflectionTestUtils.setField()

    我是 JUnittesting 的新手 所以我有一个问题 谁能告诉我为什么我们使用ReflectionTestUtils setField 在我们的 Junit 测试示例中 正如评论中提到的 java 文档很好地解释了用法 但我还想给你们举
  • java swing:向 JTree 项目添加自定义图形按钮

    我想在 JTree 中的项目右侧添加一个带有小图标的附加按钮 这可以做到吗 如果是这样 怎么办 thanks Clamp 你在这方面成功了吗 我想做同样的事情 但很难让 JButton 响应用户 设置渲染器以显示按钮的过程很顺利 但所有鼠标
  • Java和手动执行finalize

    如果我打电话finalize 在我的程序代码中的一个对象上 JVM当垃圾收集器处理这个对象时仍然再次运行该方法吗 这是一个大概的例子 MyObject m new MyObject m finalize m null System gc 是
  • Android项目中使用java获取电脑的IP地址

    我在用ksoap2 android http code google com p ksoap2 android 我需要使用java获取IP地址 这样我就不必每次都手动输入它 我所说的 IP 地址是指 例如 如果我这样做ipconfig使用命
  • Java 中处理异步响应的设计模式

    我读过类似问答的答案 如何在 JAVA 中创建异步 HTTP 请求 https stackoverflow com questions 3142915 how do you create an asynchronous http reque
  • 如何将库添加到 LIBGDX 项目的依赖项 gradle

    一切都在问题中 我已经尝试了在 SO 和其他网站中找到的所有答案 但没有运气 这就是我迄今为止尝试过的 adding compile fileTree dir lib include jar 到我的 build gradle adding
  • Android Google 地图无法在当前主题中找到样式“mapViewStyle”

    添加谷歌地图视图时 我扩展了MapView 使用xml编辑器将其添加到活动中 并将我的谷歌地图api密钥手动添加到布局xml文件中 我的权限在清单文件中允许互联网 我想知道的是 在 xml 编辑器中 我收到错误 无法在当前主题中找到样式 m
  • 你能快速告诉我这个伪代码是否有意义吗?

    我相信我的代码现在是万无一失的 我现在将写出伪代码 但我确实有一个问题 为什么 DRJava 要求我返回 if 语句之外的内容 正如你所看到的 我为 ex 写了 return 1 只是因为它问了 但是它永远不会返回该值 谁可以给我解释一下这
  • 如何使用 Jest 从 ElasticSearch 获取索引列表

    我正在尝试使用 Jest 检索索引列表 但我只得到 Stats statistics new Stats Builder build result client execute statistics 如何从结果中检索索引列表 除了统计之外
  • 使用 AmazonSNSClient 发送短信时的授权

    aws 官方文档如何发送短信 http docs aws amazon com sns latest dg sms publish to phone html使用 java 中的 aws SDK 非常简单 但是 当发送如底部示例所示的消息时

随机推荐

  • 利用逆矩阵解线性方程组_经典Jacobi方法用于求解矩阵特征值

    1 引言 求解线性方程组在许多领域中都有重要应用 写成矩阵的形式 求解 可以写成 这里需要求解矩阵 的逆 线性代数 中给出的方法主要有两类 1 设置增广矩阵 利用高斯消元法 通过初等行列变换可以求 但这种方法不利于使用计算机计算 2 利用矩
  • Bootstarp入门教程(2) 概述

    概述 深入了解Bootstrap底层结构的关键部分 包括我们让web开发变得更好 更快 更强壮的最佳实践 1 HTML5文档类型 Bootstrap使用到的某些HTML元素和CSS属性需要将页面设置为HTML5文档类型
  • 【git】git compare with branch 一样的代码 但是却标识不一样 成块显示 Git 比较 不准确

    文章目录 1 概述 本文地址 https blog csdn net qq 21383435 article details 119483593 1 概述 我一个flink项目做git比较 用flink 1 9版本的对比1 13版本的 发现
  • Go_配置系统环境MacOS(M1)

    在MacOS下和JDK一样 配不配环境其实MacOS都是可以检测的到的 安装好以后直接输入go version是一样可以的 因为都是使用开发工具的 在开发工具里配置的话是样的 如果有习惯的话就配置一下吧 下载安装及配置环境 1 官网下载 h
  • 基于QT开发的跨平台文件校验工具

    QtFileHash QtFileHash是一款基于Qt开发的跨平台文件校验工具 支持Windows Linux MacOS平台 支持MD4 MD5 SHA1 SHA256 SHA512算法 项目地址 https github com zd
  • Linux下共享文件夹的位置在哪

    大家都知道vm这个虚拟机有个共享文件夹的功能 怎么设置这个共享文件夹在图示位置 但问题是在虚拟机里面这个文件夹的位置在哪里呢 我上网找了半天也没有解决方案 这里直接告诉大家 应该是被隐藏了但是我用 ls al看也没有 直接在用户 unbun
  • python 图片的读取、显示、处理与保存(PIL和OpenCV)

    目录 0 前言 1 图片读取 显示和保存 2 PIL与cv2相互转换 3 处理与保存 3 1 裁剪 3 2 绘制矩形 参考链接 0 前言 先撇开matplotlib不谈 在python江湖用于读取图片的主要为两个门派 分别是PIL家族 fr
  • Object.is()

    ES5 比较两个值是否相等 只有两个运算符 相等运算符 两个 和严格相等运算符 三个 它们都有缺点 前者会自动转换数据类型 后者的NaN不等于自身 以及 0等于 0 JavaScript 缺乏一种运算 在所有环境中 只要两个值是一样的 它们
  • 社区版VS2019下配置Opencv4.5.3

    1 下载Opencv 我下的是4 5 3 下载地址 https sourceforge net projects opencvlibrary 解压安装 没记错的话是 exe 文件 双击安装 没啥要注意的 选好路径就行 安装完成 安装完成后是
  • STM32——OLED调试工具与显示屏

    文章目录 一 调试工具 二 OLED简介 三 硬件电路接线图 四 OLED驱动函数 五 源码 OLED c OLED h OLED Font h 一 调试工具 调试方式 串口调试 通过串口通信 将调试信息发送到电脑端 电脑使用串口助手显示调
  • 外盘国际期货

    什么是交易 有人说交易就是买卖 从字面看这没啥毛病 概括性也很强 但我们不妨再细细掰扯下 交易 的深层含义 我们可以先将 交易 二字拆开来逐字理解与分析其意 交 象形字 一个人 最早出现在甲骨文 本义 动词 反叉两腿站立 说文解字 里泛指交
  • Docker修改已有镜像,并打包生成新的镜像tar文件

    文章目录 一 加载镜像 二 运行镜像 三 对镜像进行修改 四 将容器打包成新的镜像 五 将新的镜像保存为tar包 一 加载镜像 在镜像目录下打开linux终端 输入如下命令 docker load i 镜像文件名 tar 二 运行镜像 镜像
  • shineblink HC-SR505人体红外感应传感器

    HC SR505人体红外感应传感器 一 本例程实现功能 二 HC SR505传感器介绍 三 接线图 四 完整代码 五 代码运行结果 一 本例程实现功能 通过HC SR505人体红外感应传感器模块感应人体的出现 当感应到人体时 Core电路板
  • 支持二级汉字的 php 汉字助记码生成

    gbk2312 编码范围共94区 0 55区为一级汉字 是按照拼音顺序排列的 可以按照编码区间确定汉字的拼音 但是 56 区以后是按笔画顺序排列的 所以只能用对照表来确定拼音 鉴于目前我找不到现成的代码 固整理了一份 测试可用 PHP 汉字
  • 【操作系统】王道考研 p11 线程概念、多线程模型

    视频 知识总览 是什么 为什么 进程是程序的一次执行 但有些功能不是由一个程序顺序处理就能实现的 有的进程可能需要 同时 做很多事情 而传统的进程只能串行地执行一系列程序 因此 引入 线程 来增加并发度 引入线程后 线程成为了程序执行流的最
  • esp8266连接mqtt时client.publish出现的小问题

    client publish发送变化数据的问题 温湿度为例 先是获取数据 加入我们获取的湿度为humidity 温度为temp 下一步就是我们的发送环节啦 client publish 主题 内容 我们字节将内容替换是会报错的 我们需要对数
  • qemu-guest-agent windows下的监控开发

    windows下的qemu guest agent 简称qga 的名字叫做qemu guest agent win32 目前最新版的版本号是qemu guest agent win32 0 12 1 2 2 355 el6 4 9 x86
  • 【踩坑】三种方式解决 Homebrew failing to install - fatal: not in a git directory

    问题描述 解决方法一 添加安全目录 没有测试 git config global add safe directory opt homebrew Library Taps homebrew homebrew git config globa
  • 动手写docker中遇到的问题合集

    fork exec usr bin sh operation not permitted exit status 1 我的环境 win10 wsl2 ubuntu20 04 解决方案 设置wsl默认用户为root sudo nano etc
  • java实现赫夫曼树以及赫夫曼编码和解码(用byte[])

    首先对于赫夫曼编码有个大概的理解 赫夫曼编码 Huffman Coding 又称霍夫曼编码 是一种编码方式 可变字长编码 VLC 的一种 Huffman于1952年提出一种编码方法 该方法完全依据字符出现概率来构造异字头的平均长度最短的码字