算法导论核心代码精粹

《算法导论》中的核心算法整理

以下是根据《算法导论》中的核心算法整理的C++实现示例,涵盖分治、动态规划、图算法等经典内容。示例代码均遵循C++标准,可直接用于学习或项目参考。

分治算法

1. 归并排序
void merge(vector<int>& arr, int l, int m, int r) {
    vector<int> temp(r - l + 1);
    int i = l, j = m + 1, k = 0;
    while (i <= m && j <= r) temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
    while (i <= m) temp[k++] = arr[i++];
    while (j <= r) temp[k++] = arr[j++];
    for (int p = 0; p < k; ++p) arr[l + p] = temp[p];
}
void mergeSort(vector<int>& arr, int l, int r) {
    if (l >= r) return;
    int m = l + (r - l) / 2;
    mergeSort(arr, l, m);
    mergeSort(arr, m + 1, r);
    merge(arr, l, m, r);
}

2. 快速排序
int partition(vector<int>& arr, int l, int r) {
    int pivot = arr[r], i = l;
    for (int j = l; j < r; ++j) {
        if (arr[j] <= pivot) swap(arr[i++], arr[j]);
    }
    swap(arr[i], arr[r]);
    return i;
}
void quickSort(vector<int>& arr, int l, int r) {
    if (l >= r) return;
    int p = partition(arr, l, r);
    quickSort(arr, l, p - 1);
    quickSort(arr, p + 1, r);
}

3. 最大子数组问题
struct Subarray { int l, r, sum; };
Subarray maxCrossingSubarray(vector<int>& arr, int l, int m, int r) {
    int left_sum = INT_MIN, sum = 0, max_l;
    for (int i = m; i >= l; --i) {
        sum += arr[i];
        if (sum > left_sum) { left_sum = sum; max_l = i; }
    }
    int right_sum = INT_MIN, max_r;
    sum = 0;
    for (int j = m + 1; j <= r; ++j) {
        sum += arr[j];
        if (sum > right_sum) { right_sum = sum; max_r = j; }
    }
    return {max_l, max_r, left_sum + right_sum};
}
Subarray maxSubarray(vector<int>& arr, int l, int r) {
    if (l == r) return {l, r, arr[l]};
    int m = l + (r - l) / 2;
    Subarray left = maxSubarray(arr, l, m);
    Subarray right = maxSubarray(arr, m + 1, r);
    Subarray cross = maxCrossingSubarray(arr, l, m, r);
    if (left.sum >= right.sum && left.sum >= cross.sum) return left;
    if (right.sum >= left.sum && right.sum >= cross.sum) return right;
    return cross;
}

动态规划

4. 钢条切割
int cutRod(vector<int>& price, int n) {
    vector<int> dp(n + 1, 0);
    for (int i = 1; i <= n; ++i) {
        int max_val = INT_MIN;
        for (int j = 0; j < i; ++j)
            max_val = max(max_val, price[j] + dp[i - j - 1]);
        dp[i] = max_val;
    }
    return dp[n];
}

5. 矩阵链乘法
int matrixChainOrder(vector<int>& p) {
    int n = p.size() - 1;
    vector<vector<int>> dp(n, vector<int>(n, 0));
    for (int l = 2; l <= n; ++l) {
        for (int i = 0; i <= n - l; ++i) {
            int j = i + l - 1;
            dp[i][j] = INT_MAX;
            for (int k = i; k < j; ++k) {
                int cost = dp[i][k] + dp[k + 1][j] + p[i] * p[k + 1] * p[j + 1];
                dp[i][j] = min(dp[i][j], cost);
            }
        }
    }
    return dp[0][n - 1];
}

6. 最长公共子序列
int lcs(string& X, string& Y) {
    int m = X.size(), n = Y.size();
    vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
    for (int i = 1; i <= m; ++i) {
        for (int j = 1; j <= n; ++j) {
            if (X[i - 1] == Y[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
            else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
        }
    }
    return dp[m][n];
}

贪心算法

7. 活动选择问题
int activitySelection(vector<pair<int, int>>& activities) {
    sort(activities.begin(), activities.end(), 
        [](auto& a, auto& b) { return a.second < b.second; });
    int count = 1, last_end = activities[0].second;
    for (int i = 1; i < activities.size(); ++i) {
        if (activities[i].first >= last_end) {
            ++count;
            last_end = activities[i].second;
        }
    }
    return count;
}
8. 霍夫曼编码
struct Node {
    char ch;
    int freq;
    Node *left, *right;
    Node(char c, int f) : ch(c), freq(f), left(nullptr), right(nullptr) {}
};
struct Compare {
    bool operator()(Node* a, Node* b) { return a->freq > b->freq; }
};
void encode(Node* root, string code, unordered_map<char, string>& huffmanCode) {
    if (!root) return;
    if (!root->left && !root->right) huffmanCode[root->ch] = code;
    encode(root->left, code + "0", huffmanCode);
    encode(root->right, code + "1", huffmanCode);
}
unordered_map<char, string> buildHuffmanTree(string text) {
    unordered_map<char, int> freq;
    for (char ch : text) freq[ch]++;
    priority_queue<Node*, vector<Node*>, Compare> pq;
    for (auto& pair : freq) pq.push(new Node(pair.first, pair.second));
    while (pq.size() > 1) {
        Node* left = pq.top(); pq.pop();
        Node* right = pq.top(); pq.pop();
        Node* newNode = new Node('\0', left->freq + right->freq);
        newNode->left = left;
        newNode->right = right;
        pq.push(newNode);
    }
    unordered_map<char, string> huffmanCode;
    encode(pq.top(), "", huffmanCode);
    return huffmanCode;
}

图算法

9. BFS遍历
void bfs(vector<vector<int>>& graph, int start) {
    queue<int> q;
    vector<bool> visited(graph.size(), false);
    q.push(start);
    visited[start] = true;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        cout << u << " ";
        for (int v : graph[u]) {
            if (!visited[v]) {
                visited[v] = true;
                q.push(v);
            }
        }
    }
}
10. DFS遍历
void dfsUtil(vector<vector<int>>& graph, int u, vector<bool>& visited) {
    visited[u] = true;
    cout << u << " ";
    for (int v : graph[u]) {
        if (!visited[v]) dfsUtil(graph, v, visited);
    }
}
void dfs(vector<vector<int>>& graph, int start) {
    vector<bool> visited(graph.size(), false);
    dfsUtil(graph, start, visited);
}

11. Dijkstra最短路径
void dijkstra(vector<vector<pair<int, int>>>& graph, int src) {
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
    vector<int> dist(graph.size(), INT_MAX);
    pq.push({0, src});
    dist[src] = 0;
    while (!pq.empty()) {
        int u = pq.top().second; pq.pop();
        for (auto& edge : graph[u]) {
            int v = edge.first, weight = edge.second;
            if (dist[v] > dist[u] + weight) {
                dist[v] = dist[u] + weight;
                pq.push({dist[v], v});
            }
        }
    }
}


其他重要算法

12. 红黑树插入
enum Color { RED, BLACK };
struct Node {
    int data;
    Color color;
    Node *left, *right, *parent;
    Node(int d) : data(d), color(RED), left(nullptr), 
                  right(nullptr), parent(nullptr) {}
};
void insertFixup(Node*& root, Node* pt) {
    while (pt != root && pt->parent->color == RED) {
        Node* uncle = (pt->parent == pt->parent->parent->left) ? 
                      pt->parent->parent->right : pt->parent->parent->left;
        if (uncle && uncle->color == RED) {
            pt->parent->color = BLACK;
            uncle->color = BLACK;
            pt->parent->parent->color = RED;
            pt = pt->parent->parent;
        } else {
            if (pt->parent == pt->parent->parent->left && 
                pt == pt->parent->right) {
                pt = pt->parent;
                leftRotate(root, pt);
            }
            pt->parent->color = BLACK;
            pt->parent->parent->color = RED;
            rightRotate(root, pt->parent->parent);
        }
    }
    root->color = BLACK;
}

(因篇幅限制,剩余示例可扩展实现:KMP字符串匹配、FFT快速傅里叶变换、NP完全问题验证算法等。)

KMP(Knuth-Morris-Pratt)算法

KMP算法简介

KMP(Knuth-Morris-Pratt)算法是一种高效的字符串匹配算法,通过预处理模式串构建部分匹配表(Partial Match Table),避免主串指针回溯,时间复杂度为O(n+m)。

C++实现代码模板

#include <vector>
#include <string>
using namespace std;

vector<int> computeLPS(const string& pattern) {
    vector<int> lps(pattern.size(), 0);
    int len = 0;
    for (int i = 1; i < pattern.size(); ) {
        if (pattern[i] == pattern[len]) {
            lps[i++] = ++len;
        } else {
            if (len != 0) len = lps[len-1];
            else lps[i++] = 0;
        }
    }
    return lps;
}

vector<int> KMPSearch(const string& text, const string& pattern) {
    vector<int> lps = computeLPS(pattern);
    vector<int> matches;
    int i = 0, j = 0;
    while (i < text.size()) {
        if (text[i] == pattern[j]) {
            i++; j++;
            if (j == pattern.size()) {
                matches.push_back(i - j);
                j = lps[j-1];
            }
        } else {
            if (j != 0) j = lps[j-1];
            else i++;
        }
    }
    return matches;
}

实例集合

每个示例包含测试字符串和模式串:

示例1
文本: "ABABDABACDABABCABAB"
模式: "ABABCABAB"
输出: [10]

示例2
文本: "AABAACAADAABAABA"
模式: "AABA"
输出: [0, 9, 12]

示例3
文本: "THIS IS A TEST TEXT"
模式: "TEST"
输出: [10]

示例4
文本: "AAAAABAAABA"
模式: "AAAA"
输出: [0, 1]

示例5
文本: "ABCDABCDABDE"
模式: "BCD"
输出: [1, 5]

示例6
文本: "ABCABCABCABC"
模式: "ABCABC"
输出: [0, 3, 6]

示例7
文本: "GEEKS FOR GEEKS"
模式: "GEEK"
输出: [0, 10]

示例8
文本: "ABABABABABABAB"
模式: "ABABA"
输出: [0, 2, 4, 6, 8]

示例9
文本: "1111111111"
模式: "111"
输出: [0,1,2,3,4,5,6,7]

示例10
文本: "ABC#DEF#GHI#"
模式: "#"
输出: [3,7,11]

边界测试用例

示例11
文本: ""
模式: "ABC"
输出: []

示例12
文本: "ABCD"
模式: ""
输出: []

示例13
文本: "A"
模式: "A"
输出: [0]

示例14
文本: "ABCDEF"
模式: "XYZ"
输出: []

示例15
文本: "重复重复重复"
模式: "重复"
输出: [0, 2, 4]

特殊字符测试

示例16
文本: "abc$123*^xx"
模式: "$123*"
输出: [3]

示例17
文本: "你好世界你好"
模式: "你好"
输出: [0, 4]

示例18
文本: "a\nb\tc\0d"
模式: "b\tc"
输出: [2]

性能测试用例

示例19
文本: string(1000000, 'A') + "B"
模式: string(1000, 'A') + "B"
输出: [999000]

示例20
文本: "ABCD"*10000
模式: "CDAB"
输出: [2,6,10,...,39998]

综合应用场景

示例21 - DNA序列匹配
文本: "AGCTAGCTAGCT"
模式: "AGCT"
输出: [0,4,8]

示例22 - 日志分析
文本: "ERROR:404;ERROR:500;WARN:301"
模式: "ERROR:"
输出: [0, 12]

示例23 - 二进制模式
文本: "\x01\x00\x01\x01\x00"
模式: "\x01\x00"
输出: [0, 3]

示例24 - URL路由匹配
文本: "/user/profile/account/settings"
模式: "/account/"
输出: [13]

示例25 - 版本号检测
文本: "v1.2.3 v1.2.4 v2.0.1"
模式: "v1.2."
输出: [0, 6]

复杂模式示例

示例26 - 重叠匹配
文本: "ababababa"
模式: "aba"
输出: [0,2,4,6]

示例27 - 前后缀测试
文本: "mississippi"
模式: "issi"
输出: [1,4]

示例28 - 全匹配
文本: "aaaaa"
模式: "aa"
输出: [0,1,2,3]

示例29 - Unicode字符
文本: "😊🐱🐶🍎😊"
模式: "😊"
输出: [0,4]

示例30 - 混合编码
文本: "中文ABC123!@#"
模式: "ABC"
输出: [2]

使用说明

  1. 将computeLPS和KMPSearch函数复制到C++项目中
  2. 使用g++编译时需要添加-std=c++11标准
  3. 结果返回所有匹配的起始位置索引(从0开始)
  4. 空模式或空文本时返回空向量

复杂度分析

  • 预处理阶段:O(m) 其中m为模式串长度
  • 匹配阶段:O(n) 其中n为文本长度
  • 总时间复杂度:O(n+m)
  • 空间复杂度:O(m) 用于存储LPS数组

场景下的C++插入排序

以下是不同场景下的C++插入排序实例,涵盖基础实现、变体及优化版本。每个示例独立且可直接运行,通过注释说明核心逻辑。

基础插入排序(升序)

void insertionSort(int arr[], int n) {
    for (int i = 1; i < n; 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;
    }
}

降序排列

void insertionSortDesc(int arr[], int n) {
    for (int i = 1; i < n; 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;
    }
}

字符串数组排序

void insertionSortStrings(string arr[], int n) {
    for (int i = 1; i < n; i++) {
        string key = arr[i];
        int j = i - 1;
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = key;
    }
}

结构体排序(按年龄)

struct Person {
    string name;
    int age;
};

void sortByAge(Person people[], int n) {
    for (int i = 1; i < n; i++) {
        Person key = people[i];
        int j = i - 1;
        while (j >= 0 && people[j].age > key.age) {
            people[j + 1] = people[j];
            j--;
        }
        people[j + 1] = key;
    }
}

双向插入排序

void bidirectionalInsertionSort(int arr[], int n) {
    int left = 0, right = n - 1;
    while (left < right) {
        for (int i = left + 1; i <= right; i++) {
            int key = arr[i];
            int j = i - 1;
            while (j >= left && arr[j] > key) {
                arr[j + 1] = arr[j];
                j--;
            }
            arr[j + 1] = key;
        }
        right--;
    }
}

递归实现

void recursiveInsertionSort(int arr[], int n) {
    if (n <= 1) return;
    recursiveInsertionSort(arr, n - 1);
    int key = arr[n - 1];
    int j = n - 2;
    while (j >= 0 && arr[j] > key) {
        arr[j + 1] = arr[j];
        j--;
    }
    arr[j + 1] = key;
}

使用STL的插入排序

void stlInsertionSort(vector<int>& v) {
    for (auto it = v.begin(); it != v.end(); ++it) {
        auto const insertion_point = upper_bound(v.begin(), it, *it);
        rotate(insertion_point, it, it + 1);
    }
}

链表排序

struct Node {
    int data;
    Node* next;
};

void insertionSortLinkedList(Node** head) {
    Node* sorted = nullptr;
    Node* current = *head;
    while (current != nullptr) {
        Node* next = current->next;
        if (sorted == nullptr || sorted->data >= current->data) {
            current->next = sorted;
            sorted = current;
        } else {
            Node* temp = sorted;
            while (temp->next != nullptr && temp->next->data < current->data) {
                temp = temp->next;
            }
            current->next = temp->next;
            temp->next = current;
        }
        current = next;
    }
    *head = sorted;
}

浮点数排序

void insertionSortFloat(float arr[], int n) {
    for (int i = 1; i < n; i++) {
        float key = arr[i];
        int j = i - 1;
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = key;
    }
}

带比较函数的泛型版本

template <typename T>
void insertionSortGeneric(T arr[], int n, bool (*compare)(T, T)) {
    for (int i = 1; i < n; i++) {
        T key = arr[i];
        int j = i - 1;
        while (j >= 0 && compare(arr[j], key)) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = key;
    }
}

优化版(二分查找插入位置)

void binaryInsertionSort(int arr[], int n) {
    for (int i = 1; i < n; i++) {
        int key = arr[i];
        int left = 0, right = i;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (arr[mid] <= key) left = mid + 1;
            else right = mid;
        }
        for (int j = i; j > left; j--) {
            arr[j] = arr[j - 1];
        }
        arr[left] = key;
    }
}

完整代码示例可通过C++编译器直接测试,根据实际需求调整数据类型和比较逻辑。

    C++模拟动态表

    以下是C++模拟动态表(如std::vector)插入操作的示例,涵盖不同场景和技巧。所有示例均基于动态数组的实现逻辑,可直接运行测试。

    示例1:基础动态表尾部插入

    #include <iostream>
    using namespace std;
    
    class DynamicArray {
        int* arr;
        int capacity;
        int size;
    public:
        DynamicArray() : capacity(1), size(0) {
            arr = new int[capacity];
        }
        void push_back(int val) {
            if (size == capacity) {
                capacity *= 2;
                int* temp = new int[capacity];
                for (int i = 0; i < size; i++) temp[i] = arr[i];
                delete[] arr;
                arr = temp;
            }
            arr[size++] = val;
        }
        void print() {
            for (int i = 0; i < size; i++) cout << arr[i] << " ";
        }
    };
    
    int main() {
        DynamicArray da;
        da.push_back(10); // 插入10
        da.print(); // 输出: 10
    }
    

    示例2:指定位置插入元素

    void insert(int index, int val) {
        if (index < 0 || index > size) throw "Index out of bounds";
        if (size == capacity) {
            capacity *= 2;
            int* temp = new int[capacity];
            for (int i = 0; i < index; i++) temp[i] = arr[i];
            temp[index] = val;
            for (int i = index; i < size; i++) temp[i+1] = arr[i];
            delete[] arr;
            arr = temp;
        } else {
            for (int i = size; i > index; i--) arr[i] = arr[i-1];
            arr[index] = val;
        }
        size++;
    }
    

    示例3:插入时缩小容量检查

    void push_back(int val) {
        if (size == capacity) {
            capacity = (capacity == 0) ? 1 : capacity * 2;
            int* temp = new int[capacity];
            for (int i = 0; i < size; i++) temp[i] = arr[i];
            delete[] arr;
            arr = temp;
        }
        arr[size++] = val;
    }
    

    示例4:批量插入元素

    void insertRange(int index, int* vals, int count) {
        while (size + count > capacity) capacity *= 2;
        int* temp = new int[capacity];
        for (int i = 0; i < index; i++) temp[i] = arr[i];
        for (int i = 0; i < count; i++) temp[index + i] = vals[i];
        for (int i = index; i < size; i++) temp[i + count] = arr[i];
        delete[] arr;
        arr = temp;
        size += count;
    }
    

    示例5:插入排序式插入

    void sortedInsert(int val) {
        push_back(val); // 先插入尾部
        for (int i = size - 1; i > 0 && arr[i] < arr[i-1]; i--) {
            swap(arr[i], arr[i-1]);
        }
    }
    

    可根据实际需求组合这些示例中的技术点,构建更复杂的动态表结构。

    C++中实现链表

    在C++中实现链表反转是一个常见的数据结构和算法问题。以下是多种实现方法和示例,涵盖递归、迭代以及不同场景的优化方案。

    基础迭代法

    struct ListNode {
        int val;
        ListNode* next;
        ListNode(int x) : val(x), next(nullptr) {}
    };
    
    ListNode* reverseList(ListNode* head) {
        ListNode* prev = nullptr;
        ListNode* curr = head;
        while (curr) {
            ListNode* next = curr->next;
            curr->next = prev;
            prev = curr;
            curr = next;
        }
        return prev;
    }
    

    递归实现

    ListNode* reverseListRecursive(ListNode* head) {
        if (!head || !head->next) return head;
        ListNode* newHead = reverseListRecursive(head->next);
        head->next->next = head;
        head->next = nullptr;
        return newHead;
    }
    

    头插法反转

    ListNode* reverseListHeadInsert(ListNode* head) {
        ListNode dummy(0);
        while (head) {
            ListNode* next = head->next;
            head->next = dummy.next;
            dummy.next = head;
            head = next;
        }
        return dummy.next;
    }
    

    反转部分链表(指定区间)

    ListNode* reverseBetween(ListNode* head, int m, int n) {
        ListNode dummy(0);
        dummy.next = head;
        ListNode* pre = &dummy;
        for (int i = 0; i < m - 1; ++i) pre = pre->next;
        ListNode* curr = pre->next;
        for (int i = 0; i < n - m; ++i) {
            ListNode* next = curr->next;
            curr->next = next->next;
            next->next = pre->next;
            pre->next = next;
        }
        return dummy.next;
    }
    

    每K个节点一组反转

    ListNode* reverseKGroup(ListNode* head, int k) {
        ListNode* curr = head;
        int count = 0;
        while (curr && count < k) {
            curr = curr->next;
            count++;
        }
        if (count == k) {
            curr = reverseKGroup(curr, k);
            while (count-- > 0) {
                ListNode* tmp = head->next;
                head->next = curr;
                curr = head;
                head = tmp;
            }
            head = curr;
        }
        return head;
    }
    

    双指针优化

    ListNode* reverseListTwoPointer(ListNode* head) {
        ListNode* slow = nullptr;
        ListNode* fast = head;
        while (fast) {
            ListNode* next = fast->next;
            fast->next = slow;
            slow = fast;
            fast = next;
        }
        return slow;
    }
    

    反转链表并返回新头尾

    pair<ListNode*, ListNode*> reverseListReturnHeadTail(ListNode* head) {
        if (!head || !head->next) return {head, head};
        auto [newHead, newTail] = reverseListReturnHeadTail(head->next);
        newTail->next = head;
        head->next = nullptr;
        return {newHead, head};
    }
    

    使用栈反转

    ListNode* reverseListUsingStack(ListNode* head) {
        stack<ListNode*> s;
        while (head) {
            s.push(head);
            head = head->next;
        }
        ListNode dummy(0);
        ListNode* curr = &dummy;
        while (!s.empty()) {
            curr->next = s.top();
            s.pop();
            curr = curr->next;
        }
        curr->next = nullptr;
        return dummy.next;
    }
    

    反转交替K个节点

    ListNode* reverseAlternateK(ListNode* head, int k) {
        ListNode* curr = head;
        ListNode* prev = nullptr;
        ListNode* next = nullptr;
        int count = 0;
        while (curr && count < k) {
            next = curr->next;
            curr->next = prev;
            prev = curr;
            curr = next;
            count++;
        }
        if (head) head->next = curr;
        count = 0;
        while (curr && count < k - 1) {
            curr = curr->next;
            count++;
        }
        if (curr) curr->next = reverseAlternateK(curr->next, k);
        return prev;
    }
    

    上示例盖了链表反转的多种场景,包括基础反转、部分反转、分组反转等。实际应用中可根据需求选择合适方法,注意处理边界条件(如空链表或单节点链表)。

    C++的二叉搜索树

    以下是一些基于C++的二叉搜索树(BST)实例,涵盖基础操作、常见算法和实际应用场景。每个例子均附简要说明,可直接运行或扩展。


    基础操作

    插入节点

    struct Node {
        int data;
        Node* left;
        Node* right;
        Node(int val) : data(val), left(nullptr), right(nullptr) {}
    };
    
    void insert(Node* &root, int val) {
        if (!root) root = new Node(val);
        else if (val < root->data) insert(root->left, val);
        else insert(root->right, val);
    }
    

    查找节点

    bool search(Node* root, int val) {
        if (!root) return false;
        if (root->data == val) return true;
        return val < root->data ? search(root->left, val) : search(root->right, val);
    }
    

    删除节点

    Node* deleteNode(Node* root, int val) {
        if (!root) return root;
        if (val < root->data) root->left = deleteNode(root->left, val);
        else if (val > root->data) root->right = deleteNode(root->right, val);
        else {
            if (!root->left) return root->right;
            if (!root->right) return root->left;
            Node* temp = root->right;
            while (temp->left) temp = temp->left;
            root->data = temp->data;
            root->right = deleteNode(root->right, temp->data);
        }
        return root;
    }
    


    遍历与输出

    中序遍历(升序输出)

    void inorder(Node* root) {
        if (!root) return;
        inorder(root->left);
        std::cout << root->data << " ";
        inorder(root->right);
    }
    

    层序遍历(广度优先)

    #include <queue>
    void levelOrder(Node* root) {
        if (!root) return;
        std::queue<Node*> q;
        q.push(root);
        while (!q.empty()) {
            Node* curr = q.front();
            q.pop();
            std::cout << curr->data << " ";
            if (curr->left) q.push(curr->left);
            if (curr->right) q.push(curr->right);
        }
    }
    


    实用功能

    计算树的高度

    int height(Node* root) {
        if (!root) return 0;
        return 1 + std::max(height(root->left), height(root->right));
    }
    

    检查是否为BST

    bool isBST(Node* root, Node* min = nullptr, Node* max = nullptr) {
        if (!root) return true;
        if (min && root->data <= min->data) return false;
        if (max && root->data >= max->data) return false;
        return isBST(root->left, min, root) && isBST(root->right, root, max);
    }
    

    寻找第k小的元素

    int kthSmallest(Node* root, int& k) {
        if (!root) return -1;
        int left = kthSmallest(root->left, k);
        if (left != -1) return left;
        if (--k == 0) return root->data;
        return kthSmallest(root->right, k);
    }
    


    高级应用

    BST转双向链表

    void treeToDoublyList(Node* root, Node* &prev, Node* &head) {
        if (!root) return;
        treeToDoublyList(root->left, prev, head);
        if (!prev) head = root;
        else {
            prev->right = root;
            root->left = prev;
        }
        prev = root;
        treeToDoublyList(root->right, prev, head);
    }
    

    从有序数组构造BST

    Node* sortedArrayToBST(std::vector<int>& nums, int start, int end) {
        if (start > end) return nullptr;
        int mid = start + (end - start) / 2;
        Node* root = new Node(nums[mid]);
        root->left = sortedArrayToBST(nums, start, mid - 1);
        root->right = sortedArrayToBST(nums, mid + 1, end);
        return root;
    }
    

    范围查询

    void rangeQuery(Node* root, int L, int R, std::vector<int>& res) {
        if (!root) return;
        if (root->data > L) rangeQuery(root->left, L, R, res);
        if (root->data >= L && root->data <= R) res.push_back(root->data);
        if (root->data < R) rangeQuery(root->right, L, R, res);
    }
    

    以上代码片段可直接组合使用或独立扩展。

    基于C++的BFS

    以下是一些基于C++的BFS(广度优先搜索)遍历实例,涵盖不同应用场景和数据结构。每个例子包含关键代码片段和简要说明,可直接用于实际项目或学习。

    基础BFS遍历(无向图)

    #include <queue>
    #include <vector>
    using namespace std;
    
    void bfs(vector<vector<int>>& graph, int start) {
        queue<int> q;
        vector<bool> visited(graph.size(), false);
        q.push(start);
        visited[start] = true;
    
        while (!q.empty()) {
            int node = q.front();
            q.pop();
            cout << node << " ";
            for (int neighbor : graph[node]) {
                if (!visited[neighbor]) {
                    visited[neighbor] = true;
                    q.push(neighbor);
                }
            }
        }
    }
    

    迷宫最短路径(网格BFS)

    struct Point { int x, y; };
    
    int dirs[4][2] = {
      
      {-1,0}, {1,0}, {0,-1}, {0,1}};
    
    int bfsMaze(vector<vector<int>>& maze, Point start, Point end) {
        queue<Point> q;
        vector<vector<int>> dist(maze.size(), vector<int>(maze[0].size(), -1));
        q.push(start);
        dist[start.x][start.y] = 0;
    
        while (!q.empty()) {
            Point p = q.front();
            q.pop();
            if (p.x == end.x && p.y == end.y) return dist[p.x][p.y];
    
            for (auto& dir : dirs) {
                int nx = p.x + dir[0], ny = p.y + dir[1];
                if (nx >= 0 && nx < maze.size() && ny >= 0 && ny < maze[0].size() 
                    && maze[nx][ny] == 0 && dist[nx][ny] == -1) {
                    dist[nx][ny] = dist[p.x][p.y] + 1;
                    q.push({nx, ny});
                }
            }
        }
        return -1;
    }
    

    层级遍历二叉树

    struct TreeNode {
        int val;
        TreeNode *left, *right;
    };
    
    void bfsTree(TreeNode* root) {
        if (!root) return;
        queue<TreeNode*> q;
        q.push(root);
        while (!q.empty()) {
            int levelSize = q.size();
            for (int i = 0; i < levelSize; ++i) {
                TreeNode* node = q.front();
                q.pop();
                cout << node->val << " ";
                if (node->left) q.push(node->left);
                if (node->right) q.push(node->right);
            }
            cout << endl; // 换行表示不同层级
        }
    }
    

    拓扑排序(有向无环图)

    vector<int> topologicalSort(vector<vector<int>>& graph, vector<int>& inDegree) {
        queue<int> q;
        vector<int> result;
        for (int i = 0; i < inDegree.size(); ++i) {
            if (inDegree[i] == 0) q.push(i);
        }
    
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            result.push_back(u);
            for (int v : graph[u]) {
                if (--inDegree[v] == 0) {
                    q.push(v);
                }
            }
        }
        return result.size() == graph.size() ? result : vector<int>();
    }
    

    多源BFS(多个起点)

    vector<vector<int>> multiSourceBfs(vector<vector<int>>& grid, vector<Point>& sources) {
        queue<Point> q;
        vector<vector<int>> dist(grid.size(), vector<int>(grid[0].size(), INT_MAX));
        for (auto& p : sources) {
            dist[p.x][p.y] = 0;
            q.push(p);
        }
    
        while (!q.empty()) {
            Point p = q.front();
            q.pop();
            for (auto& dir : dirs) {
                int nx = p.x + dir[0], ny = p.y + dir[1];
                if (nx >= 0 && nx < grid.size() && ny >= 0 && ny < grid[0].size() 
                    && grid[nx][ny] == 1 && dist[nx][ny] > dist[p.x][p.y] + 1) {
                    dist[nx][ny] = dist[p.x][p.y] + 1;
                    q.push({nx, ny});
                }
            }
        }
        return dist;
    }
    

    双向BFS(单词接龙问题)

    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
        unordered_set<string> dict(wordList.begin(), wordList.end());
        if (!dict.count(endWord)) return 0;
    
        unordered_set<string> beginSet{beginWord}, endSet{endWord};
        int steps = 1;
    
        while (!beginSet.empty() && !endSet.empty()) {
            if (beginSet.size() > endSet.size()) swap(beginSet, endSet);
            unordered_set<string> tempSet;
            for (string word : beginSet) {
                for (int i = 0; i < word.size(); ++i) {
                    char original = word[i];
                    for (char c = 'a'; c <= 'z'; ++c) {
                        word[i] = c;
                        if (endSet.count(word)) return steps + 1;
                        if (dict.count(word)) {
                            tempSet.insert(word);
                            dict.erase(word);
                        }
                    }
                    word[i] = original;
                }
            }
            beginSet = tempSet;
            steps++;
        }
        return 0;
    }
    

    0-1权图BFS(双端队列)

    int bfs01(vector<vector<pair<int, int>>>& graph, int start, int end) {
        deque<int> dq;
        vector<int> dist(graph.size(), INT_MAX);
        dist[start] = 0;
        dq.push_front(start);
    
        while (!dq.empty()) {
            int u = dq.front();
            dq.pop_front();
            for (auto& [v, w] : graph[u]) {
                if (dist[v] > dist[u] + w) {
                    dist[v] = dist[u] + w;
                    w == 0 ? dq.push_front(v) : dq.push_back(v);
                }
            }
        }
        return dist[end];
    }
    

    状态压缩BFS(八数码问题)

    int slidingPuzzle(vector<vector<int>>& board) {
        string target = "123450";
        string start;
        for (auto& row : board) {
            for (int num : row) {
                start += to_string(num);
            }
        }
    
        vector<vector<int>> dirs = {
      
      {1,3}, {0,2,4}, {1,5}, {0,4}, {1,3,5}, {2,4}};
        queue<string> q{
      
      {start}};
        unordered_set<string> visited{start};
        int steps = 0;
    
        while (!q.empty()) {
            int size = q.size();
            while (size--) {
                string curr = q.front();
                q.pop();
                if (curr == target) return steps;
                int zero = curr.find('0');
                for (int next : dirs[zero]) {
                    string neighbor = curr;
                    swap(neighbor[zero], neighbor[next]);
                    if (!visited.count(neighbor)) {
                        visited.insert(neighbor);
                        q.push(neighbor);
                    }
                }
            }
            steps++;
        }
        return -1;
    }
    

    1. 网页爬虫:基于URL的层级抓取
    2. 连通区域检测:图像处理中的像素连通性分析
    3. 游戏AI:寻路算法(A*的基础)
    4. 电路布线:VLSI设计中的网格布线

    每个场景均可通过调整上述基础模板实现。BFS的核心在于队列管理和状态记录,实际应用中需根据问题特点设计节点表达方式和转移规则。

    基于C++的社交网络好友推荐

    以下是一些基于C++的社交网络好友推荐实现思路和示例代码片段,涵盖不同算法和场景的应用:


    基于共同好友的推荐

    void recommendByCommonFriends(const User& targetUser, const SocialGraph& graph) {
        unordered_map<UserId, int> commonCounts;
        for (const auto& friendId : targetUser.friends) {
            for (const auto& potentialFriend : graph.getUser(friendId).friends) {
                if (!targetUser.isFriend(potentialFriend)) {
                    commonCounts[potentialFriend]++;
                }
            }
        }
        // 按共同好友数排序输出推荐
    }
    

    Jaccard相似度推荐

    vector<UserId> recommendByJaccard(const User& u1, const User& u2) {
        unordered_set<UserId> unionSet(u1.friends.begin(), u1.friends.end());
        unionSet.insert(u2.friends.begin(), u2.friends.end());
        
        unordered_set<UserId> intersection;
        for (auto& f : u1.friends) {
            if (u2.friends.count(f)) intersection.insert(f);
        }
        
        double similarity = intersection.size() / (double)unionSet.size();
        return similarity > 0.2 ? getTopRecommendations() : vector<UserId>();
    }
    

    基于图的BFS推荐

    void bfsRecommendation(UserId start, const SocialGraph& graph, int depth) {
        queue<pair<UserId, int>> q;
        unordered_set<UserId> visited;
        q.push({start, 0});
        
        while (!q.empty()) {
            auto [current, dist] = q.front();
            q.pop();
            
            if (dist == depth) {
                recommendUser(current);
                continue;
            }
            
            for (UserId neighbor : graph.getFriends(current)) {
                if (!visited.count(neighbor)) {
                    visited.insert(neighbor);
                    q.push({neighbor, dist+1});
                }
            }
        }
    }
    

    矩阵分解推荐

    void matrixFactorization(const MatrixXd& R, int k, double alpha, double lambda) {
        MatrixXd P = MatrixXd::Random(R.rows(), k);
        MatrixXd Q = MatrixXd::Random(k, R.cols());
        
        for (int iter = 0; iter < 50; ++iter) {
            for (int i = 0; i < R.rows(); ++i) {
                for (int j = 0; j < R.cols(); ++j) {
                    if (R(i,j) > 0) {
                        double error = R(i,j) - P.row(i)*Q.col(j);
                        P.row(i) += alpha * (2 * error * Q.col(j).transpose() - lambda * P.row(i));
                        Q.col(j) += alpha * (2 * error * P.row(i).transpose() - lambda * Q.col(j));
                    }
                }
            }
        }
    }
    

    基于兴趣标签的推荐

    vector<UserId> recommendByTags(const User& target, const vector<User>& users) {
        vector<pair<UserId, double>> scores;
        for (const auto& user : users) {
            if (user.id == target.id) continue;
            
            double score = cosineSimilarity(target.tags, user.tags);
            scores.emplace_back(user.id, score);
        }
        
        sort(scores.begin(), scores.end(), [](auto& a, auto& b) {
            return a.second > b.second;
        });
        
        vector<UserId> recommendations;
        for (int i = 0; i < min(5, (int)scores.size()); ++i) {
            recommendations.push_back(scores[i].first);
        }
        return recommendations;
    }
    


    其他实现方向(需完整代码可扩展)

    1. 基于PageRank的推荐
    void calculatePageRank(const SocialGraph& graph) {
        // 实现PageRank算法计算用户影响力
    }
    

    2. 社团发现推荐
    vector<Community> detectCommunities(Graph& g) {
        // 使用Louvain等方法发现社团
    }
    

    3. 基于深度学习的嵌入
    class GraphSAGE : public torch::nn::Module {
        // 实现图神经网络嵌入
    };
    

    4. 实时推荐系统
    class RealTimeRecommender {
        // 使用消息队列处理实时交互
    };
    

    5. 地理位置推荐
    vector<UserId> recommendByLocation(UserId userId, double radiusKm) {
        // 基于地理位置的推荐逻辑
    }
    

    6. 混合推荐系统
    void hybridRecommendation(const User& user) {
        // 组合多种推荐策略
    }
    

    7. 基于活动的推荐
    void eventBasedRecommendation(UserId userId) {
        // 根据用户参与的活动推荐
    }
    
    8. 社交影响力推荐
    void influenceBasedRecommendation() {
        // 基于用户影响力评分
    }
    
    9. 时间衰减推荐
    double timeDecayScore(Interaction interaction) {
        // 实现时间衰减因子
    }
    
    10. 社交图谱嵌入
    void graphEmbedding() {
        // 使用node2vec等算法
    }
    

    完整系统架构示例

    class FriendRecommender {
    private:
        SocialGraph graph;
        RecommenderAlgorithm* algorithm;
        
    public:
        void setAlgorithm(RecommenderAlgorithm* algo) {
            algorithm = algo;
        }
        
        vector<Recommendation> generateRecommendations(UserId userId) {
            return algorithm->recommend(userId, graph);
        }
    };
    
    // 策略模式实现不同算法
    class RecommenderAlgorithm {
    public:
        virtual vector<Recommendation> recommend(UserId, SocialGraph&) = 0;
    };
    
    // 具体算法实现
    class CommonFriendsAlgorithm : public RecommenderAlgorithm {
        // 实现具体逻辑
    };
    

    性能优化技巧

    // 使用位集加速共同好友计算
    bitset<MAX_USERS> getFriendBitset(const User& user) {
        bitset<MAX_USERS> bs;
        for (auto fid : user.friends) bs.set(fid);
        return bs;
    }
    
    // 并行计算推荐
    void parallelRecommend() {
        #pragma omp parallel for
        for (int i = 0; i < users.size(); ++i) {
            // 并行处理每个用户的推荐
        }
    }
    

    以上示例涵盖了从基础到进阶的各种好友推荐实现方法。完整实现需要结合具体社交网络的数据结构和业务需求进行扩展。每个示例都可以作为独立模块或组合成混合推荐系统。

    DFS(深度优先搜索)

    DFS拓扑排序简介

    DFS(深度优先搜索)拓扑排序是一种用于有向无环图(DAG)的排序算法,通过递归或栈实现节点的线性排序,确保每个节点在其前驱节点之后出现。

    基本实现代码

    以下是C++中DFS拓扑排序的基础代码框架:

    #include <iostream>
    #include <vector>
    #include <stack>
    using namespace std;
    
    void topologicalSortUtil(int v, vector<bool>& visited, stack<int>& Stack, const vector<vector<int>>& adj) {
        visited[v] = true;
        for (int i : adj[v]) {
            if (!visited[i]) {
                topologicalSortUtil(i, visited, Stack, adj);
            }
        }
        Stack.push(v);
    }
    
    void topologicalSort(int V, const vector<vector<int>>& adj) {
        stack<int> Stack;
        vector<bool> visited(V, false);
    
        for (int i = 0; i < V; ++i) {
            if (!visited[i]) {
                topologicalSortUtil(i, visited, Stack, adj);
            }
        }
    
        while (!Stack.empty()) {
            cout << Stack.top() << " ";
            Stack.pop();
        }
    }
    

    应用实例分类

    以下是DFS拓扑排序的应用实例,涵盖不同场景:

    课程安排问题

    给定课程间的先修关系,输出可行的学习顺序。

    vector<vector<int>> adj = {
      
      {1, 2}, {3}, {3}, {}};
    topologicalSort(4, adj); // 输出: 0 2 1 3
    
    任务调度

    根据任务依赖关系生成执行顺序。

    vecto
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包

    打赏作者

    KENYCHEN奉孝

    您的鼓励是我的进步源泉

    ¥1 ¥2 ¥4 ¥6 ¥10 ¥20
    扫码支付:¥1
    获取中
    扫码支付

    您的余额不足,请更换扫码支付或充值

    打赏作者

    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值