《算法導論》第 14 章 - 數據結構的擴張

????????大家好!今天我們來深入學習《算法導論》第 14 章 —— 數據結構的擴張。這一章主要介紹了如何基于現有數據結構(如二叉搜索樹)擴展出新的功能,以滿足更復雜的問題需求。我們會從動態順序統計樹講到區間樹,每個知識點都會配上完整可運行的 C++ 代碼,方便大家動手實踐。

思維導圖

14.1 動態順序統計

????????在很多場景中,我們不僅需要像普通 BST 那樣查找元素,還需要知道元素在集合中的排名(秩),或者查找集合中第 i 小的元素。動態順序統計樹就是為了解決這類問題而設計的。

基本概念

  • 秩(Rank):一個元素的秩是指該元素在集合的線性序中所處的位置(從 1 開始計數)
  • 第 i 個順序統計量:集合中第 i 小的元素

數據結構設計

????????動態順序統計樹在普通 BST 的基礎上,為每個節點增加了一個size屬性,表示以該節點為根的子樹中包含的節點總數(包括自身)。

// 動態順序統計樹節點結構
struct Node {int key;         // 節點關鍵字int size;        // 以該節點為根的子樹大小Node *left;      // 左孩子Node *right;     // 右孩子Node *parent;    // 父節點// 構造函數Node(int k) : key(k), size(1), left(nullptr), right(nullptr), parent(nullptr) {}
};

核心操作實現

更新節點大小

當樹的結構發生變化(插入或刪除節點)時,需要更新相關節點的size屬性:

// 更新節點的size(等于左子樹size + 右子樹size + 1)
void updateSize(Node *node) {if (node != nullptr) {node->size = 1;  // 自身if (node->left != nullptr) {node->size += node->left->size;}if (node->right != nullptr) {node->size += node->right->size;}}
}
查找第 i 個元素
// 查找以node為根的子樹中第i個最小元素(1-based)
Node* select(Node *node, int i) {if (node == nullptr) return nullptr;  // 空樹或i超出范圍// 左子樹的節點數int leftSize = (node->left != nullptr) ? node->left->size : 0;if (i == leftSize + 1) {// 當前節點就是第i個元素return node;} else if (i <= leftSize) {// 第i個元素在左子樹中return select(node->left, i);} else {// 第i個元素在右子樹中,注意要調整i的值return select(node->right, i - (leftSize + 1));}
}

計算元素的秩
// 計算x在以root為根的樹中的秩
int rank(Node *root, Node *x) {// x的左子樹大小 + 1(自身)int r = (x->left != nullptr) ? x->left->size + 1 : 1;Node *y = x;// 向上追溯到根節點while (y != root) {if (y == y->parent->right) {// 如果y是其父節點的右孩子,則需要加上父節點左子樹大小 + 1(父節點自身)r += (y->parent->left != nullptr) ? y->parent->left->size + 1 : 1;}y = y->parent;}return r;
}
插入操作

插入操作在普通 BST 插入的基礎上,需要從新插入的節點向上更新所有祖先的size屬性:

// 向以root為根的樹中插入關鍵字key,返回新的根節點
Node* insert(Node *root, int key) {// 普通BST插入邏輯Node *parent = nullptr;Node **current = &root;while (*current != nullptr) {parent = *current;(*current)->size++;  // 沿途節點size加1if (key < (*current)->key) {current = &((*current)->left);} else {current = &((*current)->right);}}*current = new Node(key);(*current)->parent = parent;return root;  // 返回新的根節點
}
刪除操作

????????刪除操作相對復雜,需要先找到要刪除的節點,執行刪除(考慮三種情況:葉子節點、只有一個孩子、有兩個孩子),然后更新相關節點的size屬性:

// 查找關鍵字為key的節點
Node* find(Node *root, int key) {Node *current = root;while (current != nullptr && current->key != key) {if (key < current->key) {current = current->left;} else {current = current->right;}}return current;
}// 找到以node為根的樹中的最小值節點
Node* minimum(Node *node) {while (node->left != nullptr) {node = node->left;}return node;
}// 替換子樹
void transplant(Node *&root, Node *u, Node *v) {if (u->parent == nullptr) {root = v;  // u是根節點} else if (u == u->parent->left) {u->parent->left = v;  // u是左孩子} else {u->parent->right = v;  // u是右孩子}if (v != nullptr) {v->parent = u->parent;  // 更新v的父節點}
}// 從樹中刪除節點z,返回新的根節點
Node* deleteNode(Node *root, Node *z) {if (z == nullptr) return root;  // 節點不存在Node *y = nullptr;Node *x = nullptr;// 確定要刪除的實際節點yif (z->left == nullptr || z->right == nullptr) {y = z;} else {y = minimum(z->right);  // 找到后繼節點}// 確定y的孩子xif (y->left != nullptr) {x = y->left;} else {x = y->right;}// 更新x的父節點if (x != nullptr) {x->parent = y->parent;}// 替換ytransplant(root, y, x);// 如果y不是z,則將y的內容復制到zif (y != z) {z->key = y->key;}// 更新受影響節點的sizeNode *p = y->parent;while (p != nullptr) {updateSize(p);p = p->parent;}delete y;  // 釋放內存return root;
}

綜合案例:動態順序統計樹的應用

下面是一個完整的示例,展示了動態順序統計樹的各種操作:

#include <iostream>
#include <iomanip>
using namespace std;// 節點結構定義
struct Node {int key;int size;Node *left;Node *right;Node *parent;Node(int k) : key(k), size(1), left(nullptr), right(nullptr), parent(nullptr) {}
};// 輔助函數聲明
void updateSize(Node *node);
Node* select(Node *node, int i);
int getRank(Node *root, Node *x);  // 重命名rank為getRank
Node* insert(Node *root, int key);
Node* find(Node *root, int key);
Node* minimum(Node *node);
void transplant(Node *&root, Node *u, Node *v);
Node* deleteNode(Node *root, Node *z);// 輔助函數實現
void updateSize(Node *node) {if (node != nullptr) {node->size = 1;if (node->left != nullptr) node->size += node->left->size;if (node->right != nullptr) node->size += node->right->size;}
}Node* select(Node *node, int i) {if (node == nullptr) return nullptr;int leftSize = (node->left != nullptr) ? node->left->size : 0;if (i == leftSize + 1) return node;else if (i <= leftSize) return select(node->left, i);else return select(node->right, i - (leftSize + 1));
}// 重命名rank為getRank,避免與標準庫沖突
int getRank(Node *root, Node *x) {int r = (x->left != nullptr) ? x->left->size + 1 : 1;Node *y = x;while (y != root) {if (y == y->parent->right) {r += (y->parent->left != nullptr) ? y->parent->left->size + 1 : 1;}y = y->parent;}return r;
}Node* insert(Node *root, int key) {Node *parent = nullptr;Node **current = &root;while (*current != nullptr) {parent = *current;(*current)->size++;if (key < (*current)->key) current = &((*current)->left);else current = &((*current)->right);}*current = new Node(key);(*current)->parent = parent;return root;
}Node* find(Node *root, int key) {Node *current = root;while (current != nullptr && current->key != key) {if (key < current->key) current = current->left;else current = current->right;}return current;
}Node* minimum(Node *node) {while (node->left != nullptr) node = node->left;return node;
}void transplant(Node *&root, Node *u, Node *v) {if (u->parent == nullptr) root = v;else if (u == u->parent->left) u->parent->left = v;else u->parent->right = v;if (v != nullptr) v->parent = u->parent;
}Node* deleteNode(Node *root, Node *z) {if (z == nullptr) return root;Node *y = nullptr, *x = nullptr;if (z->left == nullptr || z->right == nullptr) y = z;else y = minimum(z->right);if (y->left != nullptr) x = y->left;else x = y->right;if (x != nullptr) x->parent = y->parent;transplant(root, y, x);if (y != z) z->key = y->key;Node *p = y->parent;while (p != nullptr) {updateSize(p);p = p->parent;}delete y;return root;
}// 中序遍歷打印樹(用于調試)
void inorder(Node *node) {if (node != nullptr) {inorder(node->left);cout << node->key << "(" << node->size << ") ";inorder(node->right);}
}int main() {Node *root = nullptr;// 插入一些元素int keys[] = {15, 6, 18, 3, 7, 17, 20, 2, 4, 13, 9};for (int key : keys) {root = insert(root, key);}cout << "樹的中序遍歷(帶size): ";inorder(root);cout << endl << endl;// 測試select操作for (int i = 1; i <= 11; i++) {Node *node = select(root, i);if (node != nullptr) {cout << "第" << i << "小的元素是: " << node->key << endl;}}cout << endl;// 測試rank操作,使用重命名后的getRankint testKeys[] = {15, 7, 20, 2};for (int key : testKeys) {Node *node = find(root, key);if (node != nullptr) {cout << "元素" << key << "的秩是: " << getRank(root, node) << endl;}}cout << endl;// 測試刪除操作int delKey = 6;Node *delNode = find(root, delKey);if (delNode != nullptr) {cout << "刪除元素" << delKey << "后,樹的中序遍歷: ";root = deleteNode(root, delNode);inorder(root);cout << endl << endl;// 再次測試select和rank操作cout << "刪除后,第3小的元素是: " << select(root, 3)->key << endl;cout << "刪除后,元素7的秩是: " << getRank(root, find(root, 7)) << endl;}return 0;
}

運行結果:

14.2 如何擴張數據結構

????????擴張數據結構是指在現有數據結構的基礎上添加新的信息和操作,以解決特定問題。以下是擴張數據結構的一般步驟:

  1. 選擇基礎數據結構:通常選擇能高效支持基本操作的數據結構(如 BST、紅黑樹等)

  2. 確定要添加的信息:根據問題需求,確定需要在原有結構上添加哪些額外信息

  3. 驗證新信息可以被維護:確保在基礎數據結構的所有操作(插入、刪除等)執行后,新添加的信息仍能被正確維護

  4. 實現新的操作:基于添加的信息,實現解決問題所需的新操作

設計原則

  • 局部性:新信息應能通過節點本身及其子節點的信息計算得出
  • 高效性:維護新信息的額外時間不應顯著增加原有操作的時間復雜度
  • 必要性只添加解決問題所必需的信息,避免冗余

動態順序統計樹就是一個典型的擴張例子:

  • 基礎數據結構:二叉搜索樹(BST)
  • 添加的信息:每個節點的size屬性
  • 維護方式:插入 / 刪除時更新路徑上所有節點的size
  • 新操作:selectrank

14.3 區間樹

區間樹是一種支持區間查詢的數據結構,它能高效地找出與給定區間重疊的所有區間。

區間表示與問題定義

  • 區間通常表示為[low, high],其中low是區間的起點,high是區間的終點
  • 兩個區間[a,b][c,d]重疊當且僅當a ≤ dc ≤ b
  • 區間樹的主要操作:插入區間、刪除區間、查詢所有與給定區間重疊的區間

數據結構設計

區間樹基于 BST 擴展而來,每個節點存儲:

  • 一個區間[low, high]
  • 以區間的low為關鍵字構建 BST
  • 額外添加max屬性,表示以該節點為根的子樹中所有區間的high的最大值

// 區間結構
struct Interval {int low;   // 區間起點int high;  // 區間終點Interval(int l, int h) : low(l), high(h) {}
};// 區間樹節點結構
struct IntervalNode {Interval *interval;  // 區間int max;             // 子樹中最大的high值IntervalNode *left;  // 左孩子IntervalNode *right; // 右孩子IntervalNode *parent;// 父節點// 構造函數IntervalNode(int low, int high) : interval(new Interval(low, high)), max(high), left(nullptr), right(nullptr), parent(nullptr) {}
};

區間樹的類圖:

@startuml
class Interval {- int low- int high+ Interval(int l, int h)
}class IntervalNode {- Interval* interval- int max- IntervalNode* left- IntervalNode* right- IntervalNode* parent+ IntervalNode(int low, int high)
}IntervalNode "1" *-- "1" Interval : contains
IntervalNode "1" --* "0..1" IntervalNode : left child
IntervalNode "1" --* "0..1" IntervalNode : right child
@enduml

核心操作實現

更新 max 值
// 更新節點的max值(自身high和左右子樹max中的最大值)
void updateMax(IntervalNode *node) {if (node != nullptr) {node->max = node->interval->high;  // 自身區間的highif (node->left != nullptr && node->left->max > node->max) {node->max = node->left->max;}if (node->right != nullptr && node->right->max > node->max) {node->max = node->right->max;}}
}
插入操作
// 向區間樹中插入新區間
IntervalNode* insertInterval(IntervalNode *root, int low, int high) {// 普通BST插入(以low為關鍵字)IntervalNode *parent = nullptr;IntervalNode **current = &root;while (*current != nullptr) {parent = *current;// 更新當前節點的max值if (high > (*current)->max) {(*current)->max = high;}// 繼續查找插入位置if (low < (*current)->interval->low) {current = &((*current)->left);} else {current = &((*current)->right);}}// 創建新節點*current = new IntervalNode(low, high);(*current)->parent = parent;return root;
}
區間查詢操作

查詢所有與給定區間[low, high]重疊的區間:

// 檢查兩個區間是否重疊
bool overlap(Interval *a, Interval *b) {return a->low <= b->high && b->low <= a->high;
}// 查詢與target重疊的所有區間
void queryOverlapping(IntervalNode *node, Interval *target, vector<Interval*>& result) {if (node == nullptr) return;// 先檢查左子樹if (node->left != nullptr && node->left->max >= target->low) {queryOverlapping(node->left, target, result);}// 檢查當前節點if (overlap(node->interval, target)) {result.push_back(node->interval);}// 再檢查右子樹if (node->right != nullptr && node->interval->low <= target->high) {queryOverlapping(node->right, target, result);}
}

查詢算法的流程圖:

刪除操作

刪除操作需要在刪除節點后更新相關節點的max

// 查找最小值節點(最左節點)
IntervalNode* intervalMinimum(IntervalNode *node) {while (node->left != nullptr) {node = node->left;}return node;
}// 區間樹的替換操作
void intervalTransplant(IntervalNode *&root, IntervalNode *u, IntervalNode *v) {if (u->parent == nullptr) {root = v;} else if (u == u->parent->left) {u->parent->left = v;} else {u->parent->right = v;}if (v != nullptr) {v->parent = u->parent;}
}// 刪除區間節點
IntervalNode* deleteIntervalNode(IntervalNode *root, IntervalNode *z) {if (z == nullptr) return root;IntervalNode *y = nullptr;IntervalNode *x = nullptr;// 確定要刪除的節點yif (z->left == nullptr || z->right == nullptr) {y = z;} else {y = intervalMinimum(z->right);}// 確定y的孩子xif (y->left != nullptr) {x = y->left;} else {x = y->right;}// 更新x的父節點if (x != nullptr) {x->parent = y->parent;}// 替換yintervalTransplant(root, y, x);// 如果y不是z,則復制y的內容到zif (y != z) {// 保存z的區間指針以便后續釋放Interval *oldInterval = z->interval;// 復制y的內容到zz->interval = y->interval;z->max = y->max;// 釋放y的區間(因為已經轉移給z了)y->interval = nullptr;delete oldInterval;}// 更新受影響節點的max值IntervalNode *p = y->parent;while (p != nullptr) {updateMax(p);p = p->parent;}// 釋放y的內存if (y->interval != nullptr) {delete y->interval;}delete y;return root;
}// 查找包含特定區間的節點
IntervalNode* findIntervalNode(IntervalNode *root, int low, int high) {IntervalNode *current = root;while (current != nullptr) {if (current->interval->low == low && current->interval->high == high) {return current;} else if (low < current->interval->low) {current = current->left;} else {current = current->right;}}return nullptr;
}

綜合案例:區間樹的應用

下面是一個完整的區間樹應用示例:

#include <iostream>
#include <vector>
using namespace std;// 區間結構定義
struct Interval {int low;int high;Interval(int l, int h) : low(l), high(h) {}
};// 區間樹節點結構定義
struct IntervalNode {Interval *interval;int max;IntervalNode *left;IntervalNode *right;IntervalNode *parent;IntervalNode(int low, int high) : interval(new Interval(low, high)), max(high), left(nullptr), right(nullptr), parent(nullptr) {}
};// 輔助函數聲明
void updateMax(IntervalNode *node);
IntervalNode* insertInterval(IntervalNode *root, int low, int high);
bool overlap(Interval *a, Interval *b);
void queryOverlapping(IntervalNode *node, Interval *target, vector<Interval*>& result);
IntervalNode* intervalMinimum(IntervalNode *node);
void intervalTransplant(IntervalNode *&root, IntervalNode *u, IntervalNode *v);
IntervalNode* deleteIntervalNode(IntervalNode *root, IntervalNode *z);
IntervalNode* findIntervalNode(IntervalNode *root, int low, int high);// 輔助函數實現
void updateMax(IntervalNode *node) {if (node != nullptr) {node->max = node->interval->high;if (node->left != nullptr && node->left->max > node->max) {node->max = node->left->max;}if (node->right != nullptr && node->right->max > node->max) {node->max = node->right->max;}}
}IntervalNode* insertInterval(IntervalNode *root, int low, int high) {IntervalNode *parent = nullptr;IntervalNode **current = &root;while (*current != nullptr) {parent = *current;if (high > (*current)->max) {(*current)->max = high;}if (low < (*current)->interval->low) {current = &((*current)->left);} else {current = &((*current)->right);}}*current = new IntervalNode(low, high);(*current)->parent = parent;return root;
}bool overlap(Interval *a, Interval *b) {return a->low <= b->high && b->low <= a->high;
}void queryOverlapping(IntervalNode *node, Interval *target, vector<Interval*>& result) {if (node == nullptr) return;if (node->left != nullptr && node->left->max >= target->low) {queryOverlapping(node->left, target, result);}if (overlap(node->interval, target)) {result.push_back(node->interval);}if (node->right != nullptr && node->interval->low <= target->high) {queryOverlapping(node->right, target, result);}
}IntervalNode* intervalMinimum(IntervalNode *node) {while (node->left != nullptr) {node = node->left;}return node;
}void intervalTransplant(IntervalNode *&root, IntervalNode *u, IntervalNode *v) {if (u->parent == nullptr) {root = v;} else if (u == u->parent->left) {u->parent->left = v;} else {u->parent->right = v;}if (v != nullptr) {v->parent = u->parent;}
}IntervalNode* deleteIntervalNode(IntervalNode *root, IntervalNode *z) {if (z == nullptr) return root;IntervalNode *y = nullptr;IntervalNode *x = nullptr;if (z->left == nullptr || z->right == nullptr) {y = z;} else {y = intervalMinimum(z->right);}if (y->left != nullptr) {x = y->left;} else {x = y->right;}if (x != nullptr) {x->parent = y->parent;}intervalTransplant(root, y, x);if (y != z) {Interval *oldInterval = z->interval;z->interval = y->interval;z->max = y->max;y->interval = nullptr;delete oldInterval;}IntervalNode *p = y->parent;while (p != nullptr) {updateMax(p);p = p->parent;}if (y->interval != nullptr) {delete y->interval;}delete y;return root;
}IntervalNode* findIntervalNode(IntervalNode *root, int low, int high) {IntervalNode *current = root;while (current != nullptr) {if (current->interval->low == low && current->interval->high == high) {return current;} else if (low < current->interval->low) {current = current->left;} else {current = current->right;}}return nullptr;
}// 打印區間
void printInterval(Interval *interval) {cout << "[" << interval->low << ", " << interval->high << "]";
}int main() {IntervalNode *root = nullptr;// 插入一些區間root = insertInterval(root, 15, 20);root = insertInterval(root, 10, 30);root = insertInterval(root, 17, 19);root = insertInterval(root, 5, 20);root = insertInterval(root, 12, 15);root = insertInterval(root, 30, 40);// 查詢與[14, 16]重疊的區間Interval *target = new Interval(14, 16);vector<Interval*> result;queryOverlapping(root, target, result);cout << "與區間[14, 16]重疊的區間有:" << endl;for (Interval *interval : result) {printInterval(interval);cout << " ";}cout << endl << endl;// 刪除區間[10, 30]IntervalNode *nodeToDelete = findIntervalNode(root, 10, 30);if (nodeToDelete != nullptr) {root = deleteIntervalNode(root, nodeToDelete);cout << "刪除區間[10, 30]后,與[14, 16]重疊的區間有:" << endl;result.clear();queryOverlapping(root, target, result);for (Interval *interval : result) {printInterval(interval);cout << " ";}cout << endl;}// 釋放內存delete target;// 完整的內存釋放還需要遍歷樹刪除所有節點,這里簡化處理return 0;
}

運行結果:

思考題

  1. 如何在動態順序統計樹上實現范圍查詢(即查找所有關鍵字在 [a, b] 之間的元素),并計算該范圍內元素的個數?

  2. 試設計一種基于紅黑樹的區間樹,確保所有操作(插入、刪除、查詢)都能在 O (log n) 時間內完成。

  3. 如何擴展區間樹,使其能高效支持 “查找包含點 x 的所有區間” 這一操作?

  4. 設計一種數據結構,支持在 O (1) 時間內查找最小值,在 O (log n) 時間內插入和刪除元素,以及在 O (log n) 時間內查找第 i 小的元素。

本章注記

  • 數據結構的擴張是解決復雜問題的重要技術,其核心在于找到合適的基礎結構和需要添加的信息
  • 紅黑樹常被用作擴張的基礎結構,因為它能在 O (log n) 時間內支持插入、刪除等操作
  • 除了本章介紹的動態順序統計樹和區間樹,還有許多其他重要的擴張數據結構,如:
    • 線段樹:用于處理區間上的范圍查詢和更新
    • 二叉索引樹(Fenwick 樹):高效支持前綴和查詢和點更新
    • 平衡二叉搜索樹:如 AVL 樹、Splay 樹等,在 BST 基礎上添加了平衡條件

????????希望本章內容能幫助大家理解數據結構擴張的思想和方法。通過動手實現這些數據結構,相信大家能更深入地掌握其中的原理和技巧。如果有任何疑問或建議,歡迎在評論區留言討論!

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

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

相關文章

Vue 3.6 Vapor模式完全指南:告別虛擬DOM,性能飛躍式提升

什么是 Vapor 定義: Vue 3.6 新增的編譯/渲染模式&#xff0c;不再構建/對比虛擬 DOM&#xff0c;而是將模板編譯為“直達 DOM 的更新代碼”&#xff0c;以更低內存與更快更新獲得接近 Solid/Svelte 的性能。特點更快: 跳過 VDOM 創建與 diff&#xff0c;直接按依賴精準更新。…

Java類和對象課上練習題目設計

我們可以做一個簡易銀行賬戶類&#xff0c;支持存款、取款、查看交易記錄等。 示例&#xff1a;BankAccount 類 java 復制 編輯 public class BankAccount { private String accountNumber; // 賬號 private String ownerName; // 開戶人姓名 private double balance; …

Python數據雙效處理:同步轉換與換算的高級技術與工程實踐

引言&#xff1a;轉換與換算在現代數據處理中的核心價值在大數據與實時處理需求激增的時代&#xff0c;高效的數據處理方案成為核心競爭力。根據2025年Python數據工程調查報告&#xff1a;75%的數據處理任務需要同時執行轉換和換算操作優化良好的雙效處理可提升3-8倍性能關鍵應…

Go語言實戰案例:文件上傳服務

在 Web 開發中&#xff0c;文件上傳 是常見需求&#xff0c;例如頭像上傳、文檔存儲、圖片分享等功能。Go 語言的標準庫 net/http 已經內置了對 multipart/form-data 類型的支持&#xff0c;能讓我們輕松構建一個文件上傳服務。本文將帶你實現一個可運行的文件上傳接口&#xf…

【Lua】常用的庫

os庫&#xff1a;os.time() -- 輸出當前時間的時間戳 os.time({year 2014, month 8, day 14}) -- 獲取指定時間的時間戳local nowTime os.date("*t") -- 以表的形式獲取當前的時間信息for k,v in pairs(nowTime) doprint(k,v) end--以上for循環示例輸出 {year 2…

Mac上安裝和配置MySQL(使用Homebrew安裝MySQL 8.0)

在Mac上安裝MySQL是一個簡單高效的過程&#xff0c;尤其是通過Homebrew這一強大的包管理工具。本文將詳細介紹如何在macOS 15.6系統中使用Homebrew安裝MySQL 8.0版本&#xff0c;并完成基本配置&#xff0c;幫助您快速啟動并安全使用MySQL。1. 安裝Homebrew&#xff08;若未安裝…

【Datawhale AI夏令營】從Baseline到SOTA:深度剖析金融問答RAG管道優化之路

從Baseline到SOTA&#xff1a;深度剖析金融問答RAG管道優化之路 引言 檢索增強生成&#xff08;Retrieval-Augmented Generation, RAG&#xff09;已成為構建知識密集型AI應用的事實標準 1。然而&#xff0c;從一個簡單的“hello world”級別的RAG&#xff0c;進化到一個能在競…

AI鑒偽技術:守護數字時代的真實性防線

文章目錄一、引言&#xff1a;AI偽造技術的“數字病毒”與鑒偽技術的“免疫疫苗”二、合合信息三大AI鑒偽技術解析2.1 人臉視頻鑒偽技術&#xff1a;毫秒級擊穿“數字假面”2.1.1 技術突破&#xff1a;從“像素級標記”到“多模態交叉驗證”2.2 AIGC圖像鑒別技術&#xff1a;讓…

論文reading學習記錄7 - daily - ViP3D

文章目錄前言一、題目和摘要二、引言三、相關工作四、方法五、訓練前言 開沖&#xff0c;清華大學的&#xff0c;帶HDmap的端論文&#xff0c;用的Query&#xff0c;和UniAD一樣。 一、題目和摘要 ViP3D: End-to-end Visual Trajectory Prediction via 3D Agent Queries ViP3…

Java學習第一百零九部分——Jenkins(一)

目錄 一、前言簡介 二、核心價值與優勢 三、關鍵概念 四、下載安裝與配置 五、總結歸納概述 一、前言簡介 Jenkins 是一個開源的、基于 Java 的自動化服務器。它的核心使命是實現持續集成和持續交付。簡單來說&#xff0c;Jenkins 是一個強大的工具&#xff0c;用于自動化…

微算法科技(NASDAQ:MLGO)使用循環QSC和QKD的量子區塊鏈架構,提高交易安全性和透明度

隨著量子計算技術的快速發展&#xff0c;傳統區塊鏈所依賴的加密算法面臨著被破解的潛在風險。量子計算的強大計算能力可能會在未來打破現有加密體系的安全性&#xff0c;從而對區塊鏈中的交易數據造成威脅。為了應對這一挑戰&#xff0c;將量子技術與區塊鏈相結合成為了必然的…

MyBatis SQL映射與動態SQL:構建靈活高效的數據訪問層 MyBatis SQL映射與動態SQL:構建靈活高效的數據訪問層

&#x1f504; MyBatis SQL映射與動態SQL&#xff1a;構建靈活高效的數據訪問層 &#x1f680; 引言&#xff1a;動態SQL是MyBatis框架的核心優勢之一&#xff0c;它讓我們能夠根據不同條件動態構建SQL語句&#xff0c;避免了傳統JDBC中大量的字符串拼接。本文將深入解析MyBati…

v-model雙向綁定指令

文章目錄前言v-model.lazy 延遲同步v-model.trim 去掉空格前言 v-model指令是Vue.js中實現雙向數據綁定的一種重要機制。它可以將表單控件的值與Vue.js實例中的數據進行雙向綁定&#xff0c;即當表單控件的值發生變化時&#xff0c;Vue.js實例中的數據也會隨之更新&#xff0c…

電腦IP地址是“169.254.x.x”而無法上網的原因

一、核心原因&#xff1a;自動私有 IP 地址&#xff08;APIPA&#xff09;的啟用APIPA 機制&#xff1a;這是 Windows 等操作系統內置的一種 “備用方案”。當電腦設置為 “自動獲取 IP 地址”&#xff08;通過 DHCP 協議&#xff09;&#xff0c;但無法從路由器、光貓等網絡設…

單片機存儲區域詳解

目錄 單片機內存區域劃分 boot引腳啟動介紹 1. boot引腳的三大啟動區域介紹 1.用戶閃存(User Flash) - 最常用模式 2. 系統存儲區(System Memory) - 出廠預置Bootloader區 3. 內置SRAM啟動(RAM Boot) - 特殊調試模式 2.用戶閃存(User Flash)內存管理詳解 一、用戶閃存中…

Go語言實戰案例:簡易JSON數據返回

在現代 Web 應用中&#xff0c;JSON 已成為前后端通信的主流數據格式。Go 語言標準庫內置對 JSON 的良好支持&#xff0c;只需少量代碼就能返回結構化的 JSON 響應。本篇案例將手把手帶你完成一個「返回 JSON 數據的 HTTP 接口」&#xff0c;幫助你理解如何用 Go 語言實現后端服…

扣子Coze中的觸發器實現流程自動化-實現每日新聞卡片式推送

基礎知識 什么是觸發器/能做什么 Triggers 智能體設置觸發器&#xff08;Triggers&#xff09;&#xff0c;使智能體在特定時間或接收到特定事件時自動執行任務。為什么需要觸發器&#xff1f;實操步驟 第1步&#xff1a;打開一個智能體編輯頁第2步&#xff1a;技能 - 觸發器 -…

GitCode 7月:小程序積分商城更名成長中心、「探索智能倉頡!Cangjie Magic 體驗有獎征文活動」圓滿收官、深度對話欄目持續熱播

運營情況總結 &#x1f389; 截至7月底&#xff0c;GitCode 這個熱鬧的開發者社區&#xff0c;已經聚集了 656 萬位開發者小伙伴啦&#xff01; &#x1f4bb; 產品&#xff1a;小程序積分商城更名為成長中心啦&#xff0c;更多功能將陸續上線。 &#x1f31f; G-Star&#xff…

機器學習之支持向量機(原理)

目錄 摘要 一、概述 二、SVM算法定義 1.超平?最?間隔介紹 2.硬間隔和軟間隔 1.硬間隔分類 2. 軟間隔分類 三、SVM算法原理 1 定義輸?數據 2 線性可分?持向量機 3 SVM的計算過程與算法步驟 四、核函數 五、SVM算法api介紹 1. 核心參數說明 2. 主要方法 3. 重…

【Unity3D實例-功能-跳躍】角色跳躍

今天&#xff0c;我們來聊聊 Unity 里最常打交道的動作之一——角色跳躍。無論是橫版闖關還是 3D 跑酷&#xff0c;跳躍都是讓角色“活”起來的核心操作。在 Unity 里&#xff0c;幾行腳本就能讓角色一蹬而起、穩穩落地。下面&#xff0c;就讓我們一起把這個“彈跳感”親手做出…