乐于分享
好东西不私藏

2026-CSP数据结构模板(查找/排列/数/堆)

2026-CSP数据结构模板(查找/排列/数/堆)

一、查找算法(Binary Search)

头文件#include(使用内置函数时)
二分查找是有序数组中最高效的查找算法,时间复杂度为 O(log n)。在CSP考试中,它不仅是独立的算法,也是许多难题(如最小值最大化、最大值最小化)的解题核心。

1. STL 内置二分查找函数(适用于有序容器)

函数
作用
返回值
binary_search(begin, end, val)
判断值是否存在
bool
lower_bound(begin, end, val)
查找第一个 >= val 的位置
迭代器
upper_bound(begin, end, val)
查找第一个 > val 的位置
迭代器
equal_range(begin, end, val)
同时获取 lower_bound 和 upper_bound
pair<迭代器, 迭代器>
使用示例:
#include<iostream>#include<algorithm>#include<vector>using namespace std;intmain(){    vector<int> arr = {1233357};    // 1. 判断元素是否存在    bool exists = binary_search(arr.begin(), arr.end(), 3);  // true    // 2. 查找第一个 >= 3 的位置(指向第一个3)    auto it1 = lower_bound(arr.begin(), arr.end(), 3);    cout << "第一个>=3的索引: " << it1 - arr.begin() << endl;  // 输出 2    // 3. 查找第一个 > 3 的位置(指向5)    auto it2 = upper_bound(arr.begin(), arr.end(), 3);    cout << "第一个>3的索引: " << it2 - arr.begin() << endl;   // 输出 5    // 4. 统计值为3的元素个数    int count = upper_bound(arr.begin(), arr.end(), 3) - lower_bound(arr.begin(), arr.end(), 3);    cout << "3的个数: " << count << endl;  // 输出 3    // 5. equal_range 一次性获取区间  返回值为pair<iterator,iterator>    auto range = equal_range(arr.begin(), arr.end(), 3);    cout << "3的范围: [" << (range.first - arr.begin())          << ", " << (range.second - arr.begin()) << ")" << endl;  // 输出 [2, 5)    return 0;}

手写二分查找模板(最常用,灵活度高)

场景一:在有序数组中查找目标值(标准模板)

intbinarySearch(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;        else if (arr[mid] < target) left = mid + 1;        else right = mid - 1;    }    return -1;  // 未找到}

场景二:查找第一个满足条件的元素(左边界,即 lower_bound 手写版)

intlowerBound(vector<int>& arr, int target){    int left = 0, right = arr.size();  // 注意右边界是开区间    while (left < right) {        int mid = left + (right - left) / 2;        if (arr[mid] >= target) right = mid;   // 满足条件,向左收缩        else left = mid + 1;                    // 不满足,向右收缩    }    return left;  // 返回第一个 >= target 的索引}

场景三:查找最后一个满足条件的元素(右边界,即 upper_bound - 1 手写版)

intupperBound(vector<int>& arr, int target){    int left = 0, right = arr.size();    while (left < right) {        int mid = left + (right - left) / 2;        if (arr[mid] > target) right = mid;    // 满足 > 条件,向左收缩        else left = mid + 1;                    // 不满足(<= target),向右收缩    }    return left - 1;  // 返回最后一个 <= target 的索引}

二分查找在答案值上的应用(二分答案)

当问题要求 "最大值最小" 或 "最小值最大" 时,通常直接对答案进行二分。
示例模板(判断函数 check(mid)):
boolcheck(int mid) {    // 根据 mid 判断是否满足题目条件    // 返回 true 表示 mid 可行,false 表示不可行}intsolve() {    int left = 0, right = 1e9;  // 根据题目设定上下界    int ans = -1;    while (left <= right) {        int mid = left + (right - left) / 2;        if (check(mid)) {            ans = mid;         // 记录可行解            left = mid + 1;    // 尝试更大的值(求最大可行解)            // 若求最小可行解,则 right = mid - 1;        } else {            right = mid - 1;   // mid 不可行,收缩右边界        }    }    return ans;}

注意事项

必须有序:二分查找仅适用于有序序列(升序或降序)。
边界处理:注意left < right与left <= right的区别,以及mid的取整方向。
死循环预防:当使用left = mid时,需将mid改为(left + right + 1) / 2(向上取整)以避免死循环。
STL函数:lower_bound/upper_bound适用于所有有序容器(vector、deque、map 等)。
应用场景:有序数组查找、二分答案(最小值最大化/最大值最小化)、寻找峰值、旋转数组查找



二、排列函数(全排列)

头文件:#include
函数
作用
返回值 true 的条件
返回值 false 时重置为
next_permutation
变为更大的字典序排列
存在更大排列
最小排列(升序)
prev_permutation
变为更小的字典序排列
存在更小排列
最大排列(降序)

1. 排列函数基本用法示例

vector<int> nums = {123};// next_permutation 示例next_permutation(nums.begin(), nums.end()); // nums 变为 {1, 3, 2}// 遍历全部排列(从升序开始)sort(nums.begin(), nums.end());do {    // 处理当前排列while (next_permutation(nums.begin(), nums.end()));// 输出顺序:123, 132, 213, 231, 312, 321// prev_permutation 示例vector<int> nums2 = {132};prev_permutation(nums2.begin(), nums2.end()); // nums2 变为 {1, 2, 3}// 遍历全部排列(从降序开始)sort(nums2.begin(), nums2.end(), greater<int>());do {    // 处理当前排列while (prev_permutation(nums2.begin(), nums2.end()));// 输出顺序:321, 312, 231, 213, 132, 123

2. 排列函数进阶用法

处理重复元素:自动去重,如{1,1,2}只输出 3 种排列:112 121 211
自定义比较函数:用于结构体排序
struct Person { string name; int age; };boolcmp(const Person& a, const Person& b) { return a.age < b.age; }sort(people.begin(), people.end(), cmp);do {     /* 处理排列 */ while (next_permutation(people.begin(), people.end(), cmp));

三、树形结构

1. 二叉树节点定义

struct TreeNode {    int val;    TreeNode* left;    TreeNode* right;    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}};

2. 二叉树的递归遍历

// 先序遍历(根→左→右)void preorder(TreeNode* root) {    if (!root) return;    cout << root->val;    preorder(root->left);    preorder(root->right);}// 中序遍历(左→根→右)void inorder(TreeNode* root) {    if (!root) return;    inorder(root->left);    cout << root->val;    inorder(root->right);}// 后序遍历(左→右→根)void postorder(TreeNode* root) {    if (!root) return;    postorder(root->left);    postorder(root->right);    cout << root->val;}

四、优先队列(堆 priority_queue)

头文件:#include
// priority_queue 模版类,用于实现优先队列 默认为大根堆// 最大堆(默认)priority_queue<int> max_heap;// 最小堆// vector<int> 为默认容器 greater<int> 为默认比较函数priority_queue<int, vector<int>, greater<int>> min_heap;// 自定义比较函数struct cmp {    booloperator()(int a, int b){// 重载运算符,用于比较两个元素的优先级        return a > b;  // 注意:返回true表示优先级低    }};priority_queue<int, vector<int>, cmp> custom_heap;
应用场景:Top K 问题、Dijkstra 算法、哈夫曼树


觉得有用的话,一键三连支持一下吧~