基于C#实现赫夫曼树
赫夫曼树又称最优二叉树,也就是带权路径最短的树,对于赫夫曼树,我想大家对它是非常的熟悉,也知道它的应用场景,但是有没有自己亲手写过,这个我就不清楚了,不管以前写没写,这一篇我们来玩一把。
一、概念
赫夫曼树里面有几个概念,也是非常简单的,先来看下面的图:

- 节点的权: 节点中红色部分就是权,在实际应用中,我们用“字符”出现的次数作为权。
- 路径长度:可以理解成该节点到根节点的层数,比如:“A”到根节点的路径长度为 3。
- 树的路径长度:各个叶子节点到根节点的路径长度总和,用 WPL 标记。
最后我们要讨论的的赫夫曼树也就是带权路径长度最小的一棵树。
二、构建
由于要使 WPL 最短,赫夫曼树的构建采用自低向上的方式,这里我们采用小根堆来存放当前需要构建的各个节点,我们的方式是每次从小根堆中取出最小的两个节点,合并后放入堆中,然后继续取两个最小的节点,一直到小根堆为空,最后我们采用自底向上构建的赫夫曼树也就完毕了。

好了,赫夫曼树的典型应用就是在数据压缩方面,下面我们就要在赫夫曼树上面放入赫夫曼编码了,我们知道普通的 ASCII 码是采用等长编码的,即每个字符都采用 2 个字节,而赫夫曼编码的思想就是采用不等长的思路,权重高的字符靠近根节点,权重低的字符远离根节点,标记方式为左孩子“0”,右孩子“1”,如下图。

从图中我们可以看到各个字符的赫夫曼编码了,获取字符的编码采用从根往下的方式收集路径上的‘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();}

看看,将 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}}
相关文章:
基于C#实现赫夫曼树
赫夫曼树又称最优二叉树,也就是带权路径最短的树,对于赫夫曼树,我想大家对它是非常的熟悉,也知道它的应用场景,但是有没有自己亲手写过,这个我就不清楚了,不管以前写没写,这一篇我们…...
Android 13.0 app进程保活白名单功能实现
1.前言 在13.0的系统rom产品开发中,在某些重要的app即使进入后台,产品需求要求也不想被系统杀掉进程,需要app长时间保活,就是app进程保活白名单功能的实现, 所以需要在系统杀进程的时候不杀掉白名单的进程,接下来就看怎么样来实现这些功能 2.app进程保活白名单功能实…...
查找学习笔记
1、静态查找表 以下查找的索引均从1开始 (1)顺序查找(带哨兵) #include<iostream> #include<vector>using namespace std;int search(vector<int> arr, int key) {arr[0] key;int i;for (i arr.size() - 1…...
Qt QIODevice介绍
作者:令狐掌门 技术交流QQ群:675120140 csdn博客:https://mingshiqiang.blog.csdn.net/ 文章目录 主要功能用法示例读取数据写入数据使用数据流基于套接字的读写注意事项QIODevice 是 Qt 中所有输入/输出设备的抽象基类。它为派生类提供了一组标准的接口用于读写数据。这些派…...
python -opencv 中值滤波 ,均值滤波,高斯滤波实战
python -opencv 中值滤波 ,均值滤波,高斯滤波实战 cv2.blur-均值滤波 cv2.medianBlur-中值滤波 cv2.GaussianBlur-高斯滤波 直接看代码吧,代码很简单: import copy import math import matplotlib.pyplot as plt import matp…...
【教学类-06-07】20231124 (55格版)X-X之间的加法、减法、加减混合题
背景需求 在大四班里,预测试55格“5以内、10以内、20以内的加法题、减法题、加减混合题”的“实用性”。 由于只打印一份20以内加法减法混合题。 “这套20以内的加减法最难”,我询问谁会做(摸底幼儿的水平) 有两位男孩举手想挑…...
postgresql经常出现连接一会后服务器拒绝连接
本地连接远程Linux上PG数据库经常自动断开连接 原因:Linux设置的tcp的keepalive超时时间太长,如果网络状况不佳,可能会导致连接断掉。 [rootlocalhost ~]# sysctl -a | grep net.ipv4.tcp_keepalive sysctl: reading key "net.ipv6.con…...
迈巴赫S480升级主动式氛围灯 浪漫婉转的气氛
主动式氛围灯有263个可多色渐变的LED光源,营造出全情沉浸的动态光影氛围。结合智能驾驶辅助系统,可在转向或检测到危险时,予以红色环境光提示,令光影艺术彰显智能魅力。配件有6个氛围灯,1个电脑模块。 1、气候…...
Leetcode103 二叉树的锯齿形层序遍历
二叉树的锯齿形层序遍历 题解1 层序遍历双向队列 给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。 提示:…...
可观测性建设实践之 - 日志分析的权衡取舍
指标、日志、链路是服务可观测性的三大支柱,在服务稳定性保障中,通常指标侧重于发现故障和问题,日志和链路分析侧重于定位和分析问题,其中日志实际上是串联这三大维度的一个良好桥梁。 但日志分析往往面临成本和效果之间的权衡问…...
Ceres使用
之前用过Ceres,但是只是跑例程,现在来着重学习一下使用流程。 1. 解决的问题 主要解决非线性优化问题。Ceres是一个较为通用的库。 参考链接 2. 如何使用 这个是求解的函数,主要关注这三个参数 CERES_EXPORT void Solve(const Solver::O…...
深度学习第1天:深度学习入门-Keras与典型神经网络结构
☁️主页 Nowl 🔥专栏《机器学习实战》 《机器学习》 📑君子坐而论道,少年起而行之 文章目录 神经网络 介绍 结构 基本要素 Keras 介绍 导入 定义网络 模型训练 前馈神经网络 特点 常见类型 代码示例 反馈神经网络 特点 …...
青云科技容器平台与星辰天合存储产品完成兼容性互认证
近日, 北京青云科技股份有限公司(以下简称:青云科技)的 KubeSphere 企业版容器平台成功完成了与 XSKY星辰天合的企业级分布式统一数据平台 V6(简称:XEDP)以及天合翔宇分布式存储系统 V6…...
谈谈基于Redis的分布式锁
目录 前言 基本介绍 演化过程 防死锁 防误删 自动续期 可重入 主从一致 总结 前言 在我们没有了解分布式锁前,使用最多的就是线程锁和进程锁,但他们仅能满足在单机jvm或者同一个操作系统下,才能有效。跨jvm系统,无法…...
逸学java【初级菜鸟篇】10.I/O(输入/输出)
hi,我是逸尘,一起学java吧 目标(任务驱动) 1.请重点的掌握I/O的。 场景:最近你在企业也想搞一个短视频又想搞一个存储的云盘,你一听回想到自己对于这些存储的基础还不是很清楚,于是回家开始了…...
【Python进阶笔记】md文档笔记第6篇:Python进程和多线程使用(图文和代码)
本文从14大模块展示了python高级用的应用。分别有Linux命令,多任务编程、网络编程、Http协议和静态Web编程、htmlcss、JavaScript、jQuery、MySql数据库的各种用法、python的闭包和装饰器、mini-web框架、正则表达式等相关文章的详细讲述。 全套md格式笔记和代码自…...
基于Vue+SpringBoot的数字化社区网格管理系统
项目编号: S 042 ,文末获取源码。 \color{red}{项目编号:S042,文末获取源码。} 项目编号:S042,文末获取源码。 目录 一、摘要1.1 项目介绍1.2 源码 & 项目录屏 二、功能模块三、开发背景四、系统展示五…...
【数据库设计和SQL基础语法】--数据库设计基础--数据建模与ER图
一、数据建模的基本概念 1.1. 数据模型的概念 数据模型是对现实世界中事物及其之间关系的一种抽象表示。它提供了描述数据结构、数据操作、数据约束等的方式,是数据库设计的基础。数据模型帮助我们理解数据之间的关系,提供了一种规范化的方式来组织和存…...
Vue3 设置点击后滚动条移动到固定的位置
需求: 点击不通过按钮,显示红框中表单,且滚动条滚动到底部 (显示红框中表单默认不显示) <el-button click"onApprovalPass">不通过</el-button> <div class"item" v-if"app…...
外部 prometheus监控k8s集群资源(pod、CPU、service、namespace、deployment等)
prometheus监控k8s集群资源 一,通过CADvisior 监控pod的资源状态1.1 授权外边用户可以访问prometheus接口。1.2 获取token保存1.3 配置prometheus.yml 启动并查看状态1.4 Grafana 导入仪表盘 二,通过kube-state-metrics 监控k8s资源状态2.1 部署 kube-st…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
