首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ 基礎演算法與指針精通:排序、查找、內存模型實戰

     編輯:關於C++

一、經典排序演算法:原理、實現與複雜度

1.1 冒泡排序

核心思想:相鄰元素兩兩比較,大者後移(沉底),小者前移(上浮),每輪將最大/最小元素移至端點。


void bubbleSort(int arr[], int n) {
    for (int i = 0; i < n-1; ++i) {
        bool swapped = false;
        for (int j = 0; j < n-1-i; ++j) {
            if (arr[j] > arr[j+1]) {
                std::swap(arr[j], arr[j+1]);
                swapped = true;
            }
        }
        if (!swapped) break; // 優化:已有序提前結束
    }
}
  • 時間複雜度:O(n²) 最好 O(n)(已有序)
  • 空間複雜度:O(1)
  • 穩定性:穩定
  • 適用:教學、極小數據集、近乎有序數據

1.2 選擇排序

核心思想:每輪從無序區選出最小元素,與無序區首位交換。


void selectionSort(int arr[], int n) {
    for (int i = 0; i < n-1; ++i) {
        int minIdx = i;
        for (int j = i+1; j < n; ++j)
            if (arr[j] < arr[minIdx]) minIdx = j;
        if (minIdx != i) std::swap(arr[i], arr[minIdx]);
    }
}
  • 時間複雜度:O(n²) 無最好情況優化
  • 空間複雜度:O(1)
  • 穩定性:不穩定(交換可能改變相等元素相對順序)
  • 優勢:寫入次數最少(最多 n-1 次 swap),適合寫入昂貴存儲(如 Flash)

1.3 現代 C++ 排序最佳實踐


#include <algorithm>
#include <vector>

std::vector vec = {5, 2, 8, 1, 9};
std::sort(vec.begin(), vec.end()); // Introsort:快速+堆+插入,O(n log n) 保證
std::stable_sort(vec.begin(), vec.end()); // 歸併排序,保持相等元素順序
// 自定義比較
std::sort(vec.begin(), vec.end(), [](int a, int b){ return a > b; }); // 降序

原則:生產代碼直接使用 std::sort/std::stable_sort,除非教學/極端受限環境/特殊演算法研究。

二、查找演算法:有序與無序的分野

2.1 順序查找

適用無序序列,逐個比對,時間 O(n)。


int linearSearch(const int arr[], int n, int key) {
    for (int i = 0; i < n; ++i)
        if (arr[i] == key) return i;
    return -1;
}

2.2 二分查找

前提:序列已排序(升序)。每次排除一半區間,時間 O(log n)。


// 迭代版:推薦,無棧溢出風險
int binarySearch(const int arr[], int n, int key) {
    int left = 0, right = n - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2; // 防溢出
        if (arr[mid] == key) return mid;
        else if (arr[mid] < key) left = mid + 1;
        else right = mid - 1;
    }
    return -1; // 未找到
}

// 標準庫:返回迭代器,配合 lower_bound/upper_bound 獲取範圍
auto it = std::binary_search(vec.begin(), vec.end(), key); // bool
auto range = std::equal_range(vec.begin(), vec.end(), key); // pair

三、指針:C++ 內存模型的核心抽象

3.1 指針的本質與算術

  • 指針變量存儲內存地址,類型決定解引用讀寫尺寸與算術步長(ptr+1 移動 sizeof(T) 字節)。
  • 僅在連續存儲(數組/對象數組)上進行指針算術有定義行為;單獨對象視為大小為 1 的數組。

3.2 危險指針模式與防範

模式成因後果防範
懸垂指針對象銷毀後指針仍持有地址(delete ptr; // ptr 成懸垂)UB:讀寫已釋放內存智能指針、delete 後置空、所有權語義明確
野指針未初始化指針UB:隨機地址讀寫定義即初始化(nullptr)、auto ptr = std::make_unique<T>()
越界訪問指針算術超出分配範圍UB:緩衝區溢出容器 at()/迭代器、span (C++20)、靜態分析

3.3 const 與指針的四種組合


int value = 42;
const int cvalue = 100;

int* p1 = &value;           // 可讀寫指向可讀寫對象
const int* p2 = &cvalue;      // 只讀指針 → 可讀寫/只讀對象(指向 const)
int* const p3 = &value;       // 常量指針 → 指針本身不可改,對象可讀寫
const int* const p4 = &cvalue; // 常量指針 → 指向 const 對象

// 規則:const 修飾右側實體
// const int* == int const* : 指向 const int
// int* const : const 指針 (指針本身不可改)

實務慣例:函數參數優先 const T*/const T& 表達只讀意圖;需修改用 T*/T&;避免 T* const 參數(無意義,形參本身即副本)。

3.4 指針作為函數參數:實現多返回值、避免全局變量


// 輸出參數模式
bool divide(int a, int b, int* quotient, int* remainder) {
    if (b == 0) return false;
    if (quotient) *quotient = a / b;
    if (remainder) *remainder = a % b;
    return true;
}

// 現代替代:結構體返回值(C++17 結構化綁定)
struct DivResult { int q, r; };
DivResult divide(int a, int b) { return {a/b, a%b}; }
auto [q, r] = divide(10, 3); // 清晰、無副作用、可優化

四、數組與指針的深度關聯

4.1 數組退化與尺寸傳遞


void process(int arr[]) { } // 等價 void process(int* arr)
void process(int arr[10]) { } // 等價 void process(int* arr),10 被忽略!

// 正確傳遞尺寸:模板推導數組引用
template <size_t N>
void process(int (&arr)[N]) { /* N 為編譯期常量 */ }

// 或使用 std::array / std::vector / std::span (C++20)
void process(std::span<int> arr); // 非擁有視圖,攜帶尺寸

4.2 多維數組與指針


int matrix[3][4]; // 連續內存:3 行 4 列
int (*p)[4] = matrix; // 指向「含 4 個 int 的數組」的指針
// p[i][j] 等價 *(*(p+i)+j)

五、字符串處理:C 風格 vs 現代 C++

5.1 C 風格字符串與指針操作

  • 以 \0 結尾的 char*/char[]。
  • 指針遍歷:for (const char* p = str; *p; ++p)。
  • 標準庫函數:strlen, strcpy, strcmp, strstr 等(需手動管理緩衝區安全)。

5.2 現代 C++ 字符串最佳實踐


#include <string>
#include <string_view> // C++17 輕量只讀視圖

std::string s = "Hello";
s += " World"; // 自動擴容
std::string_view sv = s; // 零拷貝視圖
void print(std::string_view sv); // 接受字面量/string/string_view,統一接口

原則:內部存儲/構建用 std::string;函數參數/只讀處理用 std::string_view;禁用裸 char* 管理字符串生命週期。

六、綜合實戰建議

  1. 演算法學習目的是理解原理,生產用標準庫(<algorithm>, <ranges> C++20)。
  2. 指針僅用於:非擁有觀察、C API 交互、性能極致場景手動內存管理。其餘全部用智能指針/容器/值語義/引用/視圖。
  3. 數組優先 std::array (固定) / std::vector (動態) / std::span (視圖),告別 C 風格數組退化陷阱。
  4. 字符串統一 std::string/std::string_view,編碼統一 UTF-8,跨平台無亂碼。
  5. 開啟編譯器警告(-Wall -Wextra -Wpedantic -Wshadow -Wconversion),靜態分析(Clang-Tidy, Cppcheck)常態化。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved