基于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.pswp.cn/news/165553.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/165553.shtml
英文地址,請注明出處:http://en.pswp.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容器啟動過報錯的輸出日志。…

Windmill:最快的自托管開源工作流引擎

我們對 Windmill 進行了基準測試&#xff0c;認為它是 Airflow、Prefect 甚至 Temporal 中最快的自托管通用工作流引擎。對于 Airflow&#xff0c;有速度快了 10 倍&#xff01; 工作流引擎編排工作人員的有向無環圖 (DAG) 中定義的作業&#xff0c;同時尊重依賴性。 主要優點…

Haclon簡介及數據類型

Haclon簡介 HALCON是由德國MVtec公司開發的機器視覺算法包&#xff0c;它由一千多個各自獨立的函數&#xff08;算子&#xff09;構成&#xff0c;其中除了包含各類濾波、色彩以及幾何、數學轉換、形態學計算分析、圖像校正&#xff0c;目標分類辨識、形狀搜尋等基本的圖像處理…

通配符OV SSL證書都有哪些品牌?

隨著數字化時代的到來&#xff0c;網站和在線服務的安全性變得尤為重要。為了保護用戶的隱私和數據安全&#xff0c;SSL證書越來越受到重視。OV證書是一種高級別的SSL證書&#xff0c;可以提供更多的驗證和保護。而通配符SSL證書則可以保護多個子域名&#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;當六個輸入值的…

免費接口集合讓開發更簡單

企業基本信息(含聯系方式)&#xff1a;通過公司名稱/公司ID/注冊號或社會統一信用代碼獲取企業基本信息和企業聯系方式&#xff0c;包括公司名稱或ID、類型、成立日期、電話、郵箱、網址等字段的詳細信息。企業基本信息&#xff1a;通過公司名稱/公司ID/注冊號或社會統一信用代…

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界面 前言 本篇文章講解如何…

linux環境下samba服務器的配置

linux服務器怎么創建用戶 在Linux服務器上&#xff0c;可以使用以下步驟創建用戶&#xff1a; 使用adduser命令創建新用戶&#xff1a; sudo adduser username將 username 替換為你要創建的用戶名。這個命令會提示你輸入新用戶的密碼以及其他相關信息。 如果需要為新用戶設…

qml PathPercent使用介紹

PathPercent 是一個QML類型,它表示 Path 上的一個百分比位置。這個類型通常在 PathAnimation 或 PathInterpolator 中使用,以便在路徑上產生一個特定的位置。它提供了一種方式來表示在 Path 元素上的某個點。通過 PathPercent,你可以指定一個百分比,來表示沿著路徑的位置,…

『亞馬遜云科技產品測評』活動征文|通過Lightsail搭建個人筆記

提示&#xff1a;授權聲明&#xff1a;本篇文章授權活動官方亞馬遜云科技文章轉發、改寫權&#xff0c;包括不限于在 Developer Centre, 知乎&#xff0c;自媒體平臺&#xff0c;第三方開發者媒體等亞馬遜云科技官方渠道 文章目錄 前言實踐知識儲備Lightsail介紹Leanote介紹實踐…

系統架構設計: 21 論敏捷軟件開發方法及其應用

論敏捷軟件開發方法及其應用 請圍繞“敏捷軟件開發方法及其應用”論題,依次從以下三個方面進行論述。 ①簡述你所參與開發的運用了敏捷技術的項目,以及你所擔任的工作; ②分析并討論敏捷<

VSCode插件koroFileHeader的使用。

文章目錄 前言一、koroFileHeader是什么&#xff1f;二、使用步驟1.安裝1.配置2.食用 前言 今天的天氣還不錯&#xff0c;真是金風玉露一相逢&#xff0c;便勝卻人間無數&#xff0c;寫篇博客玩玩&#xff0c;主題&#xff1a;注釋。注釋的本質就是對代碼的解釋和說明&#xf…

nginx 配置靜態緩存全教程 (以及靜態緩存文件沒有生成)

一、第一步定義一個緩存目錄設置目錄結構 在 http 模塊下定義(keys_zone 緩存區名&#xff1a;后面是緩存區大小 inactive 不活躍的文件多久清理 max_size 緩存區所占磁盤的上限 use_temp_path 默認關閉&#xff08;有需要自己百度&#xff09;) proxy_cache_path /path/your…

16 Go的反射

概述 在上一節的內容中&#xff0c;我們介紹了Go的并發&#xff0c;包括&#xff1a;Goroutines、Channels、WaitGroups、Mutex、Select等。在本節中&#xff0c;我們將介紹Go的反射。Go語言中的反射是一種在運行時檢查類型信息并操作對象的能力&#xff0c;通過反射&#xff0…