[C++ standard library sorting algorithm] In-depth analysis of the sorting algorithm in the C++ standard library: functions, principles and applications


1. Introduction

In modern programming, sorting is one of the most basic and commonly used operations. Whether in database query, data analysis or simple list display, sorting is indispensable. C++, as a widely used programming language, naturally provides developers with a series of powerful sorting algorithms. These algorithms are not only efficient, but also well designed to meet a variety of application requirements.

As stated in "Introduction to Algorithms": "The importance of algorithms in computer science is self-evident. They are the steps to solve problems and the instructions for computers to perform tasks." ("Algorithms are at the heart of computer science. They are are the steps that solve problems, the instructions that computers follow." - Introduction to Algorithms )

In this chapter, we will provide an overview of the sorting algorithms provided in the C++ standard library and pave the way for in-depth discussion in subsequent chapters.

1.1 Overview of sorting algorithms in the C++ standard library

The sorting algorithm in the C++ standard library is <algorithm>defined in the header file. These algorithms provide developers with powerful tools that allow them to sort and process data with ease. These algorithms are designed to provide maximum efficiency and flexibility while maintaining code simplicity and readability.

For example, std::sortis a very powerful sorting algorithm that can sort almost any type of data. Its underlying implementation is based on a mix of quick sort, heap sort, and insertion sort, which allows it to provide very good performance in most cases.

As stated in "C++ Primer": "The C++ Standard Library provides a rich set of algorithms that can be used for a variety of common programming tasks." for a variety of common programming tasks." - C++ Primer )

In the following chapters, we will delve into the functionality, underlying principles, and usage of each sorting algorithm. We will also look at stdthe source code of the library to gain a deeper understanding of the design and implementation of these algorithms.

// 示例代码:使用std::sort进行排序
#include <algorithm>
#include <vector>
#include <iostream>

int main() {
    
    
    std::vector<int> v = {
    
    4, 2, 5, 1, 3};
    std::sort(v.begin(), v.end());
    for (int i : v) {
    
    
        std::cout << i << " ";
    }
    return 0;
}

In the above code example, we std::sortsorted a vector of integers and output the sorted result. This is just the tip of the iceberg of sorting algorithms in the C++ standard library, and subsequent chapters will reveal more exciting content to you.

Sorting Algorithm Function description (Description) Underlying Principle Precondition Use Case
std::sort Sort a sequence in ascending order A mix of quick sort, heap sort and insertion sort Random access iterator universal sorting
std::stable_sort stable sorting merge sort Random access iterator Keep elements in relative order
std::partial_sort Sort the first n elements of the sequence Heap sort Random access iterator Partial sorting
std::nth_element Sort elements at a specified position Based on quick selection algorithm Random access iterator Find the nth smallest element
std::inplace_merge Merge two sorted sequences Based on two-way merge bidirectional iterator merge sort

Bubble Sort and Selection Sort are two classic sorting algorithms. They are often used as teaching tools in computer science education because their principles are simple and easy to understand. However, they are not very efficient in practical applications, especially for large data sets. Here are the reasons why these two sorting algorithms are not implemented in the C++ standard library:

  1. Efficiency issues : The time complexity of both bubble sort and selection sort is O(n^2), which means that their efficiency will be very low when processing large data sets. In contrast, algorithms in the C++ standard library std::sortare usually implemented based on more efficient sorting algorithms (such as a mixture of quick sort, heap sort, and insertion sort), with an average time complexity of O(n log n).

  2. Limited practical applications : Due to the above-mentioned efficiency issues, bubble sort and selection sort have very limited use in practical applications. In most cases, developers will choose a more efficient sorting algorithm.

  3. Goal of the standard library : The goal of the C++ standard library is to provide efficient, versatile, and reliable algorithms and data structures. Including less efficient algorithms may not meet this goal.

  4. Teaching purposes : Although bubble sort and selection sort are not commonly used in practical applications, they are still valuable in teaching. They provide a good introduction for beginners to understand the basic concepts of sorting algorithms.

In short, although bubble sort and selection sort have their value in teaching, they have not been adopted by the C++ standard library due to their efficiency issues.

2. Basic Sorting Algorithms

2.1 std::sort

std::sortIt is the most commonly used sorting algorithm in the C++ standard library. It can sort a sequence in ascending order, but it can also do descending sorting or other custom sorting by providing a custom comparison function or lambda expression.

underlying principles

std::sortThe underlying implementation is based on a mix of quick sort, heap sort, and insertion sort. In most cases it uses quick sort. But when the recursion depth exceeds a certain limit, to avoid worst-case performance, it switches to heap sort. For small chunks of data, it may use insertion sort because in this case insertion sort may be faster than other algorithms.

Preconditions

To use std::sort, you need to provide a random access iterator. This means you can use it to sort arrays with sum std::vector, but not with std::listor std::forward_list.

code example

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

int main() {
    
    
    std::vector<int> v = {
    
    4, 2, 5, 1, 3};
    std::sort(v.begin(), v.end());
    for(int i : v) {
    
    
        std::cout << i << " ";
    }
    // 输出: 1 2 3 4 5
}

As Zhuangzi said in "Zhuangzi·Xiaoyaoyou": "Heaven and earth coexist with me, and all things are one with me." In programming, algorithms and data structures complement each other. We can't just focus on the efficiency of the algorithm, but also consider its compatibility with specific data structures.

2.2 std::stable_sort

std::stable_sortVery similar to std::sort, but it guarantees that the relative order of equal elements does not change. This is called stable sorting.

underlying principles

std::stable_sortThe underlying implementation of is based on merge sort. Merge sort is a divide-and-conquer algorithm that splits a sequence in half, sorts each half, and then merges the two sorted halves into a single whole.

Preconditions

As std::sortwith , std::stable_sortrandom access iterators are also required.

code example

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

struct Point {
    
    
    int x, y;
};

int main() {
    
    
    std::vector<Point> v = {
    
    {
    
    4, 1}, {
    
    2, 2}, {
    
    5, 3}, {
    
    2, 4}, {
    
    3, 5}};
    std::stable_sort(v.begin(), v.end(), [](const Point& a, const Point& b) {
    
    
        return a.x < b.x;
    });
    for(const auto& p : v) {
    
    
        std::cout << "(" << p.x << ", " << p.y << ") ";
    }
    // 输出: (2, 2) (2, 4) (3, 5) (4, 1) (5, 3)
}

In this example, although there are two points with an x ​​value of 2, their relative order remains unchanged after sorting.

As Mencius said in "Mencius Gongsun Chou": "Those who find the big can talk about the small." In algorithms, after understanding its core principles, we can better apply it to solve practical problems.

In the following chapters, we will discuss partial sorting algorithms and merge sorting algorithms.

3. Partial Sorting Algorithms

3.1 std::partial_sort

std::partial_sortIt is a sorting algorithm in the C++ standard library, which can sort the first n elements of a sequence.

Function description:

This can be used when we only care about the first few smallest (or largest) elements in the sequence, rather than the entire sequence std::partial_sort. For example, if you want to find the first three smallest elements in a sequence and sort them, you can use this algorithm.

The underlying principle:

std::partial_sortThe underlying implementation is based on the heap sort algorithm. It first std::make_heapcreates a max-heap std::pop_heapusing

Usage example:

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

int main() {
    
    
    std::vector<int> v = {
    
    5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
    std::partial_sort(v.begin(), v.begin() + 3, v.end());

    for (int i : v) {
    
    
        std::cout << i << " ";
    }
    // 输出:0 1 2 5 8 6 7 9 4 3
}

Preconditions:

The prerequisite for using std::partial_sortis that the sequence supports random access iterators, such as std::vector, std::arrayor native arrays.

3.2 std::nth_element

std::nth_elementIs another partial sorting algorithm in the C++ standard library.

Function description:

This algorithm rearranges the sequence so that the element at the specified position is where it should be after sorting, no element to the left of the position is greater than the element, and no element to the right of the position is less than the element.

The underlying principle:

std::nth_elementThe underlying implementation of is based on the quick select algorithm, which is a variant of the quick sort algorithm. It works by partitioning to determine the correct position of each element until the desired element is found.

Usage example:

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

int main() {
    
    
    std::vector<int> v = {
    
    5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
    std::nth_element(v.begin(), v.begin() + 5, v.end());

    for (int i : v) {
    
    
        std::cout << i << " ";
    }
    // 输出可能为:4 2 0 1 3 5 7 9 8 6
}

Preconditions:

Same std::partial_sortas , std::nth_elementthe prerequisite for using is that the sequence supports random access iterators.

As Zhuangzi said in "Zhuangzi·Xiaoyaoyou": "Heaven and earth live together with me, and all things are one with me." In programming, we often need to sort data in order to better organize and process them. This is just like how we classify and organize things in life, helping us better understand and master them. The C++ standard library provides us with these powerful sorting tools, allowing us to process data more efficiently.

4. 合并排序算法 (Merge Sorting Algorithm)

4.1 std::inplace_merge

std::inplace_merge 是 C++ 标准库中提供的一个排序算法,它的主要功能是合并两个已排序的序列,使得合并后的序列仍然是有序的。

4.1.1 功能描述 (Functionality)

当我们有两个已排序的子序列,并希望将它们合并为一个完整的已排序序列时,可以使用 std::inplace_merge。这在归并排序中是非常常见的操作。

例如,考虑以下两个已排序的子序列:

序列1: 1, 3, 5
序列2: 2, 4, 6

使用 std::inplace_merge 合并后的结果将是:

合并后的序列: 1, 2, 3, 4, 5, 6

4.1.2 底层原理 (Underlying Principle)

std::inplace_merge 的底层原理是基于两路归并算法。在两路归并中,我们从两个子序列的开始位置开始,比较它们的元素,并选择较小的元素放入结果序列中。然后,我们移动到所选子序列的下一个元素,并重复此过程,直到其中一个子序列为空。最后,我们将非空子序列的其余部分复制到结果序列中。

4.1.3 前置条件 (Preconditions)

为了使用 std::inplace_merge,我们需要提供两个迭代器,它们定义了要合并的序列的范围。这两个迭代器之间的序列应该是已排序的,并且它们应该是双向迭代器,这意味着我们可以在序列中向前和向后移动。

4.1.4 代码示例 (Code Example)

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

int main() {
    
    
    std::vector<int> v = {
    
    1, 3, 5, 2, 4, 6};
    std::inplace_merge(v.begin(), v.begin() + 3, v.end());

    for (int num : v) {
    
    
        std::cout << num << " ";
    }
    // 输出: 1 2 3 4 5 6
}

在上述代码中,我们首先创建了一个包含两个已排序子序列的向量。然后,我们使用 std::inplace_merge 合并这两个子序列。

正如《算法导论》中所说:“归并排序算法完全遵循分治模式。它的直观操作是:分解 - 将待排序的n个元素的序列分解为两个各含n/2个元素的子序列;解决 - 使用归并排序递归地排序两个子序列;合并 - 合并两个已排序的子序列以产生已排序的答案。”[算法导论]

通过这种方式,我们可以看到归并排序不仅是一种高效的排序算法,而且它也揭示了人类思维的深度,即通过将复杂问题分解为更小的、更容易管理的部分来解决问题,然后再将这些部分组合起来得到完整的解决方案。这种思维方式在许多其他领域,如科学、工程和日常生活中都有应用。

: 本节中的代码示例和解释是基于C++标准库的实现。如果你对底层的实现细节感兴趣,可以查看GCC或Clang的源码库中的<algorithm>头文件。

5. 排序检查 (Sorting Checks)

5.1 std::is_sorted

std::is_sorted 是一个非常实用的函数,它可以帮助我们检查一个序列是否已经被排序。这个函数返回一个布尔值,如果序列已经被排序(默认为升序),则返回 true,否则返回 false

使用示例:

std::vector<int> v = {
    
    1, 2, 3, 4, 5};
if (std::is_sorted(v.begin(), v.end())) {
    
    
    std::cout << "The sequence is sorted." << std::endl;
} else {
    
    
    std::cout << "The sequence is not sorted." << std::endl;
}

在这个示例中,输出将是 “The sequence is sorted.”,因为向量 v 已经被排序。

底层实现:

std::is_sorted 的实现相对简单。它从第一个元素开始,逐个比较相邻的元素,直到找到一个不满足排序条件的元素或检查完所有元素为止。

前置条件:

  • 前向迭代器

正如伟大的计算机科学家 Donald Knuth 在《计算机程序设计艺术》中所说:“我们应该忘记小效率,说到90%的时间:过早的优化是万恶之源。”

5.2 std::is_sorted_until

std::is_sorted_until 函数返回一个迭代器,指向序列中第一个不满足排序条件的元素。如果整个序列都是有序的,那么返回值将是序列的 end() 迭代器。

使用示例:

std::vector<int> v = {
    
    1, 2, 3, 5, 4};
auto it = std::is_sorted_until(v.begin(), v.end());
if (it != v.end()) {
    
    
    std::cout << "The sequence is sorted until element: " << *it << std::endl;
} else {
    
    
    std::cout << "The sequence is completely sorted." << std::endl;
}

在这个示例中,输出将是 “The sequence is sorted until element: 4.”,因为向量 v 在元素4之前是有序的。

底层实现:

std::is_sorted_until 的实现与 std::is_sorted 类似,但当找到第一个不满足排序条件的元素时,它会返回该元素的迭代器。

前置条件:

  • 前向迭代器

在编程中,我们经常需要确保数据的正确性和完整性。这两个函数为我们提供了一种简单而有效的方法来验证数据是否已经被正确排序。如同古老的哲学家孔子所说:“知之为知之,不知为不知,是知也。”,在编程中,知道自己的数据状态是非常重要的。

希望这两个函数能帮助你更好地理解和使用C++标准库中的排序检查工具。

6. 结论 (Conclusion)

在现代编程中,排序是一个基础且至关重要的操作。C++标准库中的排序算法为我们提供了强大的工具,使我们能够轻松地对数据进行排序。这些算法不仅高效,而且设计精良,可以满足各种应用场景的需求。

正如《算法导论》(Introduction to Algorithms)中所说:“算法是计算的核心,是计算机科学的灵魂。”排序算法在这其中扮演了一个关键的角色。它们不仅是计算机科学的基石,而且是我们日常编程中的得力助手。

std库的源码中,我们可以深入研究这些排序算法的实现。例如,std::sort的实现可以在GCC编译器的<algorithm>头文件中找到。通过深入研究这些源码,我们可以更好地理解算法的工作原理,以及为什么它们如此高效。

但是,排序不仅仅是关于算法和计算机。它也与我们的思维方式和如何组织信息有关。正如孔子在《论语》中所说:“知之者不如好之者,好之者不如乐之者。”这意味着真正理解和欣赏排序的美学和效率是一种艺术。

最后,无论你是一个经验丰富的开发者,还是一个初学者,C++标准库中的排序算法都是你工具箱中不可或缺的工具。希望通过本文,你能更深入地理解这些算法,以及如何在实际编程中应用它们。

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

int main() {
    
    
    std::vector<int> data = {
    
    5, 3, 8, 1, 4};
    std::sort(data.begin(), data.end());
    for (int num : data) {
    
    
        std::cout << num << " ";
    }
    return 0;
}

上述代码示例展示了如何使用std::sort对一个整数向量进行排序。这只是C++标准库中众多排序算法的冰山一角,但它为我们提供了一个开始,引导我们进入排序的奇妙世界。

在我们的编程学习之旅中,理解是我们迈向更高层次的重要一步。然而,掌握新技能、新理念,始终需要时间和坚持。从心理学的角度看,学习往往伴随着不断的试错和调整,这就像是我们的大脑在逐渐优化其解决问题的“算法”。

这就是为什么当我们遇到错误,我们应该将其视为学习和进步的机会,而不仅仅是困扰。通过理解和解决这些问题,我们不仅可以修复当前的代码,更可以提升我们的编程能力,防止在未来的项目中犯相同的错误。

我鼓励大家积极参与进来,不断提升自己的编程技术。无论你是初学者还是有经验的开发者,我希望我的博客能对你的学习之路有所帮助。如果你觉得这篇文章有用,不妨点击收藏,或者留下你的评论分享你的见解和经验,也欢迎你对我博客的内容提出建议和问题。每一次的点赞、评论、分享和关注都是对我的最大支持,也是对我持续分享和创作的动力。


阅读我的CSDN主页,解锁更多精彩内容:泡沫的CSDN主页
在这里插入图片描述

Guess you like

Origin blog.csdn.net/qq_21438461/article/details/133346119