內省排序:相對最迅速的通用排序算法

🔍 內省排序:相對最迅速的通用排序算法

🚀 前言:排序算法的演進之路

排序算法是計算機科學的核心基礎之一,其性能直接影響著數據庫系統、科學計算、圖形渲染等領域的效率。隨著硬件架構的發展,排序算法經歷了從簡單到復雜的演化過程:

基礎算法
分治算法
混合算法
硬件優化算法
自適應算法

在眾多排序算法中,內省排序(Introsort) 作為目前公認最快的通用排序算法,被廣泛應用于C++標準庫實現中。本文將深入解析內省排序的原理、實現細節及優化策略,并通過實驗數據展示如何超越標準庫實現。

🧠 一、算法核心原理與架構剖析

1.1 內省排序的設計哲學

內省排序是David Musser于1997年提出的混合排序算法,結合了三種經典算法的優勢:

  • 快速排序:平均O(n log n)時間復雜度
  • 堆排序:保證最壞情況O(n log n)時間復雜度
  • 插入排序:小數據集上的高效表現

![在這里插入圖片描述](https://i-blog.csdnimg.cn/direct/538cad930352435982daf43ddfc42df1.png

1.2 時間復雜度與空間復雜度分析

算法最佳平均最壞空間
快速排序O(n log n)O(n log n)O(n2)O(log n)
堆排序O(n log n)O(n log n)O(n log n)O(1)
插入排序O(n)O(n2)O(n2)O(1)
內省排序O(n)O(n log n)O(n log n)O(log n)

內省排序的關鍵創新在于動態監控遞歸深度,當超過2*log?(n)時切換到堆排序,避免快速排序的最壞情況。

1.3 標準庫實現的優勢與局限

C++標準庫的std::sort采用內省排序,但具有獨特優勢:

  • 編譯器內在優化:使用__builtin_expect等指令優化分支預測
  • 平臺特定優化:針對不同CPU架構的指令集優化
  • 內存訪問優化:精細控制緩存行為

然而,標準庫實現也有其局限性:

  • 固定閾值策略:插入排序和堆排序的切換閾值固定
  • 通用性優先:為各種數據類型優化,犧牲了整數排序的特化性能
  • 保守優化策略:避免使用最新指令集以保證兼容性

?? 二、關鍵優化技術深度解析

2.1 分區算法的演進與優化

2.1.1 基礎分區算法
// 經典Lomuto分區方案
int partition(vector<int>& arr, int low, int high) {int pivot = arr[high];int i = low - 1;for (int j = low; j < high; j++) {if (arr[j] <= pivot) {i++;swap(arr[i], arr[j]);}}swap(arr[i+1], arr[high]);return i+1;
}
2.1.2 三數取中優化
// 改進的樞軸選擇策略
int median_of_three(int a, int b, int c) {if (a < b) {if (b < c) return b;       // a < b < celse if (a < c) return c;  // a < c ≤ belse return a;             // c ≤ a < b} else {if (a < c) return a;       // b ≤ a < celse if (b < c) return c;  // b < c ≤ aelse return b;             // c ≤ b ≤ a}
}
2.1.3 AVX向量化分區
// 使用AVX指令集加速分區過程
int partition_avx(vector<int>& arr, int low, int high) {// ... 三數取中選擇樞軸 ...__m256i pivot_vec = _mm256_set1_epi32(pivot);int* data = arr.data();for (; j <= high - 8; j += 8) {__m256i elements = _mm256_loadu_si256((__m256i*)&data[j]);__m256i cmp = _mm256_cmpgt_epi32(pivot_vec, elements);int mask = _mm256_movemask_ps(_mm256_castsi256_ps(cmp));// 處理比較結果for (int k = 0; k < 8; k++) {if (mask & (1 << k)) {i++;swap(data[i], data[j + k]);}}}// ... 處理剩余元素 ...
}

AVX分區的性能優勢來自:

  1. 并行比較:單次處理8個元素
  2. 減少分支:使用掩碼替代條件分支
  3. 向量化操作:利用SIMD寄存器高效處理數據

2.2 遞歸消除與迭代優化

遞歸調用會導致函數調用開銷和棧空間消耗,內省排序通過迭代實現消除遞歸:

void quick_sort_iterative(vector<int>& arr, int low, int high) {stack<pair<int, int>> stk;stk.push({low, high});while (!stk.empty()) {tie(low, high) = stk.top();stk.pop();if (high - low < THRESHOLD) {insertion_sort(arr.data(), low, high);continue;}int pi = partition(arr, low, high);// 優先處理較小分區以控制棧深度if (pi - low < high - pi) {if (low < pi - 1) stk.push({low, pi - 1});if (pi + 1 < high) stk.push({pi + 1, high});} else {if (pi + 1 < high) stk.push({pi + 1, high});if (low < pi - 1) stk.push({low, pi - 1});}}
}

2.3 閾值調優的藝術

閾值選擇對性能有決定性影響:

小數據集
小閾值
大數據集
大閾值
CPU緩存
緩存行對齊
數據類型
比較成本

實驗數據顯示:

  • 32閾值:在50萬數據量以下表現優異
  • 512閾值:在500萬數據量以上超越標準庫

📊 三、性能對比與實驗分析

3.1 測試環境與方法論

  • 硬件:AMD R9-7945HX (16P+16L), 32*2GB DDR5 5600MHz
  • 編譯器:Microsoft Visual Studio 2022, /O2優化
  • 數據集:隨機整數數組,均勻分布
  • 測試方法:5次運行取平均值,排除緩存預熱影響

3.2 關鍵性能數據對比

3.2.1 閾值32的性能表現(單位:ms)
數據量普通快排AVX快排內省排序標準庫內省/標準庫
100K4.423.573.523.990.88
500K31.5818.0217.7818.660.95
1M85.6037.3036.2236.041.00
5M1299.88267.44242.61171.481.41
3.2.2 閾值512的性能表現(單位:ms)
數據量普通快排AVX快排內省排序標準庫內省/標準庫
100K4.344.765.993.941.52
500K31.4926.4630.6918.601.65
1M86.1651.7558.1235.811.62
5M1299.02153.88153.14180.690.85

3.3 關鍵發現與洞見

  1. 小數據集優勢

    • 32閾值內省排序在50萬數據量內超越標準庫
    • 優勢來自優化的插入排序和更少的函數調用
  2. 大數據集反轉

    • 5M數據量時,512閾值內省排序性能優于標準庫15%
    • 主要來自AVX加速和優化的閾值策略
  3. AVX的邊界效應

    數據量 < 100K
    AVX開銷 > 收益
    100K < 數據量 < 1M
    顯著加速
    數據量 > 1M
    線性加速
  4. 內存訪問模式

    • 標準庫在5M數據量仍有優勢,源于優化的緩存策略
    • 自定義實現可通過調整內存布局進一步優化

🎯 四、各算法適用場景與策略指南

4.1 算法特性對比矩陣

特性普通快排AVX快排內省排序標準庫
最佳數據量10K-100K100K-1M全范圍全范圍
最壞時間復雜度O(n2)O(n2)O(n log n)O(n log n)
平臺依賴性x86/AVX
實現復雜度封裝
小數據集性能★★☆★★☆★★★★★☆
大數據集性能★☆☆★★☆★★★★★☆
可調優性

4.2 實用決策樹

< 50K
50K-500K
> 500K
選擇排序算法
數據規模
平臺支持AVX?
32閾值內省+AVX
32閾值內省
標準庫
需要最優化?
512閾值內省+AVX
標準庫

4.3 各場景最佳實踐

  1. 嵌入式系統

    • 使用純插入排序或小閾值內省排序
    • 避免AVX依賴和遞歸
  2. 科學計算

    • 512閾值內省排序+AVX加速
    • 數據預處理確保內存對齊
  3. 數據庫系統

    • 標準庫為主,特定模塊定制
    • 混合使用不同閾值策略
  4. 游戲開發

    • 小數據使用32閾值內省
    • 大數據使用標準庫

🚀 五、超越標準庫的優化策略

5.1 動態閾值調整

實驗顯示固定閾值存在局限,實現動態閾值策略:

int dynamic_threshold(size_t n) {// 基于數據量和緩存大小計算閾值const size_t L1_cache_size = 32768; // 32KBconst size_t elem_size = sizeof(int);const size_t elems_in_cache = L1_cache_size / elem_size;if (n < 50000) return 32;else if (n < 1000000) return 64;else return min(512, static_cast<int>(elems_in_cache / 4));
}

5.2 混合內存布局

優化內存訪問模式提升緩存利用率:

小數據集
大數據集
原始數據
數據規模
連續存儲
分塊存儲
塊內排序
多路歸并

5.3 多核并行擴展

void parallel_intro_sort(vector<int>& arr) {const size_t threshold = 1000000;if (arr.size() < threshold) {intro_sort(arr);return;}unsigned conc_threads = thread::hardware_concurrency();vector<future<void>> futures;vector<vector<int>> segments(conc_threads);// 數據劃分size_t seg_size = arr.size() / conc_threads;for (int i = 0; i < conc_threads; ++i) {auto begin = arr.begin() + i * seg_size;auto end = (i == conc_threads - 1) ? arr.end() : begin + seg_size;segments[i] = vector<int>(begin, end);futures.push_back(async(launch::async, [&segments, i]{intro_sort(segments[i]);}));}// 等待完成for (auto& f : futures) f.wait();// 多路歸并// ... 高效合并已排序段 ...
}

📌 結論與工程建議

  1. 標準庫優先原則

    • 大多數場景優先使用std::sort
    • 避免過早優化
  2. 定制化場景

    • 50萬以下數據:32閾值內省排序
    • 500萬以上數據:512閾值+AVX內省排序
    • 特定硬件:深度優化AVX/NEON實現
  3. 持續性能分析

    真實負載
    性能剖析
    熱點分析
    算法優化
    參數調整
    部署驗證
  4. 全棧優化思維

    • 算法選擇與數據預處理結合
    • 內存布局與算法協同設計
    • 硬件特性充分挖掘

🧩 附錄一:算法實機性能測試

內省排序閾值: 32

在這里插入圖片描述

內省排序閾值: 512

在這里插入圖片描述

🧩 附錄二:完整算法實現及例程代碼

#include <iostream>
#include <vector>
#include <random>
#include <chrono>
#include <algorithm>
#include <immintrin.h>
#include <cmath>
#include <stack>
#include <tuple>
#include <iomanip>using namespace std;
using namespace std::chrono;// 插入排序 - 使用指針減少索引計算
void insertion_sort(int* arr, int low, int high) {for (int i = low + 1; i <= high; i++) {int key = arr[i];int j = i - 1;// 使用指針算術int* p = arr + j;while (j >= low && *p > key) {*(p + 1) = *p;j--;p--;}*(p + 1) = key;}
}// 三數取中法選擇樞軸
inline int median_of_three(int a, int b, int c) {if (a < b) {if (b < c) return b;else if (a < c) return c;else return a;}else {if (a < c) return a;else if (b < c) return c;else return b;}
}// 普通快速排序分區函數
int partition_normal(vector<int>& arr, int low, int high) {// 使用三數取中法選擇樞軸int mid = low + (high - low) / 2;int pivot = median_of_three(arr[low], arr[mid], arr[high]);// 將樞軸放到最后if (pivot == arr[low])swap(arr[low], arr[high]);else if (pivot == arr[mid])swap(arr[mid], arr[high]);int i = low - 1;int* data = arr.data();// 使用指針算術循環for (int j = low; j < high; j++) {if (data[j] <= pivot) {i++;swap(data[i], data[j]);}}swap(data[i + 1], data[high]);return i + 1;
}// 普通快速排序 - 使用迭代代替遞歸減少函數調用開銷
void quick_sort_normal_iterative(vector<int>& arr, int low, int high) {stack<pair<int, int>> stk;stk.push({ low, high });while (!stk.empty()) {tie(low, high) = stk.top();stk.pop();if (high - low < 16) {insertion_sort(arr.data(), low, high);continue;}int pi = partition_normal(arr, low, high);// 先處理較小的子數組以減少棧深度if (pi - low < high - pi) {if (low < pi - 1) stk.push({ low, pi - 1 });if (pi + 1 < high) stk.push({ pi + 1, high });}else {if (pi + 1 < high) stk.push({ pi + 1, high });if (low < pi - 1) stk.push({ low, pi - 1 });}}
}// AVX分區函數 - 減少內存訪問和分支
int partition_avx(vector<int>& arr, int low, int high) {// 使用三數取中法選擇樞軸int mid = low + (high - low) / 2;int pivot = median_of_three(arr[low], arr[mid], arr[high]);// 將樞軸放到最后if (pivot == arr[low])swap(arr[low], arr[high]);else if (pivot == arr[mid])swap(arr[mid], arr[high]);int i = low - 1;int j = low;const int simd_width = 8;int* data = arr.data();// 預加載樞軸值__m256i pivot_vec = _mm256_set1_epi32(pivot);// 處理可以對齊SIMD寬度的部分for (; j <= high - simd_width; j += simd_width) {// 非對齊加載數據__m256i elements = _mm256_loadu_si256((__m256i*) & data[j]);// 比較: elements <= pivot__m256i cmp = _mm256_cmpgt_epi32(pivot_vec, elements);int mask = _mm256_movemask_ps(_mm256_castsi256_ps(cmp));// 處理比較結果for (int k = 0; k < simd_width; k++) {if (mask & (1 << k)) {i++;swap(data[i], data[j + k]);}}}// 處理剩余元素for (; j < high; j++) {if (data[j] <= pivot) {i++;swap(data[i], data[j]);}}// 將樞軸放到正確位置swap(data[i + 1], data[high]);return i + 1;
}// AVX快速排序 - 使用迭代實現
void quick_sort_avx_iterative(vector<int>& arr, int low, int high) {stack<pair<int, int>> stk;stk.push({ low, high });while (!stk.empty()) {tie(low, high) = stk.top();stk.pop();if (high - low < 32) {  // 使用更大的閾值insertion_sort(arr.data(), low, high);continue;}int pi = partition_avx(arr, low, high);// 先處理較小的子數組以減少棧深度if (pi - low < high - pi) {if (low < pi - 1) stk.push({ low, pi - 1 });if (pi + 1 < high) stk.push({ pi + 1, high });}else {if (pi + 1 < high) stk.push({ pi + 1, high });if (low < pi - 1) stk.push({ low, pi - 1 });}}
}// 內省排序實現
void intro_sort(vector<int>& arr, int low, int high, int depth_limit) {// 如果數組很小,使用插入排序if (high - low < 32) {insertion_sort(arr.data(), low, high);return;}// 如果遞歸深度達到限制,使用堆排序if (depth_limit == 0) {make_heap(arr.begin() + low, arr.begin() + high + 1);sort_heap(arr.begin() + low, arr.begin() + high + 1);return;}// 使用的AVX分區int pi = partition_avx(arr, low, high);intro_sort(arr, low, pi - 1, depth_limit - 1);intro_sort(arr, pi + 1, high, depth_limit - 1);
}// 內省排序入口函數
void intro_sort(vector<int>& arr) {int n = arr.size();if (n <= 1) return;// 計算最大遞歸深度為2*log極(n)int depth_limit = static_cast<int>(2 * log2(n));intro_sort(arr, 0, n - 1, depth_limit);
}// 生成隨機測試數據 - 使用更高效的方法
vector<int> generate_random_data(size_t size, int min_val = 0, int max_val = 10000) {vector<int> data(size);random_device rd;mt19937 gen(rd());uniform_int_distribution<> dis(min_val, max_val);// 使用指針算術循環int* data_ptr = data.data();for (size_t i = 0; i < size; i++) {data_ptr[i] = dis(gen);}return data;
}// 驗證兩個數組是否相同 - 使用memcmp
bool verify_equality(const vector<int>& arr1, const vector<int>& arr2) {if (arr1.size() != arr2.size()) return false;return memcmp(arr1.data(), arr2.data(), arr1.size() * sizeof(int)) == 0;
}// 性能測試函數
void performance_test(size_t data_size, int num_tests = 5) {cout << "數據量: " << data_size << " 元素" << endl;cout << "測試次數: " << num_tests << endl;cout << "==========================================" << endl;double normal_total_time = 0.0;double avx_total_time = 0.0;double intro_total_time = 0.0;double std_total_time = 0.0;// 表頭cout << left << setw(8) << "測試"<< setw(15) << "普通(ms)"<< setw(15) << "AVX(ms)"<< setw(15) << "內省(ms)"<< setw(15) << "標準庫(ms)"<< setw(15) << "AVX/普通"<< setw(15) << "內省/普通"<< setw(15) << "標準庫/普通"<< setw(15) << "AVX/標準庫"<< setw(15) << "內省/標準庫"<< setw(20) << "性能排名" << endl;cout << "------------------------------------------------------------------------------------------------------------------------------------------------------------------------" << endl;for (int i = 0; i < num_tests; i++) {// 生成測試數據vector<int> data_normal = generate_random_data(data_size);vector<int> data_avx = data_normal;vector<int> data_intro = data_normal;vector<int> data_std = data_normal;// 測試標準庫排序auto start = high_resolution_clock::now();sort(data_std.begin(), data_std.end());auto end = high_resolution_clock::now();double std_time = duration_cast<microseconds>(end - start).count() / 1000.0;std_total_time += std_time;// 測試普通快速排序start = high_resolution_clock::now();quick_sort_normal_iterative(data_normal, 0, data_size - 1);end = high_resolution_clock::now();double normal_time = duration_cast<microseconds>(end - start).count() / 1000.0;normal_total_time += normal_time;// 測試AVX快速排序start = high_resolution_clock::now();quick_sort_avx_iterative(data_avx, 0, data_size - 1);end = high_resolution_clock::now();double avx_time = duration_cast<microseconds>(end - start).count() / 1000.0;avx_total_time += avx_time;// 測試內省排序start = high_resolution_clock::now();intro_sort(data_intro);end = high_resolution_clock::now();double intro_time = duration_cast<microseconds>(end - start).count() / 1000.0;intro_total_time += intro_time;// 驗證結果正確性bool normal_correct = verify_equality(data_normal, data_std);bool avx_correct = verify_equality(data_avx, data_std);bool intro_correct = verify_equality(data_intro, data_std);// 計算比值double avx_vs_normal = avx_time / normal_time;double intro_vs_normal = intro_time / normal_time;double std_vs_normal = std_time / normal_time;double avx_vs_std = avx_time / std_time;double intro_vs_std = intro_time / std_time;// 確定性能排名vector<pair<double, string>> times = {{normal_time, "普通"},{avx_time, "AVX"},{intro_time, "內省"},{std_time, "標準庫"}};sort(times.begin(), times.end());string ranking;for (int j = 0; j < 4; j++) {if (j > 0) ranking += " > ";ranking += times[j].second;}cout << left << setw(8) << i + 1<< setw(15) << fixed << setprecision(2) << normal_time<< setw(15) << fixed << setprecision(2) << avx_time<< setw(15) << fixed << setprecision(2) << intro_time<< setw(15) << fixed << setprecision(2) << std_time<< setw(15) << fixed << setprecision(3) << avx_vs_normal<< setw(15) << fixed << setprecision(3) << intro_vs_normal<< setw(15) << fixed << setprecision(3) << std_vs_normal<< setw(15) << fixed << setprecision(3) << avx_vs_std<< setw(15) << fixed << setprecision(3) << intro_vs_std<< setw(20) << ranking << endl;}// 計算平均時間double normal_avg = normal_total_time / num_tests;double avx_avg = avx_total_time / num_tests;double intro_avg = intro_total_time / num_tests;double std_avg = std_total_time / num_tests;// 計算平均比值double avx_vs_normal_avg = avx_avg / normal_avg;double intro_vs_normal_avg = intro_avg / normal_avg;double std_vs_normal_avg = std_avg / normal_avg;double avx_vs_std_avg = avx_avg / std_avg;double intro_vs_std_avg = intro_avg / std_avg;// 確定平均性能排名vector<pair<double, string>> avg_times = {{normal_avg, "普通"},{avx_avg, "AVX"},{intro_avg, "內省"},{std_avg, "標準庫"}};sort(avg_times.begin(), avg_times.end());string avg_ranking;for (int j = 0; j < 4; j++) {if (j > 0) avg_ranking += " > ";avg_ranking += avg_times[j].second;}// 找出最佳算法string best_algorithm = avg_times[0].second;string best_algorithm_note = "性能最佳算法: " + best_algorithm;cout << "------------------------------------------------------------------------------------------------------------------------------------------------------------------------" << endl;cout << left << setw(8) << "平均"<< setw(15) << fixed << setprecision(2) << normal_avg<< setw(15) << fixed << setprecision(2) << avx_avg<< setw(15) << fixed << setprecision(2) << intro_avg<< setw(15) << fixed << setprecision(2) << std_avg<< setw(15) << fixed << setprecision(3) << avx_vs_normal_avg<< setw(15) << fixed << setprecision(3) << intro_vs_normal_avg<< setw(15) << fixed << setprecision(3) << std_vs_normal_avg<< setw(15) << fixed << setprecision(3) << avx_vs_std_avg<< setw(15) << fixed << setprecision(3) << intro_vs_std_avg<< setw(20) << avg_ranking << endl;cout << "========================================================================================================================================================================" << endl;cout << best_algorithm_note << endl;cout << "========================================================================================================================================================================" << endl << endl;
}int main() {cout << "排序算法性能測試" << endl;cout << "==========================================" << endl << endl;// 測試不同數據量performance_test(100000);performance_test(500000);performance_test(1000000);performance_test(5000000);return 0;
}

最終優化建議:在實際工程中,建議創建動態閾值適配層,根據運行時數據特征自動選擇最優策略

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

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

相關文章

Linux驅動開發重要操作匯總

本文主要記錄imx6ull的linux驅動開發過程中常用的一些操作。 uboot編譯 make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- distclean make ARCHarm CROSS_COMPILEarm-linux-gnueabihf mx6ull_14x14_evk_emmc_defconfig make V1 ARCHarm CROSS_COMPILEarm-linux-gnueabihf- …

【Java后端】MySQL 常見 SQL 語句優化指南

在 MySQL 中&#xff0c;SQL 優化是性能調優的核心環節&#xff0c;尤其是在數據量大、并發高的情況下。這里整理一份 MySQL 常見 SQL 語句優化指南&#xff0c;從查詢寫法、索引使用到執行計劃分析&#xff0c;涵蓋實用技巧&#xff1a;1. 查詢語句層面的優化 ? 避免 SELECT …

Golang 面試題「高級」

以下是 100 道 Golang 高級面試題及答案&#xff0c;聚焦語言底層實現、并發深度優化、性能調優、源碼級理解等核心方向&#xff0c;適合資深開發者或架構師級別的面試場景&#xff1a; 一、GPM 調度模型與并發深度 問題&#xff1a;Goroutine 的棧空間初始大小是多少&#xff…

WebGIS視角:體感溫度實證,哪座“火爐”火力全開?

目錄 前言 一、火爐城市空間分布及特點 1、空間分布 2、氣候特點 二、數據來源及技術實現 1、數據來源介紹 2、技術路線簡介 三、WebGIS系統實現 1、后端設計與實現 2、前端程序實現 四、成果展示 1、整體展示 2、蒸烤模式城市 3、舒適城市 五、總結 前言 “火爐…

《數據結構入門:順序表的結構設計與核心操作(C 語言版)》

目錄 一. 線性表 二. 順序表的概念與結構 2.1 核心概念 2.2 兩種常見結構 靜態順序表 動態順序表 2.3 核心區別對比 四. 順序表的實現 4.1 順序表的定義 4.2 順序表初始化 4.3 動態順序表容量檢查與擴容 4.4 動態順序表插入數據 4.4.1 頭插 4.4.2 尾插 4.4.3 指…

[Maven 基礎課程]Maven 是什么

Maven 的官方網站&#xff1a;https://maven.apache.org/ 來自 Maven 官網的對于 Maven 是什么的描述&#xff1a; Apache Maven is a build tool for Java projects. Using a project object model (POM), Maven manages a project’s compilation, testing, and documentat…

【MATLAB例程】三維組合導航,濾波使用EKF,帶嚴格的慣導推算、雅克比求解函數,圖像對比濾波前后的速度、位置、姿態

文章目錄程序介紹系統建模濾波框架仿真設置性能對比代碼優點運行結果MATLAB源代碼程序介紹 本程序實現了 三維狀態量的擴展卡爾曼濾波&#xff08;EKF&#xff09;組合導航仿真&#xff0c;采用嚴格的15維誤差狀態模型&#xff0c;狀態向量包括&#xff1a; x[pxpypzvxvyvz?θ…

港資企業在大陸,如何靠 SD-WAN 專線暢連香港?

在當前市場形勢下&#xff0c;港資企業在大陸的業務布局不斷拓展&#xff0c;企業間訪問香港總部系統以及香港員工到內陸出差時訪問相關系統&#xff0c;成為日常運營的高頻需求。然而&#xff0c;網絡問題卻常常阻礙業務的順暢開展&#xff0c;基于 SD-WAN 專線的到香港加速網…

并發編程——08 Semaphore源碼分析

1 概述Semaphore 是基于 AQS CAS 實現的&#xff0c;可根據構造參數的布爾值&#xff0c;選擇使用公平鎖&#xff0c;還是非公平鎖。Semaphore 默認使用非公平鎖&#xff1b;2 構造函數 // AQS的實現 private final Sync sync;// 默認使用非公平鎖 public Semaphore(int permi…

Java全棧開發面試實戰:從基礎到微服務的深度解析

Java全棧開發面試實戰&#xff1a;從基礎到微服務的深度解析 一、面試開場 面試官&#xff08;中年工程師&#xff0c;穿著休閑但專業&#xff09;&#xff1a;你好&#xff0c;我是李工&#xff0c;今天來聊一下你的技術背景。你之前在XX科技做全棧開發&#xff0c;對吧&#…

CVPR深度學習論文創新合集拆解:模型訓練速度算提升

關注gongzhonghao【CVPR頂會精選】大語言模型擴散Transformer的深度融合&#xff0c;讓文本到圖像生成更精準、細節更豐富&#xff1b;同時&#xff0c;專家軌跡正則化深度強化學習在自動對焦中的穩定加速表現&#xff0c;也展示了深度學習與軌跡建模結合的潛力。這樣的組合正在…

【智能體】零代碼學習 Coze 智能體(2)創建智能體的完整步驟

歡迎關注【AGI使用教程】 專欄 【智能體】零代碼學習 Coze 智能體&#xff08;1&#xff09; 【智能體】零代碼學習 Coze 智能體&#xff08;2&#xff09; 【智能體】零代碼學習 Coze 智能體&#xff08;1&#xff09;1、登錄 Coze 平臺2、創建智能體3、智能體編排頁面4、編寫…

WPF和WinFrom區別

WPF 總結Windows Presentation Foundation (WPF) 是微軟開發的一個用于構建 Windows 桌面應用程序的用戶界面框架。它基于 .NET Framework&#xff0c;提供豐富的圖形、動畫和數據綁定功能&#xff0c;幫助開發者創建現代化、高性能的應用程序。以下是其核心要點總結&#xff1…

數據庫原理及應用_數據庫基礎_第3章數據庫編程_常用系統函數

前言 "<數據庫原理及應用>(MySQL版)".以下稱為"本書"中3.1.2節內容 引入 數據庫常用系統函數的分析.上一篇帖子分析了,數據庫函數需要看看能否被C語言函數替代 1.字符串函數 1)計算字符串字符數的函數和字符串長度的函數 語法: CHAR_LENGTH(str)…

回歸問題的損失函數

簡單來說&#xff0c;?在回歸問題中&#xff0c;最常用的損失函數是均方誤差&#xff08;MSE, Mean Squared Error&#xff09;和平均絕對誤差&#xff08;MAE, Mean Absolute Error&#xff09;?。它們衡量的都是模型預測值&#xff08;?&#xff09;與真實值&#xff08;y…

吳恩達機器學習(四)

一、神經網絡神經元模擬邏輯單元&#xff1a;神經網絡簡單模型&#xff1a;神經網絡中的前向傳播過程&#xff1a;依次計算激活項&#xff0c;從輸入層到隱藏層再到輸出層的過程。樣例&#xff1a;多元分類&#xff1a;

【重學 MySQL】九十三、MySQL的字符集的修改與底層原理詳解

【重學 MySQL】九十三、MySQL的字符集的修改與底層原理詳解一、字符集修改方法1. **配置文件修改**2. **SQL命令修改**3. **數據遷移方案**二、底層原理與注意事項1. **字符集與排序規則**2. **存儲與性能影響**3. **數據一致性風險**三、常見問題解決1. **亂碼問題**2. **性能…

pdf 轉圖片工具實現

一、安裝 sudo yum install poppler-utils pdftoppm -v pdftoppm -png -r 300 a.pdf /tmp/page 運行效果&#xff1a; PDF轉圖片工具 - 在線PDF轉PNG/JPG/TIFF轉換器 | 免費在線工具 后臺實現&#xff1a; using System.Diagnostics; using System.IO.Compression;namespac…

Zynq開發實踐(FPGA之輸入、輸出整合)

【 聲明&#xff1a;版權所有&#xff0c;歡迎轉載&#xff0c;請勿用于商業用途。 聯系信箱&#xff1a;feixiaoxing 163.com】fpga開發的時候習慣上先把功能拆分成若干個模塊。針對這些模塊&#xff0c;一個一、個實現好之后&#xff0c;再用wire連接即可。這一點有點像軟件編…

【Linux基礎】深入理解計算機啟動原理:MBR主引導記錄詳解

目錄 引言 1 硬盤分區初始化概述 1.1 為什么需要硬盤分區 1.2 硬盤分區格式的發展 1.3 分區初始化的基本流程 2 MBR詳解 2.1 MBR的定義與位置 2.2 MBR的結構詳解 2.3 分區表結構詳解 2.4 MBR的工作原理 2.5 MBR的引導程序 3 MBR的局限性 3.1 硬盤容量限制 3.2 分…