基于C#实现赫夫曼树

赫夫曼树又称最优二叉树,也就是带权路径最短的树,对于赫夫曼树,我想大家对它是非常的熟悉,也知道它的应用场景,但是有没有自己亲手写过,这个我就不清楚了,不管以前写没写,这一篇我们来玩一把。

一、概念

赫夫曼树里面有几个概念,也是非常简单的,先来看下面的图:
image.png

  1. 节点的权: 节点中红色部分就是权,在实际应用中,我们用“字符”出现的次数作为权。
  2. 路径长度:可以理解成该节点到根节点的层数,比如:“A”到根节点的路径长度为 3。
  3. 树的路径长度:各个叶子节点到根节点的路径长度总和,用 WPL 标记。

最后我们要讨论的的赫夫曼树也就是带权路径长度最小的一棵树。

二、构建

由于要使 WPL 最短,赫夫曼树的构建采用自低向上的方式,这里我们采用小根堆来存放当前需要构建的各个节点,我们的方式是每次从小根堆中取出最小的两个节点,合并后放入堆中,然后继续取两个最小的节点,一直到小根堆为空,最后我们采用自底向上构建的赫夫曼树也就完毕了。
image.png
好了,赫夫曼树的典型应用就是在数据压缩方面,下面我们就要在赫夫曼树上面放入赫夫曼编码了,我们知道普通的 ASCII 码是采用等长编码的,即每个字符都采用 2 个字节,而赫夫曼编码的思想就是采用不等长的思路,权重高的字符靠近根节点,权重低的字符远离根节点,标记方式为左孩子“0”,右孩子“1”,如下图。
image.png
从图中我们可以看到各个字符的赫夫曼编码了,获取字符的编码采用从根往下的方式收集路径上的‘0,1’,如:

A:110。B:111。C:0。D:10。

最后我们来比较他们的 WPL 的长度: ASCII 码=102+202+402+802=300
赫夫曼码=103+203+402+801=250
可以看到,赫夫曼码压缩了 50 个 0,1 字符。

三、代码

1、树节点

我们采用 7 元节点,其中 parent 方便我们在 DFS 的时候找到从叶子节点到根节点的路径上的赫夫曼编码。

 #region 赫夫曼节点/// <summary>/// 赫夫曼节点/// </summary>public class Node{/// <summary>/// 左孩子/// </summary>public Node left;/// <summary>/// 右孩子/// </summary>public Node right;/// <summary>/// 父节点/// </summary>public Node parent;/// <summary>/// 节点字符/// </summary>public char c;/// <summary>/// 节点权重/// </summary>public int weight;//赫夫曼“0"or“1"public char huffmancode;/// <summary>/// 标记是否为叶子节点/// </summary>public bool isLeaf;}#endregion

2、构建赫夫曼树(Build)

上面也说了,构建赫夫曼编码树我们采用小根堆的形式构建,构建完后,我们采用 DFS 的方式统计各个字符的编码,复杂度为 N*logN。

 #region 构建赫夫曼树/// <summary>/// 构建赫夫曼树/// </summary>public void Build(){//构建while (queue.Count() > 0){//如果只有一个节点,则说明已经到根节点了if (queue.Count() == 1){root = queue.Dequeue().t;break;}//节点1var node1 = queue.Dequeue();//节点2var node2 = queue.Dequeue();//标记左孩子node1.t.huffmancode = '0';//标记为右孩子node2.t.huffmancode = '1';//判断当前节点是否为叶子节点,hufuman无度为1点节点(方便计算huffman编码)if (node1.t.left == null)node1.t.isLeaf = true;if (node2.t.left == null)node2.t.isLeaf = true;//父节点root = new Node();root.left = node1.t;root.right = node2.t;root.weight = node1.t.weight + node2.t.weight;//当前节点为根节点node1.t.parent = node2.t.parent = root;//将当前节点的父节点入队列queue.Eequeue(root, root.weight);}//深度优先统计各个字符的编码DFS(root);}#endregion

3、编码(Encode,Decode)

树构建起来后,我会用字典来保存字符和”赫夫曼编码“的对应表,然后拿着明文或者密文对着编码表翻译就行了, 复杂度 O(N)。

 #region 赫夫曼编码/// <summary>/// 赫夫曼编码/// </summary>/// <returns></returns>public string Encode(){StringBuilder sb = new StringBuilder();foreach (var item in word){sb.Append(huffmanEncode[item]);}return sb.ToString();}#endregion#region 赫夫曼解码/// <summary>/// 赫夫曼解码/// </summary>/// <returns></returns>public string Decode(string str){StringBuilder decode = new StringBuilder();string temp = string.Empty;for (int i = 0; i < str.Length; i++){temp += str[i].ToString();//如果包含 O(N)时间if (huffmanDecode.ContainsKey(temp)){decode.Append(huffmanDecode[temp]);temp = string.Empty;}}return decode.ToString();}#endregion

最后我们做个例子,压缩 9M 的文件,看看到底能压缩多少?

public static void Main(){StringBuilder sb = new StringBuilder();for (int i = 0; i < 1 * 10000; i++){sb.Append("人民网北京12月8日电 (记者 宋心蕊) 北京时间8日晚的央视《新闻联播》节目出现了直播失误。上一条新闻尚未播放完毕时,播就将画面切换回了演播间,主播李梓萌开始播报下一条新闻,导致两条新闻出现了“混音”播出。央视新闻官方微博账号在21点09分发布了一条致歉微博:【致歉】今晚《新闻联播》因导播员口令失误,导致画面切换错误,特此向观众朋友表示歉意。央视特约评论员杨禹在个人微博中写道:今晚《新闻联播》出了个切换错误,@央视新闻 及时做了诚恳道歉。联播一直奉行“金标准”,压力源自全社会的高要求。其实报纸亦都有“勘误”一栏,坦诚纠错与道歉。《新闻联播》是中国影响力最大的电视新闻节目。它有不可替代的符号感,它有失误,更有悄然的进步。新的改进正在或即将发生,不妨期待");}File.WriteAllText(Environment.CurrentDirectory + "//1.txt", sb.ToString());Huffman huffman = new Huffman(sb.ToString());Stopwatch watch = Stopwatch.StartNew();huffman.Build();watch.Stop();Console.WriteLine("构建赫夫曼树耗费:{0}", watch.ElapsedMilliseconds);//将8位二进制转化为ascII码var s = huffman.Encode();var remain = s.Length % 8;List<char> list = new List<char>();var start = 0;for (int i = 8; i < s.Length; i = i + 8){list.Add((char)Convert.ToInt32(s.Substring(i - 8, 8), 2));start = i;}var result = new String(list.ToArray());//当字符编码不足8位时, 用‘艹'来标记,然后拿出’擦‘以后的所有0,1即可result += "艹" + s.Substring(start);File.WriteAllText(Environment.CurrentDirectory + "//2.txt", result);Console.WriteLine("压缩完毕!");Console.Read();//解码var str = File.ReadAllText(Environment.CurrentDirectory + "//2.txt");sb.Clear();for (int i = 0; i < str.Length; i++){int ua = (int)str[i];//说明已经取完毕了  用'艹'来做标记if (ua == 33401)sb.Append(str.Substring(i));elsesb.Append(Convert.ToString(ua, 2).PadLeft(8, '0'));}var sss = huffman.Decode(sb.ToString());Console.Read();}

image.png
看看,将 9M 的文件压缩到了 4M。
主程序:

 using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Diagnostics;using System.Threading;using System.IO;namespace ConsoleApplication2{public class Program{public static void Main(){StringBuilder sb = new StringBuilder();for (int i = 0; i < 1 * 10000; i++){sb.Append("人民网北京12月8日电 (记者 宋心蕊) 北京时间8日晚的央视《新闻联播》节目出现了直播失误。上一条新闻尚未播放完毕时,播就将画面切换回了演播间,主播李梓萌开始播报下一条新闻,导致两条新闻出现了“混音”播出。央视新闻官方微博账号在21点09分发布了一条致歉微博:【致歉】今晚《新闻联播》因导播员口令失误,导致画面切换错误,特此向观众朋友表示歉意。央视特约评论员杨禹在个人微博中写道:今晚《新闻联播》出了个切换错误,@央视新闻 及时做了诚恳道歉。联播一直奉行“金标准”,压力源自全社会的高要求。其实报纸亦都有“勘误”一栏,坦诚纠错与道歉。《新闻联播》是中国影响力最大的电视新闻节目。它有不可替代的符号感,它有失误,更有悄然的进步。新的改进正在或即将发生,不妨期待");}File.WriteAllText(Environment.CurrentDirectory + "//1.txt", sb.ToString());Huffman huffman = new Huffman(sb.ToString());Stopwatch watch = Stopwatch.StartNew();huffman.Build();watch.Stop();Console.WriteLine("构建赫夫曼树耗费:{0}", watch.ElapsedMilliseconds);//将8位二进制转化为ascII码var s = huffman.Encode();var remain = s.Length % 8;List<char> list = new List<char>();var start = 0;for (int i = 8; i < s.Length; i = i + 8){list.Add((char)Convert.ToInt32(s.Substring(i - 8, 8), 2));start = i;}var result = new String(list.ToArray());//当字符编码不足8位时, 用‘艹'来标记,然后拿出’擦‘以后的所有0,1即可result += "艹" + s.Substring(start);File.WriteAllText(Environment.CurrentDirectory + "//2.txt", result);Console.WriteLine("压缩完毕!");Console.Read();//解码var str = File.ReadAllText(Environment.CurrentDirectory + "//2.txt");sb.Clear();for (int i = 0; i < str.Length; i++){int ua = (int)str[i];//说明已经取完毕了  用'艹'来做标记if (ua == 33401)sb.Append(str.Substring(i));elsesb.Append(Convert.ToString(ua, 2).PadLeft(8, '0'));}var sss = huffman.Decode(sb.ToString());Console.Read();}}public class Huffman{#region 赫夫曼节点/// <summary>/// 赫夫曼节点/// </summary>public class Node{/// <summary>/// 左孩子/// </summary>public Node left;/// <summary>/// 右孩子/// </summary>public Node right;/// <summary>/// 父节点/// </summary>public Node parent;/// <summary>/// 节点字符/// </summary>public char c;/// <summary>/// 节点权重/// </summary>public int weight;//赫夫曼“0"or“1"public char huffmancode;/// <summary>/// 标记是否为叶子节点/// </summary>public bool isLeaf;}#endregionPriorityQueue<Node> queue = new PriorityQueue<Node>();/// <summary>/// 编码对应表(加速用)/// </summary>Dictionary<char, string> huffmanEncode = new Dictionary<char, string>();/// <summary>/// 解码对应表(加速用)/// </summary>Dictionary<string, char> huffmanDecode = new Dictionary<string, char>();/// <summary>/// 明文/// </summary>string word = string.Empty;public Node root = new Node();public Huffman(string str){this.word = str;Dictionary<char, int> dic = new Dictionary<char, int>();foreach (var s in str){if (dic.ContainsKey(s))dic[s] += 1;elsedic[s] = 1;}foreach (var item in dic.Keys){var node = new Node(){c = item,weight = dic[item]};//入队queue.Eequeue(node, dic[item]);}}#region 构建赫夫曼树/// <summary>/// 构建赫夫曼树/// </summary>public void Build(){//构建while (queue.Count() > 0){//如果只有一个节点,则说明已经到根节点了if (queue.Count() == 1){root = queue.Dequeue().t;break;}//节点1var node1 = queue.Dequeue();//节点2var node2 = queue.Dequeue();//标记左孩子node1.t.huffmancode = '0';//标记为右孩子node2.t.huffmancode = '1';//判断当前节点是否为叶子节点,hufuman无度为1点节点(方便计算huffman编码)if (node1.t.left == null)node1.t.isLeaf = true;if (node2.t.left == null)node2.t.isLeaf = true;//父节点root = new Node();root.left = node1.t;root.right = node2.t;root.weight = node1.t.weight + node2.t.weight;//当前节点为根节点node1.t.parent = node2.t.parent = root;//将当前节点的父节点入队列queue.Eequeue(root, root.weight);}//深度优先统计各个字符的编码DFS(root);}#endregion#region 赫夫曼编码/// <summary>/// 赫夫曼编码/// </summary>/// <returns></returns>public string Encode(){StringBuilder sb = new StringBuilder();foreach (var item in word){sb.Append(huffmanEncode[item]);}return sb.ToString();}#endregion#region 赫夫曼解码/// <summary>/// 赫夫曼解码/// </summary>/// <returns></returns>public string Decode(string str){StringBuilder decode = new StringBuilder();string temp = string.Empty;for (int i = 0; i < str.Length; i++){temp += str[i].ToString();//如果包含 O(N)时间if (huffmanDecode.ContainsKey(temp)){decode.Append(huffmanDecode[temp]);temp = string.Empty;}}return decode.ToString();}#endregion#region 深度优先遍历子节点,统计各个节点的赫夫曼编码/// <summary>/// 深度优先遍历子节点,统计各个节点的赫夫曼编码/// </summary>/// <returns></returns>public void DFS(Node node){if (node == null)return;//遍历左子树DFS(node.left);//遍历右子树DFS(node.right);//如果当前叶节点if (node.isLeaf){string code = string.Empty;var temp = node;//回溯的找父亲节点的huffmancode LgN 的时间while (temp.parent != null){//注意,这里最后形成的 “反过来的编码”code += temp.huffmancode;temp = temp.parent;}var codetemp = new String(code.Reverse().ToArray());huffmanEncode.Add(node.c, codetemp);huffmanDecode.Add(codetemp, node.c);}}#endregion}}

小根堆:

 using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Diagnostics;using System.Threading;using System.IO;namespace ConsoleApplication2{public class PriorityQueue<T> where T : class{/// <summary>/// 定义一个数组来存放节点/// </summary>private List<HeapNode> nodeList = new List<HeapNode>();#region 堆节点定义/// <summary>/// 堆节点定义/// </summary>public class HeapNode{/// <summary>/// 实体数据/// </summary>public T t { get; set; }/// <summary>/// 优先级别 1-10个级别 (优先级别递增)/// </summary>public int level { get; set; }public HeapNode(T t, int level){this.t = t;this.level = level;}public HeapNode() { }}#endregion#region  添加操作/// <summary>/// 添加操作/// </summary>public void Eequeue(T t, int level = 1){//将当前节点追加到堆尾nodeList.Add(new HeapNode(t, level));//如果只有一个节点,则不需要进行筛操作if (nodeList.Count == 1)return;//获取最后一个非叶子节点int parent = nodeList.Count / 2 - 1;//堆调整UpHeapAdjust(nodeList, parent);}#endregion#region 对堆进行上滤操作,使得满足堆性质/// <summary>/// 对堆进行上滤操作,使得满足堆性质/// </summary>/// <param name="nodeList"></param>/// <param name="index">非叶子节点的之后指针(这里要注意:我们/// 的筛操作时针对非叶节点的)/// </param>public void UpHeapAdjust(List<HeapNode> nodeList, int parent){while (parent >= 0){//当前index节点的左孩子var left = 2 * parent + 1;//当前index节点的右孩子var right = left + 1;//parent子节点中最大的孩子节点,方便于parent进行比较//默认为left节点var min = left;//判断当前节点是否有右孩子if (right < nodeList.Count){//判断parent要比较的最大子节点min = nodeList[left].level < nodeList[right].level ? left : right;}//如果parent节点大于它的某个子节点的话,此时筛操作if (nodeList[parent].level > nodeList[min].level){//子节点和父节点进行交换操作var temp = nodeList[parent];nodeList[parent] = nodeList[min];nodeList[min] = temp;//继续进行更上一层的过滤parent = (int)Math.Ceiling(parent / 2d) - 1;}else{break;}}}#endregion#region 优先队列的出队操作/// <summary>/// 优先队列的出队操作/// </summary>/// <returns></returns>public HeapNode Dequeue(){if (nodeList.Count == 0)return null;//出队列操作,弹出数据头元素var pop = nodeList[0];//用尾元素填充头元素nodeList[0] = nodeList[nodeList.Count - 1];//删除尾节点nodeList.RemoveAt(nodeList.Count - 1);//然后从根节点下滤堆DownHeapAdjust(nodeList, 0);return pop;}#endregion#region  对堆进行下滤操作,使得满足堆性质/// <summary>/// 对堆进行下滤操作,使得满足堆性质/// </summary>/// <param name="nodeList"></param>/// <param name="index">非叶子节点的之后指针(这里要注意:我们/// 的筛操作时针对非叶节点的)/// </param>public void DownHeapAdjust(List<HeapNode> nodeList, int parent){while (2 * parent + 1 < nodeList.Count){//当前index节点的左孩子var left = 2 * parent + 1;//当前index节点的右孩子var right = left + 1;//parent子节点中最大的孩子节点,方便于parent进行比较//默认为left节点var min = left;//判断当前节点是否有右孩子if (right < nodeList.Count){//判断parent要比较的最大子节点min = nodeList[left].level < nodeList[right].level ? left : right;}//如果parent节点小于它的某个子节点的话,此时筛操作if (nodeList[parent].level > nodeList[min].level){//子节点和父节点进行交换操作var temp = nodeList[parent];nodeList[parent] = nodeList[min];nodeList[min] = temp;//继续进行更下一层的过滤parent = min;}else{break;}}}#endregion#region 获取元素并下降到指定的level级别/// <summary>/// 获取元素并下降到指定的level级别/// </summary>/// <returns></returns>public HeapNode GetAndDownPriority(int level){if (nodeList.Count == 0)return null;//获取头元素var pop = nodeList[0];//设置指定优先级(如果为 MinValue 则为 -- 操作)nodeList[0].level = level == int.MinValue ? --nodeList[0].level : level;//下滤堆DownHeapAdjust(nodeList, 0);return nodeList[0];}#endregion#region 获取元素并下降优先级/// <summary>/// 获取元素并下降优先级/// </summary>/// <returns></returns>public HeapNode GetAndDownPriority(){//下降一个优先级return GetAndDownPriority(int.MinValue);}#endregion#region 返回当前优先队列中的元素个数/// <summary>/// 返回当前优先队列中的元素个数/// </summary>/// <returns></returns>public int Count(){return nodeList.Count;}#endregion}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/165553.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【LeetCode刷题笔记】DFSBFS(二)

994. 腐烂的橘子(树/图的BFS问题) 解题思路: 多源BFS ,首选找到 所有的腐烂的橘子 ,放入队列中,然后进行 BFS 广搜,广搜的 层数 - 1 就是所需要花费的分钟数。 在最开始先扫描一遍二维数组,将所有的 腐烂的橘子 加入 队列 ,同时统计新鲜橘子的数量 <

Blender烘焙AO操作及对应的python代码

&#xff08;一&#xff09;Blender软件操作 1. 导入模型&#xff08;这里省略&#xff09; 2. 材质设置 模型使用的所有材质都需要删除Surface Shader&#xff0c;没有其他多余的计算&#xff0c;可以大量缩短烘焙时间。删除之后的只留下一个材质输出节点&#xff0c;如图所…

CentOS Stream 9系统Cgroup问题处理

安装docker容器启动失败 之前适配过Ubuntu系统的容器&#xff0c;由于版本比较高&#xff0c;没有挂载Cgroup的路径。这次使用Centos Stream 9系统安装docker容器时也遇到了这个情况。由于处理方式有些不一样&#xff0c;所以记录一下。 这是docker容器启动过报错的输出日志。…

Haclon简介及数据类型

Haclon简介 HALCON是由德国MVtec公司开发的机器视觉算法包&#xff0c;它由一千多个各自独立的函数&#xff08;算子&#xff09;构成&#xff0c;其中除了包含各类滤波、色彩以及几何、数学转换、形态学计算分析、图像校正&#xff0c;目标分类辨识、形状搜寻等基本的图像处理…

C/C++文件操作————写文件与读文件以及通讯录的改进 (保姆级教学)

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言程序设计————KTV C语言小游戏 C语言进阶 C语言刷题 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力&#xff0c;一起奔赴大厂。 目录 1.前言 2.写文件函数与读文件函数 …

多个JDK版本可以吗:JDK17、JDK19、JDK1.8轻松切换(无坑版)小白也可以看懂

多个版本JDK切换 多个JDK&#xff1a;JDK17、JDK19、JDK1.8轻松切换&#xff08;无坑版&#xff09;小白也可以看懂 提示&#xff1a;看了网上很多教程&#xff0c;5w观看、32w观看、几千观看的&#xff0c;多多少少带点坑&#xff0c;这里我就把踩过的坑都给抹了 文章目录 多…

「Verilog学习笔记」不重叠序列检测

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 题目要求检测a的序列&#xff0c;a为单bit输入&#xff0c;每个时刻可能具有不同的值&#xff0c; 当连续的六个输入值符合目标序列表示序列匹配&#xff0c;当六个输入值的…

Redisson分布式锁源码解析、集群环境存在的问题

一、使用Redisson步骤 Redisson各个锁基本所用Redisson各个锁基本所用Redisson各个锁基本所用 二、源码解析 lock锁 1&#xff09; 基本思想&#xff1a; lock有两种方法 一种是空参 另一种是带参 * 空参方法&#xff1a;会默认调用看门狗的过期时间30*1000&…

内网穿透的应用-如何在本地安装Flask,以及将其web界面发布到公网上并进行远程访问

轻量级web开发框架&#xff1a;Flask本地部署及实现公网访问界面 文章目录 轻量级web开发框架&#xff1a;Flask本地部署及实现公网访问界面前言1. 安装部署Flask2. 安装Cpolar内网穿透3. 配置Flask的web界面公网访问地址4. 公网远程访问Flask的web界面 前言 本篇文章讲解如何…

『亚马逊云科技产品测评』活动征文|通过Lightsail搭建个人笔记

提示&#xff1a;授权声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 Developer Centre, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道 文章目录 前言实践知识储备Lightsail介绍Leanote介绍实践…

VSCode插件koroFileHeader的使用。

文章目录 前言一、koroFileHeader是什么&#xff1f;二、使用步骤1.安装1.配置2.食用 前言 今天的天气还不错&#xff0c;真是金风玉露一相逢&#xff0c;便胜却人间无数&#xff0c;写篇博客玩玩&#xff0c;主题&#xff1a;注释。注释的本质就是对代码的解释和说明&#xf…

STM32_6(TIM)

TIM定时器&#xff08;第一部分&#xff09; TIM&#xff08;Timer&#xff09;定时器定时器可以对输入的时钟进行计数&#xff0c;并在计数值达到设定值时触发中断16位计数器、预分频器、自动重装寄存器的时基单元&#xff0c;在72MHz计数时钟下可以实现最大59.65s的定时不仅…

在游戏开发中,实时渲染和离线渲染对于游戏平衡的影响有哪些?

实时渲染和离线渲染对游戏平衡有那些影响呢&#xff1f;在游戏开发中&#xff0c;渲染方式的选择对游戏的整体表现和玩家体验有着至关重要的作用。那么&#xff0c;实时渲染和离线渲染究竟有哪些利弊呢&#xff1f; 一、实时渲染 实时渲染&#xff0c;顾名思义&#xff0c;是…

Ubuntu 1.84.2Visual Studio Code 下载配置与vscode查看内存Hex Editor插件,简单易懂

目录 前言 一 首先我为啥要重装Vs Code呢&#xff1f; 二 下载1.84.2Visual Studio Code 三 配置Vscode终端字体 四 安装插件 前言 这是一篇将老版本的VsCode下载至最新版的博文&#xff0c;从下载到调试全篇 一 首先我为啥要重装Vs Code呢&#xff1f; 因为我想安装这个…

1、postman的安装及使用

一、安装、登录 1.安装 下载地址 2.注册登录&#xff08;保存云服务进度&#xff09; 二、界面介绍 三、执行接口测试页面 请求页签&#xff1a; 1、params&#xff1a;当是get请求时&#xff0c;通过params传参 2、authorization&#xff1a;鉴权 3、headers&#xff1…

idea 26 个天花板技巧

1、 查看代码历史版本&#xff1b;2、 调整idea的虚拟内存&#xff1a;&#xff1b;3、 idea设置成eclipse的快捷键&#xff1b;4、 设置提示词忽略大小写&#xff1b;5、 关闭代码检查&#xff1b;6、 设置文档注释模板&#xff1b;7、 显示方法分隔符&#xff1b;8、 设置多行…

DAOS低时延与高性能RDMA网络

什么是RDMA RDMA&#xff08;Remote Direct Memory Access&#xff09;远程直接内存访问是一种技术&#xff0c;它使两台联网的计算机能够在主内存中交换数据&#xff0c;而无需依赖任何一台计算机的处理器、缓存或操作系统。与基于本地的直接内存访问 ( DMA ) 一样&#xff0c…

03-详细介绍Stream及其常用API

Stream API Stream API(java.util.stream)把真正的函数式编程风格引入到Java中,可以极大地提高程序员生产力&#xff0c;让程序员写出高效、简洁的代码 实际开发中项目中多数数据源都是来自MySQL、Oracle等关系型数据库,还有部分来自MongDB、Redis等非关系型数据库 从关系型…

1.测试基础

目录 一、测试基础 1.软件测试中基础信息定义 2.测试主流技能 3.常见的测试分类 3.1按阶段划分 3.2按代码可见度划分 3.3其他 4.测试模型 5.测试流程 6.测试用例 二、用例设计方法 2.1等价类 2.2 边界值 2.3判定表法 2.4场景法 2.5错误推测法 三、缺陷管理 1…