【C++之泛型算法】017已排序区间算法.md

binary_search()

在 C++ 中,binary_search 是一个算法,用于在已排序的序列中执行二分查找。这个算法在 头文件中定义,并且有两个版本:一个用于基本数据类型,另一个用于自定义类型,允许用户提供自定义的比较函数。
基本声明

对于基本数据类型,binary_search 的声明如下:

template <class ForwardIt, class T>
bool binary_search(ForwardIt first, ForwardIt last, const T& value);

其中:

  • ForwardIt 是一个前向迭代器类型,用于指定序列的开始和结束。
  • first 和 last 是指向要搜索的序列的开始和结束的迭代器。
  • value 是要在序列中查找的值。

自定义比较声明

对于自定义类型或需要自定义比较逻辑的情况,binary_search 的声明如下:

template <class ForwardIt, class T, class Compare>
bool binary_search(ForwardIt first, ForwardIt last, const T& value, Compare comp);

其中:

  • Compare 是一个比较函数或函数对象,用于定义序列中元素之间的比较逻辑。

具体用法

以下是一个使用 binary_search 的例子:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    // 创建一个已排序的向量
    std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9};

    // 要查找的元素
    int target = 5;

    // 使用 binary_search 查找元素
    auto result = std::binary_search(v.begin(), v.end(), target);

    if (result) {
        std::cout << "Element " << target << " found in the vector." << std::endl;
    } else {
        std::cout << "Element " << target << " not found in the vector." << std::endl;
    }

    return 0;
}

在这个例子中,我们有一个已排序的整数向量 v,我们想要查找整数 5 是否在这个向量中。binary_search 函数返回一个布尔值,如果找到目标值则返回 true,否则返回 false。

对于自定义类型,你可以提供一个比较函数或函数对象来告诉 binary_search 如何比较元素。例如:

#include <iostream>
#include <vector>
#include <algorithm>

struct Person {
    std::string name;
    int age;

    bool operator<(const Person& other) const {
        return age < other.age; // 定义如何比较 Person 对象
    }
};

int main() {
    // 创建一个已排序的 Person 向量
    std::vector<Person> people = {
        {"Alice", 25},
        {"Bob", 20},
        {"Charlie", 30}
    };

    // 要查找的人
    Person target = {"Charlie", 30};

    // 使用 binary_search 查找元素
    auto result = std::binary_search(people.begin(), people.end(), target);

    if (result) {
        std::cout << "Person " << target.name << " found in the vector." << std::endl;
    } else {
        std::cout << "Person " << target.name << " not found in the vector." << std::endl;
    }

    return 0;
}

在这个例子中,Person 结构体定义了如何比较两个 Person 对象。因此,binary_search 可以使用这些对象的默认比较操作来执行二分查找。

includes()

在 C++ 中,std::includes 是一个泛型算法,它用于检查一个序列是否包含另一个序列。具体来说,std::includes 检查 [first1, last1) 是否包含 [first2, last2),其中两个序列都必须是已排序的。如果 first2 到 last2 中的每个元素都可以在 first1 到 last1 中找到,并且它们的相对顺序保持不变,则 std::includes 返回 true;否则返回 false。
泛型声明

std::includes 的泛型声明如下:

template <class ForwardIt1, class ForwardIt2>
bool includes(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2);

template <class ForwardIt1, class ForwardIt2, class Compare>
bool includes(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2, ForwardIt2 last2, Compare comp);

其中:

  • ForwardIt1 和 ForwardIt2 是前向迭代器类型,用于指定两个序列的开始和结束。
  • first1 和 last1 指向第一个序列的开始和结束。
  • first2 和 last2 指向第二个序列的开始和结束。
  • Compare 是一个可选的比较函数或函数对象,用于定义两个序列中元素之间的比较逻辑。

具体用法

下面是一个使用 std::includes 的例子:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    // 创建两个已排序的向量
    std::vector<int> v1 = {1, 2, 3, 4, 5};
    std::vector<int> v2 = {3, 4};

    // 使用 includes 检查 v1 是否包含 v2
    bool result = std::includes(v1.begin(), v1.end(), v2.begin(), v2.end());

    if (result) {
        std::cout << "v1 includes v2" << std::endl;
    } else {
        std::cout << "v1 does not include v2" << std::endl;
    }

    return 0;
}

在这个例子中,v1 包含 v2,因为 v2 中的所有元素(3 和 4)都可以在 v1 中找到,并且它们的相对顺序保持不变。因此,std::includes 返回 true,并输出 “v1 includes v2”。
自定义比较

如果需要自定义比较逻辑,可以传递一个比较函数或函数对象给 std::includes 的重载版本:

#include <iostream>
#include <vector>
#include <algorithm>

// 自定义比较函数
bool my_compare(int a, int b) {
    return a < b; // 定义小于比较
}

int main() {
    // 创建两个已排序的向量(降序)
    std::vector<int> v1 = {5, 4, 3, 2, 1};
    std::vector<int> v2 = {4, 3};

    // 使用 includes 和自定义比较检查 v1 是否包含 v2
    bool result = std::includes(v1.begin(), v1.end(), v2.begin(), v2.end(), my_compare);

    if (result) {
        std::cout << "v1 includes v2 with custom comparison" << std::endl;
    } else {
        std::cout << "v1 does not include v2 with custom comparison" << std::endl;
    }

    return 0;
}

在这个例子中,我们定义了一个自定义的比较函数 my_compare,它使用小于操作符 < 来比较元素。由于 v1 和 v2 都是降序排列的,我们需要传递这个比较函数给 std::includes,以便它能够正确地判断 v1 是否包含 v2。在这个例子中,输出将是 “v1 includes v2 with custom comparison”,因为根据我们的自定义比较,v1 确实包含 v2。

lower_bound()

std::lower_bound 是 C++ 标准库中的一个泛型算法,用于在一个已排序的序列中查找第一个不小于(即大于或等于)给定值的元素的迭代器。这个算法通常用于二分查找。
泛型声明

std::lower_bound 的泛型声明如下:

template <class ForwardIt, class T>
ForwardIt lower_bound(ForwardIt first, ForwardIt last, const T& value);

template <class ForwardIt, class T, class Compare>
ForwardIt lower_bound(ForwardIt first, ForwardIt last, const T& value, Compare comp);

其中:

ForwardIt 是前向迭代器类型,用于指定序列的开始和结束。
first 和 last 指向序列的开始和结束。
value 是要在序列中查找的值。
Compare 是一个可选的比较函数或函数对象,用于定义序列中元素之间的比较逻辑。

具体用法

下面是一个使用 std::lower_bound 的例子:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    // 创建一个已排序的向量
    std::vector<int> v = {1, 2, 3, 4, 4, 4, 5, 6, 7};

    // 要查找的值
    int target = 4;

    // 使用 lower_bound 查找 target 在向量中的位置
    auto it = std::lower_bound(v.begin(), v.end(), target);

    // it 现在指向向量中第一个不小于 target 的元素
    if (it != v.end() && *it == target) {
        std::cout << "Element " << target << " is found at position " << std::distance(v.begin(), it) << std::endl;
    } else {
        std::cout << "Element " << target << " is not found in the vector" << std::endl;
    }

    return 0;
}

在这个例子中,我们有一个已排序的整数向量 v,我们想要查找整数 4 在向量中的位置。std::lower_bound 返回指向第一个不小于 4 的元素的迭代器。由于 4 在向量中出现了多次,it 将指向第一个 4 的位置。
使用自定义比较

如果你需要自定义比较逻辑,你可以传递一个比较函数或函数对象给 std::lower_bound 的重载版本:

#include <iostream>
#include <vector>
#include <algorithm>

// 自定义比较函数
bool my_compare(int a, int b) {
    return a < b; // 定义小于比较
}

int main() {
    // 创建一个已排序的向量(降序)
    std::vector<int> v = {7, 6, 5, 4, 4, 4, 3, 2, 1};

    // 要查找的值
    int target = 4;

    // 使用 lower_bound 和自定义比较查找 target 在向量中的位置
    auto it = std::lower_bound(v.begin(), v.end(), target, my_compare);

    // it 现在指向向量中第一个不小于 target 的元素
    if (it != v.end() && *it == target) {
        std::cout << "Element " << target << " is found at position " << std::distance(v.begin(), it) << std::endl;
    } else {
        std::cout << "Element " << target << " is not found in the vector" << std::endl;
    }

    return 0;
}

在这个例子中,由于向量 v 是降序排列的,我们传递了一个自定义的比较函数 my_compare 给 std::lower_bound,以便它能够正确地找到第一个不小于 4 的元素。

uper_bound()

在 C++ 标准库中,std::upper_bound 是一个泛型算法,用于在一个已排序的序列中查找第一个大于给定值的元素的迭代器。与 std::lower_bound 类似,std::upper_bound 也常用于二分查找。
泛型声明

std::upper_bound 的泛型声明如下:

template <class ForwardIt, class T>
ForwardIt upper_bound(ForwardIt first, ForwardIt last, const T& value);

template <class ForwardIt, class T, class Compare>
ForwardIt upper_bound(ForwardIt first, ForwardIt last, const T& value, Compare comp);

其中:

  • ForwardIt 是前向迭代器类型,用于指定序列的开始和结束。
  • first 和 last 指向序列的开始和结束。
  • value 是要在序列中查找的值。
  • Compare 是一个可选的比较函数或函数对象,用于定义序列中元素之间的比较逻辑。

具体用法

下面是一个使用 std::upper_bound 的例子:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    // 创建一个已排序的向量
    std::vector<int> v = {1, 2, 3, 4, 4, 4, 5, 6, 7};

    // 要查找的值
    int target = 4;

    // 使用 upper_bound 查找 target 在向量中的位置
    auto it = std::upper_bound(v.begin(), v.end(), target);

    // it 现在指向向量中第一个大于 target 的元素
    if (it != v.begin() && *(it - 1) == target) {
        std::cout << "Element " << target << " is found at position " << std::distance(v.begin(), it - 1) << std::endl;
    } else {
        std::cout << "Element " << target << " is not found in the vector" << std::endl;
    }

    return 0;
}

在这个例子中,我们有一个已排序的整数向量 v,我们想要查找整数 4 在向量中的位置。std::upper_bound 返回指向向量中第一个大于 4 的元素的迭代器。由于 4 在向量中出现了多次,it 将指向第一个大于 4 的元素的位置。因此,我们需要检查 it - 1 是否指向 4 来确定 4 是否存在于向量中。
使用自定义比较

如果需要自定义比较逻辑,你可以传递一个比较函数或函数对象给 std::upper_bound 的重载版本:

#include <iostream>
#include <vector>
#include <algorithm>

// 自定义比较函数
bool my_compare(int a, int b) {
    return a < b; // 定义小于比较
}

int main() {
    // 创建一个已排序的向量(降序)
    std::vector<int> v = {7, 6, 5, 4, 4, 4, 3, 2, 1};

    // 要查找的值
    int target = 4;

    // 使用 upper_bound 和自定义比较查找 target 在向量中的位置
    auto it = std::upper_bound(v.begin(), v.end(), target, my_compare);

    // it 现在指向向量中第一个大于 target 的元素
    if (it != v.begin() && *(it - 1) == target) {
        std::cout << "Element " << target << " is found at position " << std::distance(v.begin(), it - 1) << std::endl;
    } else {
        std::cout << "Element " << target << " is not found in the vector" << std::endl;
    }

    return 0;
}

在这个例子中,由于向量 v 是降序排列的,我们传递了一个自定义的比较函数 my_compare 给 std::upper_bound,以便它能够正确地找到第一个大于 4 的元素。

equal_range()

在 C++ 标准库中,std::equal_range 是一个泛型算法,用于在一个已排序的序列中查找一个值的范围,即所有与给定值相等的元素所在的序列区间。这个算法返回一对迭代器,分别指向第一个大于或等于给定值的元素和第一个大于给定值的元素。如果序列中没有与给定值相等的元素,则这两个迭代器将指向相同的位置。
泛型声明

std::equal_range 的泛型声明如下:

template <class ForwardIt, class T>
std::pair<ForwardIt, ForwardIt> equal_range(ForwardIt first, ForwardIt last, const T& value);

template <class ForwardIt, class T, class Compare>
std::pair<ForwardIt, ForwardIt> equal_range(ForwardIt first, ForwardIt last, const T& value, Compare comp);

其中:

  • ForwardIt 是前向迭代器类型,用于指定序列的开始和结束。
  • first 和 last 指向序列的开始和结束。
  • value 是要在序列中查找的值。
  • Compare 是一个可选的比较函数或函数对象,用于定义序列中元素之间的比较逻辑。

具体用法

下面是一个使用 std::equal_range 的例子:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    // 创建一个已排序的向量
    std::vector<int> v = {1, 2, 3, 4, 4, 4, 5, 6, 7};

    // 要查找的值
    int target = 4;

    // 使用 equal_range 查找值的范围
    auto range = std::equal_range(v.begin(), v.end(), target);

    // range.first 指向第一个大于或等于 target 的元素
    // range.second 指向第一个大于 target 的元素
    
    // 检查是否找到了相等的元素
    if (range.first != range.second) {
        std::cout << "Elements equal to " << target << " are: ";
        for (auto it = range.first; it != range.second; ++it) {
            std::cout << *it << " ";
        }
        std::cout << std::endl;
    } else {
        std::cout << "No elements equal to " << target << " found." << std::endl;
    }

    return 0;
}

在这个例子中,我们有一个已排序的整数向量 v,我们想要查找整数 4 在向量中的范围。std::equal_range 返回一对迭代器 range.first 和 range.second,它们分别指向第一个大于或等于 4 的元素和第一个大于 4 的元素。因为 4 在向量中出现了多次,所以我们可以使用这两个迭代器来遍历所有等于 4 的元素。
使用自定义比较

如果需要自定义比较逻辑,你可以传递一个比较函数或函数对象给 std::equal_range 的重载版本:

#include <iostream>
#include <vector>
#include <algorithm>

// 自定义比较函数
bool my_compare(int a, int b) {
    return a < b; // 定义小于比较
}

int main() {
    // 创建一个已排序的向量(降序)
    std::vector<int> v = {7, 6, 5, 4, 4, 4, 3, 2, 1};

    // 要查找的值
    int target = 4;

    // 使用 equal_range 和自定义比较查找值的范围
    auto range = std::equal_range(v.begin(), v.end(), target, my_compare);

    // ...(与前面的例子相同,处理 range.first 和 range.second)

    return 0;
}

在这个例子中,由于向量 v 是降序排列的,我们传递了一个自定义的比较函数 my_compare 给 std::equal_range,以便它能够正确地找到与 target 相等的元素的范围。

merge()

在 C++ 标准库中,std::merge 是一个泛型算法,用于合并两个已排序的范围(序列)为一个新的已排序范围。这个算法需要两个输入范围(通常是由迭代器指定的容器或数组片段)和一个输出范围,其中输出范围必须足够大以容纳合并后的序列。
泛型声明

std::merge 的泛型声明如下:

template <class InputIt1, class InputIt2, class OutputIt>
OutputIt merge(InputIt1 first1, InputIt1 last1,
               InputIt2 first2, InputIt2 last2,
               OutputIt d_first);

template <class InputIt1, class InputIt2, class OutputIt, class Compare>
OutputIt merge(InputIt1 first1, InputIt1 last1,
               InputIt2 first2, InputIt2 last2,
               OutputIt d_first, Compare comp);

其中:

  • InputIt1 和 InputIt2 是输入范围的迭代器类型。
  • first1 和 last1 定义了第一个输入范围的开始和结束。
  • first2 和 last2 定义了第二个输入范围的开始和结束。
  • OutputIt 是输出范围的迭代器类型。
  • d_first 是输出范围的开始。
  • Compare 是一个可选的比较函数或函数对象,用于定义元素之间的比较逻辑。

具体用法

下面是一个使用 std::merge 的例子:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    // 创建两个已排序的向量
    std::vector<int> v1 = {1, 3, 5};
    std::vector<int> v2 = {2, 4, 6};

    // 创建一个足够大的向量来存储合并后的结果
    std::vector<int> v_merged(v1.size() + v2.size());

    // 使用 merge 算法合并两个向量
    auto it_merged = std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v_merged.begin());

    // 调整 v_merged 的大小以移除尾部的空位
    v_merged.resize(std::distance(v_merged.begin(), it_merged));

    // 打印合并后的向量
    for (int n : v_merged) {
        std::cout << n << " ";
    }
    std::cout << std::endl;

    return 0;
}

在这个例子中,我们有两个已排序的向量 v1 和 v2。我们使用 std::merge 将它们合并到一个新的向量 v_merged 中。std::merge 返回一个指向输出范围末尾的迭代器,我们可以使用 std::distance 来计算实际合并了多少元素,并调整 v_merged 的大小。最后,我们打印出合并后的向量。
使用自定义比较

如果需要自定义比较逻辑,你可以传递一个比较函数或函数对象给 std::merge 的重载版本:

#include <iostream>
#include <vector>
#include <algorithm>

// 自定义比较函数
bool my_compare(int a, int b) {
    return a < b; // 定义小于比较
}

int main() {
    // ...(与前面的例子相同,创建两个向量和输出向量)

    // 使用自定义比较函数合并两个向量
    auto it_merged = std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v_merged.begin(), my_compare);

    // ...(与前面的例子相同,调整大小并打印)

    return 0;
}

在这个例子中,我们传递了自定义的比较函数 my_compare 给 std::merge,以定义元素之间的比较逻辑。这对于处理非标准类型的元素或者需要特殊排序规则的情况非常有用。

set_union()

在 C++ 标准库中,std::set_union 是一个泛型算法,用于合并两个已排序的范围(序列)为一个新的已排序范围,并返回合并后范围的末尾迭代器。该算法实现了并集操作,它合并了两个集合的元素,并保持了结果的排序。
泛型声明

std::set_union 的泛型声明如下:

template <class InputIt1, class InputIt2, class OutputIt>
OutputIt set_union(InputIt1 first1, InputIt1 last1,
                   InputIt2 first2, InputIt2 last2,
                   OutputIt d_first);

template <class InputIt1, class InputIt2, class OutputIt, class Compare>
OutputIt set_union(InputIt1 first1, InputIt1 last1,
                   InputIt2 first2, InputIt2 last2,
                   OutputIt d_first, Compare comp);

其中:

  • InputIt1 和 InputIt2 是输入范围的迭代器类型,分别指向两个已排序的序列。
  • first1 和 last1 定义了第一个输入范围的开始和结束。
  • first2 和 last2 定义了第二个输入范围的开始和结束。
  • OutputIt 是输出范围的迭代器类型,用于存储合并后的序列。
  • d_first 是输出范围的开始。
  • Compare 是一个可选的比较函数或函数对象,用于定义元素之间的比较逻辑。

具体用法

下面是一个使用 std::set_union 的例子:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    // 创建两个已排序的向量
    std::vector<int> v1 = {1, 3, 5};
    std::vector<int> v2 = {2, 4, 6};

    // 计算合并后需要的空间大小
    std::vector<int> v_union(v1.size() + v2.size());

    // 使用 set_union 算法合并两个向量
    auto it_union = std::set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), v_union.begin());

    // 调整 v_union 的大小以移除尾部的空位
    v_union.resize(std::distance(v_union.begin(), it_union));

    // 打印合并后的向量
    for (int n : v_union) {
        std::cout << n << " ";
    }
    std::cout << std::endl;

    return 0;
}

在这个例子中,我们有两个已排序的向量 v1 和 v2。我们使用 std::set_union 将它们合并到一个新的向量 v_union 中。std::set_union 返回一个指向输出范围末尾的迭代器,我们可以使用 std::distance 来计算实际合并了多少元素,并调整 v_union 的大小。最后,我们打印出合并后的向量。
使用自定义比较

如果需要自定义比较逻辑,你可以传递一个比较函数或函数对象给 std::set_union 的重载版本:

#include <iostream>
#include <vector>
#include <algorithm>

// 自定义比较函数
bool my_compare(int a, int b) {
    return a < b; // 定义小于比较
}

int main() {
    // ...(与前面的例子相同,创建两个向量和输出向量)

    // 使用自定义比较函数合并两个向量
    auto it_union = std::set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), v_union.begin(), my_compare);

    // ...(与前面的例子相同,调整大小并打印)

    return 0;
}

在这个例子中,我们传递了自定义的比较函数 my_compare 给 std::set_union,以定义元素之间的比较逻辑。这对于处理非标准类型的元素或者需要特殊排序规则的情况非常有用。

set_intersection()

在 C++ 标准库中,std::set_intersection 是一个泛型算法,用于计算两个已排序范围的交集,并将结果存储在一个输出范围中。这个算法返回指向输出范围末尾的迭代器。
泛型声明

std::set_intersection 的泛型声明如下:

template <class InputIt1, class InputIt2, class OutputIt>
OutputIt set_intersection(InputIt1 first1, InputIt1 last1,
                           InputIt2 first2, InputIt2 last2,
                           OutputIt d_first);

template <class InputIt1, class InputIt2, class OutputIt, class Compare>
OutputIt set_intersection(InputIt1 first1, InputIt1 last1,
                           InputIt2 first2, InputIt2 last2,
                           OutputIt d_first, Compare comp);

其中:

  • InputIt1 和 InputIt2 是输入范围的迭代器类型,分别指向两个已排序的序列。
  • first1 和 last1 定义了第一个输入范围的开始和结束。
  • first2 和 last2 定义了第二个输入范围的开始和结束。
  • OutputIt 是输出范围的迭代器类型,用于存储交集的结果。
  • d_first 是输出范围的开始。
  • Compare 是一个可选的比较函数或函数对象,用于定义元素之间的比较逻辑。

具体用法

下面是一个使用 std::set_intersection 的例子:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    // 创建两个已排序的向量
    std::vector<int> v1 = {1, 2, 3, 4, 5};
    std::vector<int> v2 = {4, 5, 6, 7, 8};

    // 计算交集需要的空间大小(至少为两个集合中最小的那个的大小)
    std::vector<int> v_intersection(std::min(v1.size(), v2.size()));

    // 使用 set_intersection 算法计算交集
    auto it_intersection = std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), v_intersection.begin());

    // 调整 v_intersection 的大小以移除尾部的空位
    v_intersection.resize(std::distance(v_intersection.begin(), it_intersection));

    // 打印交集结果
    for (int n : v_intersection) {
        std::cout << n << " ";
    }
    std::cout << std::endl;

    return 0;
}

在这个例子中,我们有两个已排序的向量 v1 和 v2。我们使用 std::set_intersection 计算它们的交集,并将结果存储在 v_intersection 中。std::set_intersection 返回一个指向输出范围末尾的迭代器,我们可以使用 std::distance 来计算实际计算了多少个交集元素,并调整 v_intersection 的大小。最后,我们打印出交集的结果。
使用自定义比较

如果需要自定义比较逻辑,你可以传递一个比较函数或函数对象给 std::set_intersection 的重载版本:

#include <iostream>
#include <vector>
#include <algorithm>

// 自定义比较函数
bool my_compare(int a, int b) {
    return a < b; // 定义小于比较
}

int main() {
    // ...(与前面的例子相同,创建两个向量和输出向量)

    // 使用自定义比较函数计算交集
    auto it_intersection = std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), v_intersection.begin(), my_compare);

    // ...(与前面的例子相同,调整大小并打印)

    return 0;
}

在这个例子中,我们传递了自定义的比较函数 my_compare 给 std::set_intersection,以定义元素之间的比较逻辑。这对于处理非标准类型的元素或者需要特殊排序规则的情况非常有用。

set_difference()

std::set_difference 是 C++ 标准库中的一个泛型算法,用于计算两个已排序范围的差集。给定两个范围,它返回属于第一个范围但不属于第二个范围的元素。以下是 std::set_difference 的所有声明和具体用法。
泛型声明

template <class InputIt1, class InputIt2, class OutputIt>
OutputIt set_difference(InputIt1 first1, InputIt1 last1,
                        InputIt2 first2, InputIt2 last2,
                        OutputIt d_first);

template <class InputIt1, class InputIt2, class OutputIt, class Compare>
OutputIt set_difference(InputIt1 first1, InputIt1 last1,
                        InputIt2 first2, InputIt2 last2,
                        OutputIt d_first, Compare comp);

其中:

  • InputIt1 和 InputIt2 是输入范围的迭代器类型,分别指向两个已排序的序列。
  • first1 和 last1 定义了第一个输入范围的开始和结束。
  • first2 和 last2 定义了第二个输入范围的开始和结束。
  • OutputIt 是输出范围的迭代器类型,用于存储差集的结果。
  • d_first 是输出范围的开始。
  • Compare 是一个可选的比较函数或函数对象,用于定义元素之间的比较逻辑。

具体用法

下面是一个使用 std::set_difference 的例子:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    // 创建两个已排序的向量
    std::vector<int> v1 = {1, 2, 3, 4, 5};
    std::vector<int> v2 = {4, 5, 6, 7, 8};

    // 计算差集需要的空间大小(至少为第一个集合的大小)
    std::vector<int> v_difference(v1.size());

    // 使用 set_difference 算法计算差集
    auto it_difference = std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), v_difference.begin());

    // 调整 v_difference 的大小以移除尾部的空位
    v_difference.resize(std::distance(v_difference.begin(), it_difference));

    // 打印差集结果
    for (int n : v_difference) {
        std::cout << n << " ";
    }
    std::cout << std::endl;

    return 0;
}

在这个例子中,v1 和 v2 是两个已排序的向量。我们使用 std::set_difference 来计算 v1 中存在但 v2 中不存在的元素,并将结果存储在 v_difference 中。算法返回一个迭代器 it_difference,指向输出范围的末尾。我们再次使用 std::distance 来计算实际计算了多少个差集元素,并调整 v_difference 的大小。最后,我们打印出差集的结果。
使用自定义比较

如果你需要自定义比较逻辑,你可以提供一个比较函数或函数对象。例如:

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional> // for std::greater

int main() {
    std::vector<int> v1 = {8, 7, 6, 5, 4};
    std::vector<int> v2 = {4, 5, 6, 7, 8};
    std::vector<int> v_difference;

    // 使用 std::greater 作为比较函数,计算差集
    auto it_difference = std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(),
                                             std::back_inserter(v_difference), std::greater<int>());

    // 不需要调整大小,因为 std::back_inserter 会自动管理空间

    // 打印差集结果
    for (int n : v_difference) {
        std::cout << n << " ";
    }
    std::cout << std::endl;

    return 0;
}

在这个例子中,我们使用了 std::greater() 作为比较函数,这意味着我们希望找到在 v1 中但不在 v2 中的较大元素。

set_symmetric_difference()

std::set_symmetric_difference 是 C++ 标准库中的一个泛型算法,用于计算两个已排序范围的对称差集。对称差集包括所有属于第一个范围或第二个范围(但不同时属于两者)的元素。下面是 std::set_symmetric_difference 的所有声明和具体用法。
泛型声明

template <class InputIt1, class InputIt2, class OutputIt>
OutputIt set_symmetric_difference(InputIt1 first1, InputIt1 last1,
                                  InputIt2 first2, InputIt2 last2,
                                  OutputIt d_first);

template <class InputIt1, class InputIt2, class OutputIt, class Compare>
OutputIt set_symmetric_difference(InputIt1 first1, InputIt1 last1,
                                  InputIt2 first2, InputIt2 last2,
                                  OutputIt d_first, Compare comp);

其中:

  • InputIt1 和 InputIt2 是输入范围的迭代器类型,分别指向两个已排序的序列。
  • first1 和 last1 定义了第一个输入范围的开始和结束。
  • first2 和 last2 定义了第二个输入范围的开始和结束。
  • OutputIt 是输出范围的迭代器类型,用于存储对称差集的结果。
  • d_first 是输出范围的开始。
  • Compare 是一个可选的比较函数或函数对象,用于定义元素之间的比较逻辑。

具体用法

下面是一个使用 std::set_symmetric_difference 的例子:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    // 创建两个已排序的向量
    std::vector<int> v1 = {1, 2, 3, 4, 5};
    std::vector<int> v2 = {4, 5, 6, 7, 8};

    // 计算对称差集需要的空间大小(至少为两个集合中元素数量之和)
    std::vector<int> v_symmetric_difference(v1.size() + v2.size());

    // 使用 set_symmetric_difference 算法计算对称差集
    auto it_symmetric_difference = std::set_symmetric_difference(
        v1.begin(), v1.end(),
        v2.begin(), v2.end(),
        v_symmetric_difference.begin()
    );

    // 调整 v_symmetric_difference 的大小以移除尾部的空位
    v_symmetric_difference.resize(std::distance(v_symmetric_difference.begin(), it_symmetric_difference));

    // 打印对称差集结果
    for (int n : v_symmetric_difference) {
        std::cout << n << " ";
    }
    std::cout << std::endl;

    return 0;
}

在这个例子中,v1 和 v2 是两个已排序的向量。我们使用 std::set_symmetric_difference 来计算两个向量的对称差集,并将结果存储在 v_symmetric_difference 中。算法返回一个迭代器 it_symmetric_difference,指向输出范围的末尾。我们再次使用 std::distance 来计算实际计算了多少个对称差集元素,并调整 v_symmetric_difference 的大小。最后,我们打印出对称差集的结果。

使用自定义比较

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional> // for std::greater

// 自定义比较函数对象
struct MyCompare {
    bool operator()(const int& a, const int& b) const {
        // 自定义比较逻辑,例如降序比较
        return a > b;
    }
};

int main() {
    // 创建两个已排序的向量(降序)
    std::vector<int> v1 = {5, 4, 3, 2, 1};
    std::vector<int> v2 = {8, 7, 6, 5, 4};

    // 计算对称差集需要的空间大小
    std::vector<int> v_symmetric_difference(v1.size() + v2.size());

    // 使用 set_symmetric_difference 算法计算对称差集,并提供自定义的比较函数对象
    auto it_symmetric_difference = std::set_symmetric_difference(
        v1.begin(), v1.end(),
        v2.begin(), v2.end(),
        v_symmetric_difference.begin(),
        MyCompare() // 使用自定义的比较函数对象
    );

    // 调整 v_symmetric_difference 的大小以移除尾部的空位
    v_symmetric_difference.resize(std::distance(v_symmetric_difference.begin(), it_symmetric_difference));

    // 打印对称差集结果
    for (int n : v_symmetric_difference) {
        std::cout << n << " ";
    }
    std::cout << std::endl;

    return 0;
}

在这个例子中,我们定义了一个名为 MyCompare 的结构体,它实现了函数调用运算符 operator(),用于比较两个整数。在这个比较函数中,我们使用了降序比较逻辑(a > b),这与默认的升序比较相反。然后,在调用 std::set_symmetric_difference 时,我们将 MyCompare() 的一个实例作为第六个参数传递,从而告诉算法使用我们的自定义比较逻辑。

请注意,当使用自定义比较函数或函数对象时,你需要确保该函数或对象适用于你的输入数据,并且与你的排序逻辑一致。在上面的例子中,由于我们使用的是降序排序的向量,因此自定义比较也必须与这种排序方式相匹配。如果输入向量是升序排序的,那么你应该在自定义比较函数中使用 a < b 的逻辑。

inplace_merge()

std::inplace_merge 是 C++ 标准库中的一个泛型算法,用于合并两个连续的已排序范围(或称为子序列)为一个单一的已排序范围。这个算法会修改输入范围以产生结果,因此被称为“就地”(inplace)合并。
泛型声明

template< class ForwardIt >
void inplace_merge( ForwardIt first, ForwardIt middle, ForwardIt last );

template< class ForwardIt, class Compare >
void inplace_merge( ForwardIt first, ForwardIt middle, ForwardIt last, Compare comp );

其中:

  • ForwardIt 是一个前向迭代器的类型,指向已排序范围的元素。
  • first 和 middle 定义了第一个子序列的范围 [first, middle)。
  • middle 和 last 定义了第二个子序列的范围 [middle, last)。
  • comp 是一个可选的比较函数或函数对象,用于定义元素之间的比较逻辑。如果不提供,则使用 < 操作符。

具体用法

下面是一个使用 std::inplace_merge 的例子:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    // 创建一个未排序的向量
    std::vector<int> v = {1, 4, 2, 5, 3, 6};

    // 分割向量成两个子序列
    auto middle = v.begin() + v.size() / 2;

    // 分别对两个子序列进行排序
    std::sort(v.begin(), middle);
    std::sort(middle, v.end());

    // 使用 inplace_merge 将两个子序列合并成一个排序后的序列
    std::inplace_merge(v.begin(), middle, v.end());

    // 打印排序后的向量
    for (int n : v) {
        std::cout << n << " ";
    }
    std::cout << std::endl;

    return 0;
}

在这个例子中,我们首先创建了一个未排序的向量 v。然后,我们将向量分割成两个等长的子序列(如果元素数量是奇数,则第一个子序列多一个元素)。接着,我们对这两个子序列分别进行排序。最后,我们调用 std::inplace_merge 来合并这两个已排序的子序列,形成一个完全排序的向量。

std::inplace_merge 保证合并后的范围是排序好的,并且不需要额外的存储空间(除了输入范围本身)。因此,它非常适合在需要就地修改数据并且空间有限的情况下使用。
使用自定义比较

如果你需要自定义比较逻辑,你可以提供一个比较函数或函数对象给 std::inplace_merge。例如:

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional> // for std::greater

int main() {
    // 创建一个未排序的向量(降序)
    std::vector<int> v = {1, 4, 2, 5, 3, 6};

    // 分割向量成两个子序列
    auto middle = v.begin() + v.size() / 2;

    // 分别对两个子序列进行降序排序
    std::sort(v.begin(), middle, std::greater<int>());
    std::sort(middle, v.end(), std::greater<int>());

    // 使用 inplace_merge 将两个子序列合并成一个降序排序后的序列
    std::inplace_merge(v.begin(), middle, v.end(), std::greater<int>());

    // 打印排序后的向量
    for (int n : v) {
        std::cout << n << " ";
    }
    std::cout << std::endl;

    return 0;
}

在这个例子中,我们使用 std::greater() 作为比较函数来告诉 std::sort 和 std::inplace_merge 按照降序来排序和合并元素。

  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

熊猫Devin

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值