貪心算法應用:決策樹(ID3/C4.5)詳解

在這里插入圖片描述

Java中的貪心算法應用:決策樹(ID3/C4.5)詳解

決策樹是一種常用的機器學習算法,它通過遞歸地將數據集分割成更小的子集來構建樹形結構。ID3和C4.5是兩種經典的決策樹算法,它們都使用了貪心算法來選擇最優的特征進行分割。下面我們將從原理到實現,全面詳細地講解這兩種算法在Java中的應用。

一、決策樹基礎概念

1. 什么是決策樹

決策樹是一種樹形結構,其中:

  • 內部節點表示一個特征或屬性
  • 分支代表該特征的可能取值
  • 葉節點代表最終的決策結果(分類或回歸值)

2. 決策樹構建的核心問題

構建決策樹時需要解決兩個關鍵問題:

  1. 如何選擇最優的特征進行分割(這正是貪心算法的應用點)
  2. 何時停止樹的生長(預剪枝或后剪枝)

二、貪心算法在決策樹中的應用

貪心算法在決策樹構建中體現在每次選擇當前最優的特征進行分割,而不考慮全局最優。這種局部最優的選擇策略使得算法高效,但可能無法得到全局最優的決策樹。

貪心選擇策略:

  1. 從根節點開始,計算所有特征的信息增益(ID3)或信息增益比(C4.5)
  2. 選擇信息增益(比)最大的特征作為當前節點的分割特征
  3. 對每個特征值創建分支,并遞歸地重復上述過程

三、ID3算法詳解

1. ID3算法核心思想

ID3(Iterative Dichotomiser 3)算法使用信息增益作為特征選擇標準,傾向于選擇取值較多的特征。

2. 關鍵概念與公式

信息熵(Entropy):

度量樣本集合純度的指標,熵越小純度越高。

公式:

H(D) = -Σ(p_k * log?p_k)

其中p_k是第k類樣本在數據集D中的比例

條件熵:

已知特征A的條件下,數據集D的熵。

公式:

H(D|A) = Σ(|D_v|/|D| * H(D_v))

其中D_v是特征A取值為v的子集

信息增益:

特征A對數據集D的信息增益是D的熵與條件熵之差。

公式:

Gain(D,A) = H(D) - H(D|A)

3. ID3算法步驟

  1. 計算數據集D的熵H(D)
  2. 對每個特征A:
    • 計算條件熵H(D|A)
    • 計算信息增益Gain(D,A)
  3. 選擇信息增益最大的特征作為當前節點的分割特征
  4. 對每個特征值創建分支,遞歸構建子樹
  5. 終止條件:
    • 所有樣本屬于同一類別
    • 沒有剩余特征可用于分割
    • 分支下沒有樣本

4. ID3算法的局限性

  1. 傾向于選擇取值較多的特征(可能過擬合)
  2. 不能處理連續值特征
  3. 不能處理缺失值
  4. 沒有剪枝策略,容易過擬合

四、C4.5算法詳解

C4.5是對ID3的改進算法,使用信息增益比作為特征選擇標準,并增加了對連續值和缺失值的處理。

1. C4.5的改進點

  1. 使用信息增益比代替信息增益
  2. 可以處理連續值特征
  3. 可以處理缺失值
  4. 增加了剪枝策略

2. 關鍵概念與公式

固有值(Intrinsic Value):

特征A的固有值衡量特征取值的分散程度。

公式:

IV(A) = -Σ(|D_v|/|D| * log?(|D_v|/|D|))
信息增益比:

信息增益與固有值的比值。

公式:

GainRatio(D,A) = Gain(D,A) / IV(A)

3. 連續值處理

對于連續值特征A:

  1. 將特征A的取值排序
  2. 考慮每兩個相鄰值的中間點作為候選分割點
  3. 對每個候選分割點t,將數據集分為A≤t和A>t兩部分
  4. 計算每個分割點的信息增益,選擇最優分割點

4. 缺失值處理

  1. 計算信息增益時,只使用非缺失樣本
  2. 將缺失值樣本按比例分配到各分支

5. C4.5算法步驟

  1. 計算數據集D的熵H(D)
  2. 對每個特征A:
    • 如果是離散特征:計算信息增益比
    • 如果是連續特征:找到最佳分割點并計算信息增益比
  3. 選擇信息增益比最大的特征作為當前節點的分割特征
  4. 對每個特征值創建分支,遞歸構建子樹
  5. 使用預剪枝或后剪枝策略防止過擬合

五、Java實現決策樹

下面我們給出一個完整的Java實現,包括ID3和C4.5算法。

1. 數據結構定義

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;// 決策樹節點類
class TreeNode {String featureName; // 分裂特征名稱(內部節點)String decision; // 決策結果(葉節點)boolean isLeaf;Map<String, TreeNode> children; // 子節點映射public TreeNode() {children = new HashMap<>();}
}// 樣本數據類
class DataSample {Map<String, String> features; // 特征名->特征值String label; // 類別標簽public DataSample() {features = new HashMap<>();}
}// 數據集類
class DataSet {List<DataSample> samples;List<String> featureNames;public DataSet(List<String> featureNames) {this.featureNames = new ArrayList<>(featureNames);this.samples = new ArrayList<>();}public void addSample(DataSample sample) {samples.add(sample);}// 獲取指定特征的取值集合public List<String> getFeatureValues(String featureName) {List<String> values = new ArrayList<>();for (DataSample sample : samples) {String value = sample.features.get(featureName);if (!values.contains(value)) {values.add(value);}}return values;}// 根據特征和取值分割數據集public DataSet split(String featureName, String value) {DataSet subset = new DataSet(featureNames);for (DataSample sample : samples) {if (sample.features.get(featureName).equals(value)) {subset.addSample(sample);}}return subset;}// 判斷是否所有樣本屬于同一類別public boolean isPure() {if (samples.isEmpty()) return true;String firstLabel = samples.get(0).label;for (DataSample sample : samples) {if (!sample.label.equals(firstLabel)) {return false;}}return true;}// 獲取多數類別public String getMajorityLabel() {Map<String, Integer> labelCounts = new HashMap<>();for (DataSample sample : samples) {labelCounts.put(sample.label, labelCounts.getOrDefault(sample.label, 0) + 1);}String majorityLabel = null;int maxCount = -1;for (Map.Entry<String, Integer> entry : labelCounts.entrySet()) {if (entry.getValue() > maxCount) {maxCount = entry.getValue();majorityLabel = entry.getKey();}}return majorityLabel;}
}

2. 決策樹工具類(實現ID3和C4.5)

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class DecisionTree {private boolean useID3; // true使用ID3,false使用C4.5public DecisionTree(boolean useID3) {this.useID3 = useID3;}// 計算信息熵private double calculateEntropy(DataSet dataSet) {Map<String, Integer> labelCounts = new HashMap<>();int total = dataSet.samples.size();for (DataSample sample : dataSet.samples) {labelCounts.put(sample.label, labelCounts.getOrDefault(sample.label, 0) + 1);}double entropy = 0.0;for (int count : labelCounts.values()) {double probability = (double) count / total;entropy -= probability * (Math.log(probability) / Math.log(2));}return entropy;}// 計算條件熵private double calculateConditionalEntropy(DataSet dataSet, String featureName) {double conditionalEntropy = 0.0;int total = dataSet.samples.size();List<String> featureValues = dataSet.getFeatureValues(featureName);for (String value : featureValues) {DataSet subset = dataSet.split(featureName, value);double subsetEntropy = calculateEntropy(subset);conditionalEntropy += ((double) subset.samples.size() / total) * subsetEntropy;}return conditionalEntropy;}// 計算信息增益private double calculateInformationGain(DataSet dataSet, String featureName) {double entropy = calculateEntropy(dataSet);double conditionalEntropy = calculateConditionalEntropy(dataSet, featureName);return entropy - conditionalEntropy;}// 計算固有值private double calculateIntrinsicValue(DataSet dataSet, String featureName) {double intrinsicValue = 0.0;int total = dataSet.samples.size();List<String> featureValues = dataSet.getFeatureValues(featureName);for (String value : featureValues) {DataSet subset = dataSet.split(featureName, value);double ratio = (double) subset.samples.size() / total;intrinsicValue -= ratio * (Math.log(ratio) / Math.log(2));}return intrinsicValue;}// 計算信息增益比private double calculateGainRatio(DataSet dataSet, String featureName) {double informationGain = calculateInformationGain(dataSet, featureName);double intrinsicValue = calculateIntrinsicValue(dataSet, featureName);// 避免除以0if (intrinsicValue == 0) {return 0;}return informationGain / intrinsicValue;}// 選擇最佳分裂特征private String chooseBestFeature(DataSet dataSet, List<String> remainingFeatures) {String bestFeature = null;double bestScore = -Double.MAX_VALUE;for (String feature : remainingFeatures) {double score;if (useID3) {score = calculateInformationGain(dataSet, feature);} else {score = calculateGainRatio(dataSet, feature);}if (score > bestScore) {bestScore = score;bestFeature = feature;}}return bestFeature;}// 構建決策樹public TreeNode buildTree(DataSet dataSet, List<String> remainingFeatures) {TreeNode node = new TreeNode();// 終止條件1:所有樣本屬于同一類別if (dataSet.isPure()) {node.isLeaf = true;node.decision = dataSet.samples.get(0).label;return node;}// 終止條件2:沒有剩余特征可用于分割if (remainingFeatures.isEmpty()) {node.isLeaf = true;node.decision = dataSet.getMajorityLabel();return node;}// 選擇最佳分裂特征String bestFeature = chooseBestFeature(dataSet, remainingFeatures);node.featureName = bestFeature;node.isLeaf = false;// 從剩余特征中移除已選特征List<String> newRemainingFeatures = new ArrayList<>(remainingFeatures);newRemainingFeatures.remove(bestFeature);// 遞歸構建子樹List<String> featureValues = dataSet.getFeatureValues(bestFeature);for (String value : featureValues) {DataSet subset = dataSet.split(bestFeature, value);if (subset.samples.isEmpty()) {// 如果子集為空,創建葉節點,使用父節點的多數類別TreeNode leafNode = new TreeNode();leafNode.isLeaf = true;leafNode.decision = dataSet.getMajorityLabel();node.children.put(value, leafNode);} else {// 遞歸構建子樹node.children.put(value, buildTree(subset, newRemainingFeatures));}}return node;}// 預測樣本類別public String predict(TreeNode root, DataSample sample) {if (root.isLeaf) {return root.decision;}String featureValue = sample.features.get(root.featureName);TreeNode child = root.children.get(featureValue);if (child == null) {// 如果特征值在訓練時未出現,返回null或采取其他策略return null;}return predict(child, sample);}// 打印決策樹(用于調試)public void printTree(TreeNode node, String indent) {if (node.isLeaf) {System.out.println(indent + "Predict: " + node.decision);return;}System.out.println(indent + "Feature: " + node.featureName);for (Map.Entry<String, TreeNode> entry : node.children.entrySet()) {System.out.println(indent + "  " + entry.getKey() + ":");printTree(entry.getValue(), indent + "    ");}}
}

3. 使用示例

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;public class Main {public static void main(String[] args) {// 定義特征名稱List<String> featureNames = Arrays.asList("Outlook", "Temperature", "Humidity", "Wind");// 創建數據集DataSet dataSet = new DataSet(featureNames);// 添加樣本數據(天氣、溫度、濕度、風況、是否打球)addSample(dataSet, "Sunny", "Hot", "High", "Weak", "No");addSample(dataSet, "Sunny", "Hot", "High", "Strong", "No");addSample(dataSet, "Overcast", "Hot", "High", "Weak", "Yes");addSample(dataSet, "Rain", "Mild", "High", "Weak", "Yes");addSample(dataSet, "Rain", "Cool", "Normal", "Weak", "Yes");addSample(dataSet, "Rain", "Cool", "Normal", "Strong", "No");addSample(dataSet, "Overcast", "Cool", "Normal", "Strong", "Yes");addSample(dataSet, "Sunny", "Mild", "High", "Weak", "No");addSample(dataSet, "Sunny", "Cool", "Normal", "Weak", "Yes");addSample(dataSet, "Rain", "Mild", "Normal", "Weak", "Yes");addSample(dataSet, "Sunny", "Mild", "Normal", "Strong", "Yes");addSample(dataSet, "Overcast", "Mild", "High", "Strong", "Yes");addSample(dataSet, "Overcast", "Hot", "Normal", "Weak", "Yes");addSample(dataSet, "Rain", "Mild", "High", "Strong", "No");// 使用ID3算法構建決策樹System.out.println("ID3 Decision Tree:");DecisionTree id3Tree = new DecisionTree(true);TreeNode id3Root = id3Tree.buildTree(dataSet, new ArrayList<>(featureNames));id3Tree.printTree(id3Root, "");// 使用C4.5算法構建決策樹System.out.println("\nC4.5 Decision Tree:");DecisionTree c45Tree = new DecisionTree(false);TreeNode c45Root = c45Tree.buildTree(dataSet, new ArrayList<>(featureNames));c45Tree.printTree(c45Root, "");// 預測新樣本DataSample newSample = new DataSample();newSample.features.put("Outlook", "Sunny");newSample.features.put("Temperature", "Cool");newSample.features.put("Humidity", "High");newSample.features.put("Wind", "Strong");System.out.println("\nPrediction for new sample (Sunny, Cool, High, Strong):");System.out.println("ID3: " + id3Tree.predict(id3Root, newSample));System.out.println("C4.5: " + c45Tree.predict(c45Root, newSample));}private static void addSample(DataSet dataSet, String outlook, String temperature, String humidity, String wind, String label) {DataSample sample = new DataSample();sample.features.put("Outlook", outlook);sample.features.put("Temperature", temperature);sample.features.put("Humidity", humidity);sample.features.put("Wind", wind);sample.label = label;dataSet.addSample(sample);}
}

六、算法優化與擴展

1. 預剪枝策略

為了防止過擬合,可以在決策樹構建過程中加入預剪枝策略:

// 在buildTree方法中添加預剪枝判斷
public TreeNode buildTree(DataSet dataSet, List<String> remainingFeatures, int maxDepth, int currentDepth) {// 終止條件3:達到最大深度if (currentDepth >= maxDepth) {TreeNode leafNode = new TreeNode();leafNode.isLeaf = true;leafNode.decision = dataSet.getMajorityLabel();return leafNode;}// ...原有代碼...
}

2. 連續值特征處理

擴展C4.5算法處理連續值特征:

// 在DecisionTree類中添加連續值處理方法
private String chooseBestFeatureForContinuous(DataSet dataSet, List<String> remainingFeatures) {String bestFeature = null;double bestScore = -Double.MAX_VALUE;double bestSplitPoint = 0;for (String feature : remainingFeatures) {// 檢查是否是連續值特征(假設連續值特征以"Cont_"前綴標識)if (feature.startsWith("Cont_")) {// 獲取所有樣本的該特征值并排序List<Double> values = new ArrayList<>();for (DataSample sample : dataSet.samples) {values.add(Double.parseDouble(sample.features.get(feature)));}Collections.sort(values);// 檢查相鄰值之間的候選分割點for (int i = 0; i < values.size() - 1; i++) {double splitPoint = (values.get(i) + values.get(i + 1)) / 2;// 臨時修改特征值為離散值(≤splitPoint和>splitPoint)DataSet tempDataSet = new DataSet(dataSet.featureNames);for (DataSample sample : dataSet.samples) {DataSample tempSample = new DataSample();for (String f : dataSet.featureNames) {if (f.equals(feature)) {double val = Double.parseDouble(sample.features.get(f));tempSample.features.put(f, val <= splitPoint ? "≤" + splitPoint : ">" + splitPoint);} else {tempSample.features.put(f, sample.features.get(f));}}tempSample.label = sample.label;tempDataSet.addSample(tempSample);}double score = calculateGainRatio(tempDataSet, feature);if (score > bestScore) {bestScore = score;bestFeature = feature;bestSplitPoint = splitPoint;}}} else {// 離散特征處理(原有邏輯)double score = calculateGainRatio(dataSet, feature);if (score > bestScore) {bestScore = score;bestFeature = feature;}}}// 對于連續值特征,保存分割點信息if (bestFeature != null && bestFeature.startsWith("Cont_")) {return bestFeature + ":" + bestSplitPoint;}return bestFeature;
}

3. 缺失值處理

擴展C4.5算法處理缺失值:

// 在DecisionTree類中添加缺失值處理方法
private double calculateInformationGainWithMissing(DataSet dataSet, String featureName) {// 計算非缺失樣本的比例int total = dataSet.samples.size();int missingCount = 0;for (DataSample sample : dataSet.samples) {if (sample.features.get(featureName) == null) {missingCount++;}}if (missingCount == total) {return 0; // 所有樣本該特征都缺失}double nonMissingRatio = (double) (total - missingCount) / total;// 創建非缺失樣本的子集DataSet nonMissingSubset = new DataSet(dataSet.featureNames);for (DataSample sample : dataSet.samples) {if (sample.features.get(featureName) != null) {nonMissingSubset.addSample(sample);}}// 計算信息增益double entropy = calculateEntropy(dataSet);double conditionalEntropy = calculateConditionalEntropy(nonMissingSubset, featureName);return nonMissingRatio * (entropy - conditionalEntropy);
}// 在構建樹時處理缺失值
private TreeNode buildTreeWithMissing(DataSet dataSet, List<String> remainingFeatures) {// ...類似原有buildTree方法,但在分割時處理缺失值...// 對于有缺失值的樣本,將其按比例分配到各分支for (String value : featureValues) {DataSet subset = dataSet.split(bestFeature, value);// 計算該特征值的比例double ratio = (double) subset.samples.size() / (dataSet.samples.size() - missingCount);// 添加缺失值樣本到該分支,但權重按比例// 實際實現可能需要修改數據結構以支持加權樣本// ...}// ...
}

七、決策樹的優缺點

優點:

  1. 易于理解和解釋(可視化)
  2. 不需要太多數據預處理(如歸一化)
  3. 可以處理數值和類別數據
  4. 能夠處理多輸出問題
  5. 使用白盒模型,結果可解釋

缺點:

  1. 容易過擬合(需要剪枝)
  2. 可能不穩定(數據微小變化導致完全不同樹)
  3. 貪心算法不能保證全局最優
  4. 對某些類型的關系(如XOR)難以學習
  5. 類別不平衡時可能偏向多數類

八、實際應用中的考慮

  1. 特征選擇:決策樹對特征選擇敏感,應選擇有區分力的特征
  2. 剪枝策略:合理設置預剪枝參數或使用后剪枝
  3. 類別不平衡:可以使用類權重或采樣方法
  4. 多棵樹集成:隨機森林等集成方法可以提升性能
  5. 并行化:決策樹構建可以并行化加速

九、總結

決策樹作為一種經典的機器學習算法,其貪心的分割策略使其高效且易于理解,而Java的實現展示了算法的具體細節。理解這些基礎算法對于掌握更復雜的集成方法(如隨機森林、GBDT等)至關重要。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/923616.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/923616.shtml
英文地址,請注明出處:http://en.pswp.cn/news/923616.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

華為任旭東:開源協作,激發創新,共創智能世界 | GOSIM HANGZHOU 2025

GOSIM HANGZHOU 2025峰會盛大開幕&#xff0c;華為首席開源聯絡官、CNCF基金會董事任旭東以《開源協作&#xff0c;激發創新&#xff0c;共創智能世界》為題發表Keynote演講。顛覆性技術到工業應用的轉換時間越來越短&#xff0c;AI技術正在推動傳統軟件產業的演進&#xff0c;…

本地部署 GPS 跟蹤系統 Traccar 并實現外部訪問

Traccar 是一款集成了強大的 java 后端服務的 GPS 跟蹤系統 。它支持在多種設備使用&#xff0c;在物流運輸、資產管理和個人安全等領域應用。本文將詳細的介紹如何利用 Docker 在本地部署 Traccar 并結合路由俠實現外網訪問本地部署的 Traccar 。 第一步&#xff0c;本地部署…

【開題答辯全過程】以 “川趣玩”旅行團預定微信小程序為例,包含答辯的問題和答案

個人簡介一名14年經驗的資深畢設內行人&#xff0c;語言擅長Java、php、微信小程序、Python、Golang、安卓Android等開發項目包括大數據、深度學習、網站、小程序、安卓、算法。平常會做一些項目定制化開發、代碼講解、答辯教學、文檔編寫、也懂一些降重方面的技巧。感謝大家的…

Android Doze低電耗休眠模式 與 WorkManager

1. Doze模式下&#xff0c;WorkManager setInitialDelay設置小于15分鐘&#xff0c;被系統強制到15分鐘執行&#xff0c;怎么辦 ? Android 擁有兩項省電功能&#xff0c;通過管理設備未連接電源時應用的行為來延長用戶電池續航時間&#xff1a;低電耗模式 (Doze) 和應用待機模…

iOS 能耗監控與電池優化實戰:如何查看App耗電量、分析CPU、GPU內存使用、(uni-app iOS開發性能調試指南)

在 iOS 應用開發中&#xff0c;能耗與電池消耗是用戶最直觀的體驗指標。 即便功能完善&#xff0c;如果 App 存在以下問題&#xff1a; 電池掉電快、設備發熱嚴重&#xff1b;后臺任務執行過多&#xff1b;頁面渲染與文件操作引發 CPU/GPU 過載&#xff1b;日志或緩存導致頻繁 …

Git 本地分支推送多個遠程分支

方法一&#xff1a;一次性推送命令 命令格式&#xff1a; git push <遠程倉庫名> <本地分支引用>:<遠程分支名1> <本地分支引用>:<遠程分支名2> ...具體步驟&#xff1a; 確保你的代碼修改已經提交到了本地分支 git add . git commit -m "你…

抖音私信評論互動消息通知監聽自動獲取,通過qq機器人轉發到qq來通知

抖音私信評論互動消息通知監聽自動獲取&#xff0c;通過qq機器人轉發到qq來通知 如果不是抖音平臺&#xff0c;其他平臺也類似的&#xff0c;也可以實現&#xff0c;只是目前懶得寫了 本期視頻點贊過10個就開源代碼 有需要的人可以在視頻底下留言 需求反饋多的我可以實現

UVM驗證工具--gvim

目錄 gvim語法高亮 gvim支持git Linux環境自帶gvim工具&#xff0c;我們需要做如下設置&#xff1a; 支持UVM、SystemVerilog、verilog語法高亮支持git&#xff08;實時顯示對文件的修改&#xff09; gvim語法高亮 gvim支持git

MyBatis 從入門到精通(第二篇)—— 核心架構、配置解析與 Mapper 代理開發

在第一篇博客中&#xff0c;我們掌握了 MyBatis 的基礎概念與環境搭建&#xff0c;成功通過簡單查詢實現了數據持久化。但要真正用好 MyBatis&#xff0c;還需深入理解其 “內部工作原理” 與 “企業級開發規范”。本篇將聚焦三大核心&#xff1a;MyBatis 架構與核心類、全局配…

uniapp+<script setup lang=“ts“>單個時間格式轉換(format)

有問題的時間&#xff08;只示例&#xff0c;不是真實數據&#xff09;修改后的時間展示&#xff08;只示例&#xff0c;不是真實數據&#xff09;原代碼<view v-else-if"item?.payTime" class"order-info-item">支付時間&#xff1a;item?.payTim…

運維安全05,iptables規則保存與恢復

一&#xff1a;網絡安全1.1、昨日功能優化配置后引發的問題&#xff1a;配置iptables后防火墻起到了防護作用&#xff0c;但使用127.0.0.1訪問不了數據庫了[rootlocalhost /]# mysql -u admin -p -h 127.0.0.1 Enter password:思考&#xff1a;如果使用localhost可以訪問嗎&…

線性代數 · 矩陣 | 秩 / 行秩 / 列秩 / 計算方法

注&#xff1a;本文為 “線性代數 矩陣 | 秩” 相關合輯。 圖片清晰度受引文原圖所限。 略作重排&#xff0c;未全校去重。 如有內容異常&#xff0c;請看原文。 矩陣的秩及其應用 一、矩陣秩的基本概念 &#xff08;一&#xff09;k 階子式 設矩陣 A(aij)mnA (a_{ij})_{m…

Ajax-day2(圖書管理)-彈框顯示和隱藏

Bootstrap 彈框圖書管理-Bootsrap 彈框&#xff08;一&#xff09;屬性控制一、模板代碼二、彈框模板三、bootsrap 的顯示彈框屬性完整代碼&#xff08;二&#xff09;JS 控制一、模板代碼二、步驟圖書管理-Bootsrap 彈框 Bootstrap 框架渲染列表&#xff08;查&#xff09;新…

【Linux網絡】認識https

認識https一&#xff0c;概念鋪墊1.1 什么是加密&#xff1f;1.2 為什么要加密&#xff1f;1.3 加密的方式1.4 數據摘要&數據指紋二&#xff0c;認識https2.1 方案1-只使用對稱加密2.2 方案2-只使用非對稱加密2.3 方案3-雙方都使用非對稱加密2.4 方案4-非對稱加密對稱加密2…

OC-AFNetworking

文章目錄AFNetworking簡介問題&#x1f914;優化策略解決AFNetworking局限性使用單例進行網絡請求的優勢使用單例進行網絡請求的風險最優使用使用參數講解POST請求AFNetworking 簡介 這篇文章旨在實現使用AFNetworking設置一個集中的單通道網絡對象&#xff0c;該對象與MVC組建…

【數據結構】跳表

目錄 1.什么是跳表-skiplist 2.skiplist的效率如何保證&#xff1f; 3.skiplist的實現 3.1節點和成員設計 3.2查找實現 3.3前置節點查找 3.4插入實現 3.5刪除實現 3.6隨機層數 3.7完整代碼 4.skiplist跟平衡搜索樹和哈希表的對比 1.什么是跳表-skiplist skiplist是由…

html實現右上角有個圖標,鼠標移動到該位置出現手型,點擊會彈出登錄窗口。

寫了一段html代碼實現的效果&#xff1a;實現右上角有個圖標&#xff0c;鼠標移動到該位置出現手型&#xff0c;點擊會彈出登錄窗口。功能實現前端&#xff0c;沒有實現后端。<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF…

STM32G4 電流環閉環(二) 霍爾有感運行

目錄一、STM32G4 電流環閉環(二) 霍爾有感運行2. 霍爾有感運行附學習參考網址歡迎大家有問題評論交流 (* ^ ω ^)一、STM32G4 電流環閉環(二) 霍爾有感運行 2. 霍爾有感運行 文章使用的BLDC在定子側以互差120電角度的位置安裝三個霍爾元件Ha&#xff0c;Hb&#xff0c;Hc。當…

展示框選擇

好的&#xff0c;非常感謝您提供更詳細的項目情況。這是一個非常典型的父子組件通信場景。 根據您的新需求&#xff0c;我將對代碼進行重構&#xff1a; FaultSelect.vue (子組件): 這個組件現在將變得更加“純粹”。它只負責自身的下拉框邏輯&#xff0c;不關心外部按鈕&#…

第5課:上下文管理與狀態持久化

第5課:上下文管理與狀態持久化 課程目標 掌握上下文存儲和檢索策略 學習會話狀態管理 了解數據持久化方案 實踐實現上下文管理系統 課程內容 5.1 上下文管理基礎 什么是上下文管理? 上下文管理是Agent系統中維護和利用歷史信息的能力,包括: 對話歷史:用戶與Agent的交互…