優化算法
- 第五章重難點詳解與代碼實戰
- 編譯與測試說明
- 第五章核心知識點整理
- 重難點梳理
- 第一部分:多選題(10道)
- 第二部分:設計題(5道)
- 答案與詳解
- 多選題答案:
- 設計題參考實現(以題目2為例)
- 代碼說明:
- 測試用例設計要點
第五章重難點詳解與代碼實戰
- 時間復雜度分析(5.1節)
重點:掌握大O符號含義,區分最優/平均/最差情況時間復雜度。
示例:插入排序時間復雜度分析
#include <iostream>
#include <vector>
using namespace std;// 插入排序實現
void insertionSort(vector<int>& arr) {for (int i = 1; i < arr.size(); ++i) {int key = arr[i];int j = i-1;while (j >= 0 && arr[j] > key) {arr[j+1] = arr[j];j--;}arr[j+1] = key;}
}int main() {vector<int> test1 = {5, 2, 4, 6, 1, 3}; // 平均情況insertionSort(test1);cout << "Sorted average case: ";for (int num : test1) cout << num << " ";cout << endl;vector<int> test2 = {6, 5, 4, 3, 2, 1}; // 最壞情況(逆序)insertionSort(test2);cout << "Sorted worst case: ";for (int num : test2) cout << num << " ";return 0;
}
測試:觀察不同輸入下的執行時間差異(平均O(n2),最優O(n))。
- 查找算法優化(5.3節)
重點:線性查找 vs 二分查找時間復雜度差異。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;// 線性查找 O(n)
int linearSearch(const vector<int>& arr, int target) {for (int i = 0; i < arr.size(); ++i) {if (arr[i] == target) return i;}return -1;
}// 二分查找 O(log n)
int binarySearch(const vector<int>& arr, int target) {int left = 0, right = arr.size()-1;while (left <= right) {int mid = left + (right - left)/2;if (arr[mid] == target) return mid;if (arr[mid] < target) left = mid + 1;else right = mid - 1;}return -1;
}int main() {vector<int> arr = {1, 3, 5, 7, 9, 11};int target = 7;cout << "Linear search index: " << linearSearch(arr, target) << endl;cout << "Binary search index: " << binarySearch(arr, target) << endl;// 性能對比測試(需添加計時邏輯)return 0;
}
優化點:預處理排序后使用二分查找大幅提升效率。
- 排序算法優化(5.4節)
重點:快速排序優化(三數取中法避免最壞情況)
#include <iostream>
#include <vector>
using namespace std;// 三數取中法選擇pivot
int medianOfThree(vector<int>& arr, int left, int right) {int mid = left + (right - left)/2;if (arr[mid] < arr[left]) swap(arr[left], arr[mid]);if (arr[right] < arr[left]) swap(arr[left], arr[right]);if (arr[mid] < arr[right]) swap(arr[mid], arr[right]);return right;
}// 快速排序優化實現
void quickSort(vector<int>& arr, int left, int right) {if (left >= right) return;// 選擇pivot并分區int pivot = medianOfThree(arr, left, right);int i = left - 1;for (int j = left; j < right; ++j) {if (arr[j] <= arr[pivot]) {i++;swap(arr[i], arr[j]);}}swap(arr[i+1], arr[pivot]);int partitionIndex = i + 1;quickSort(arr, left, partitionIndex-1);quickSort(arr, partitionIndex+1, right);
}int main() {vector<int> test = {3, 6, 8, 10, 1, 2, 1};quickSort(test, 0, test.size()-1);cout << "Optimized QuickSort: ";for (int num : test) cout << num << " ";return 0;
}
測試:對比標準快速排序與優化版本在逆序數組中的性能。
- 優化模式:緩存(5.5.4節)
示例:斐波那契數列的緩存優化
#include <iostream>
#include <unordered_map>
using namespace std;unordered_map<int, int> cache;// 帶緩存的遞歸斐波那契
int fib(int n) {if (n <= 1) return n;if (cache.find(n) != cache.end()) return cache[n];cache[n] = fib(n-1) + fib(n-2);return cache[n];
}int main() {cout << "Fib(10): " << fib(10) << endl; // 55cout << "Fib(20): " << fib(20) << endl; // 6765return 0;
}
優化效果:時間復雜度從O(2?)降為O(n)。
- 斯特潘諾夫抽象懲罰(5.6節)
重點:泛型編程帶來的性能損耗分析
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;// 自定義簡單排序(無抽象)
void simpleSort(int* arr, int size) {for (int i=0; i<size; ++i)for (int j=i+1; j<size; ++j)if (arr[j] < arr[i])swap(arr[i], arr[j]);
}// 測試對比
int main() {vector<int> data(10000);generate(data.begin(), data.end(), rand);// 測試STL排序(模板抽象)auto stlData = data;sort(stlData.begin(), stlData.end());// 測試簡單排序(直接實現)auto simpleData = data;simpleSort(&simpleData[0], simpleData.size());// 添加計時代碼比較性能差異return 0;
}
結論:抽象層級越高可能帶來額外開銷,需權衡可維護性與性能。
編譯與測試說明
- 所有代碼均使用C++11或更高標準編譯:
g++ -std=c++11 example.cpp -o example
- 添加計時邏輯推薦使用
<chrono>
庫:
#include <chrono>
auto start = chrono::high_resolution_clock::now();
// ...測試代碼...
auto end = chrono::high_resolution_clock::now();
cout << "Time: " << chrono::duration_cast<chrono::microseconds>(end-start).count() << "μs\n";
第五章核心知識點整理
重難點梳理
- 算法時間復雜度分析(最優/平均/最壞情況)
- 哈希表與二分查找的性能對比
- 排序算法的選擇策略(快速排序 vs 基數排序)
- 預計算與延遲計算的應用場景
- 緩存策略的失效處理機制
- 雙重檢查鎖定模式的應用
- 散列函數設計原則
- 分治策略在排序中的應用
- 算法選擇時的內存局部性考量
- 攤銷時間復雜度分析
第一部分:多選題(10道)
-
關于哈希表查找性能,正確的是:
A) 平均時間復雜度O(1)
B) 最壞時間復雜度O(n)
C) 適合有序數據查詢
D) 空間復雜度總是O(n) -
快速排序的優化策略包括:
A) 三數取中法選擇樞軸
B) 小數組切換插入排序
C) 遞歸實現優先于迭代
D) 處理重復元素的3-way partition -
適合處理海量數據的排序算法:
A) 基數排序
B) 歸并排序
C) 冒泡排序
D) Flashsort -
關于二分查找正確的是:
A) 要求數據有序
B) 時間復雜度O(n)
C) 適合鏈表結構
D) 可處理動態數據集 -
預計算模式的適用場景:
A) 運行時頻繁計算的固定值
B) 需要實時更新的動態數據
C) 編譯期已知的常量表達式
D) 內存敏感的低配設備 -
緩存失效的常見處理方式:
A) LRU置換策略
B) 定時強制刷新
C) 寫穿透策略
D) 哈希碰撞鏈表法 -
關于時間復雜度分析:
A) 插入排序最壞O(n2)
B) 快速排序平均O(n logn)
C) 基數排序O(nk) k為位數
D) 冒泡排序最優O(n) -
雙重檢查鎖定用于:
A) 單例模式初始化
B) 線程安全緩存訪問
C) 原子計數器操作
D) 無鎖數據結構設計 -
影響算法實際性能的因素:
A) 緩存命中率
B) 分支預測效率
C) 循環展開次數
D) 指令流水線深度 -
關于分治策略:
A) 快速排序基于分治
B) 歸并排序需要額外空間
C) 適合并行計算
D) 總將問題分為兩等份
第二部分:設計題(5道)
題目1:延遲計算緩存系統
設計支持過期時間的緩存系統,要求:
- 使用unordered_map存儲數據
- 支持惰性清理過期條目
- 線程安全的雙重檢查鎖定
- 提供get/put接口
題目2:預計算優化斐波那契
實現基于預計算的斐波那契數列:
- 編譯期生成前50項
- 運行時直接查表
- 處理溢出異常
- 支持動態擴展
題目3:快速排序優化
實現優化的快速排序:
- 三數取中選擇樞軸
- 小數組切換插入排序
- 迭代替代遞歸
- 處理重復元素
題目4:哈希表性能優化
設計高性能哈希表:
- 開放尋址法解決沖突
- 負載因子超過0.75時擴容
- 使用素數表控制容量
- 支持移動語義
題目5:二分查找邊界處理
實現泛型二分查找:
- 處理重復元素的第一個/最后一個位置
- 支持旋轉有序數組
- 異常安全保證
- 性能測試對比線性搜索
答案與詳解
多選題答案:
- AB(哈希表平均O(1),最壞O(n))
- ABD(三數取中、小數組優化、3-way分區)
- ABD(基數、歸并、Flashsort適合大數據)
- A(必須有序)
- AC(固定值和編譯期計算)
- ABC(LRU、刷新、寫穿透)
- ABC(插入最壞O(n2),快排平均O(n logn),基數O(nk))
- AB(單例和緩存訪問)
- ABCD(全部影響實際性能)
- ABC(快排分治、歸并需空間、可并行)
設計題參考實現(以題目2為例)
#include <iostream>
#include <vector>
#include <stdexcept>template<typename T>
class FibonacciCache {std::vector<T> cache;static const size_t INIT_SIZE = 50;
public:FibonacciCache() {cache.reserve(INIT_SIZE);cache.push_back(0);cache.push_back(1);for(size_t i=2; i<INIT_SIZE; ++i){T next = cache[i-1] + cache[i-2];if(next < cache[i-1]) throw std::overflow_error("Overflow in precomputation");cache.push_back(next);}}T get(size_t n) {while(n >= cache.size()){size_t i = cache.size();T next = cache[i-1] + cache[i-2];if(next < cache[i-1]) throw std::overflow_error("Overflow during expansion");cache.push_back(next);}return cache[n];}
};int main() {try {FibonacciCache<unsigned long long> fib;// Test precomputed valuesstd::cout << fib.get(10) << std::endl; // 55std::cout << fib.get(49) << std::endl; // 7778742049// Test dynamic expansionstd::cout << fib.get(50) << std::endl; // 12586269025// Test overflow detectionFibonacciCache<unsigned> small_fib;small_fib.get(47); // Throw overflow} catch(const std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;}return 0;
}
代碼說明:
- 模板類支持不同數值類型
- 編譯期預計算前50項
- 運行時動態擴展緩存
- 溢出檢測機制
- 異常安全保證
測試用例設計要點
- 驗證預計算正確性(n=10,49)
- 測試動態擴展能力(n=50)
- 邊界條件測試(n=0,1)
- 溢出異常檢測(unsigned類型n=47)
- 性能對比非預計算版本