vector基础概念

        vector是标准模板库(STL)提供的一种动态数组容器,能够存储相同类型的元素。类似于数组,vector是一种内存中连续存储的结构。但同时又区别于普通数组,vector 的大小可以动态调整,支持在运行时高效地插入或删除元素。

        通俗的说vector就是数组的进阶版,可以像数组那样通过索引,进行直接访问元素,实现时间复杂度为 o(1)。功能上不仅支持容量大小的动态调整,还提供了多种多样的方法,方便对vector进行操作。


vector对象的创建方法

  • 通过默认构造函数进行创建,即无任何参数输入
  • 通过列表进行显式、隐式创建
  • 通过迭代器进行创建
  • 通过指定初始元素个数进行创建
  • 通过拷贝构造进行创建

1.默认构造函数

创建一个空的vector对象,不包含任何元素。适用于需要从零动态添加元素的情况。

std::vector<int> v; // 默认构造函数,v为空vector

2.通过列表进行显式和隐式创建

  • 显式创建:使用花括号{ }直接初始化,直接在声明时指定元素列表。
  • 隐式创建:使用赋值运算符=结合花括号列表初始化,语法更简洁,但效果相同。 这两种方式都利用初始化列表(C++11特性),创建一个包含指定元素的vector。
// 显式创建:直接使用花括号
std::vector<int> v_explicit{1, 2, 3}; // v_explicit包含元素1,2,3   
// 隐式创建:通过赋值运算符
std::vector<int> v_implicit = {4, 5, 6}; // v_implicit包含元素4,5,6

3.通过迭代进行创建

        使用迭代器范围创建vector,从一个已有容器(如数组、list或其他vector)的迭代器开始和结束位置复制元素。适用于高效复制部分或全部元素。

int num[] = {1, 2, 3, 4};                    // 数组
std::list<int> my_list = {10, 20, 30};       // list
std::vector<int> my_vector = {12, 14, 15};   // vector

// 通过迭代器范围创建vector
std::vector<int> v1(num, num + sizeof(num)/sizeof(int));// v1包含元素1, 2, 3, 4
std::vector<int> v2(my_list.begin(), my_list.end());    // v2包含元素10, 20, 30
std::vector<int> v3(my_vector.begin(), my_vector.end());// v3包含元素12, 14, 15

4.通过指定初始元素个数进行创建

        指定vector的初始大小(元素个数),所有元素使用默认值初始化(如int类型默认为0)。也可以指定初始值。

// 指定大小:创建大小为5的vector,元素默认为0
std::vector<int> v_size(5); // v_size = {0, 0, 0, 0, 0}   

// 指定大小和初始值:创建大小为3的vector,所有元素初始化为100
std::vector<int> v_size_value(3, 100); // v_size_value = {100, 100, 100}

5.通过拷贝构造进行创建

     使用拷贝构造函数基于另一个vector创建新对象,复制所有元素。适用于需要独立副本的场景。

std::vector<int> original = {1, 2, 3};
// 拷贝构造:创建original的副本
std::vector<int> copy_vector(original); // copy_vector包含元素1,2,3

        在实际编程中,需要根据场景的需要灵活选择构造方法。例如,优先使用初始化列表以简化代码,或使用迭代器以避免不必要的拷贝。


vector赋值操作

        在C++中,vector的赋值操作用于修改已有vector对象的内容,而不是创建新对象(拷贝构造则用于创建新对象时初始化)。赋值操作主要分为两种方式:使用赋值运算符(=)和assign成员函数。赋值操作与拷贝构造不同:拷贝构造发生在对象创建时,如vector<int> target = source, 而赋值操作发生在对象已存在时。

1.通过赋值运算符进行赋值

        使用赋值运算符=将另一个vector的内容复制到现有或新创建的vector中。如果目标vector已存在,会覆盖原有内容;如果目标未初始化,则隐式创建新vector。

std::vector<int> source = {7, 8, 9};
// 赋值运算符:创建新vector或覆盖现有vector
std::vector<int> target; // 先创建空vector
target = source; // target现在包含元素7,8,9

 2.通过assign方法赋值

        assign成员函数用于重置现有vector的内容,而不是创建新对象。它可以指定元素个数和值,使用迭代器范围来填充内容或指定元素列表。此操作会销毁原有元素并重新分配内存(相当于“重新创建”内容)。

std::vector<int> v;
// 使用assign指定元素个数和值
v.assign(4, 50);         // v现在包含四个50: {50, 50, 50, 50}
    
// 使用assign指定迭代器范围
int arr[] = {60, 70, 80};
v.assign(arr, arr + 3);  // v现在包含元素60,70,80

// 使用assign指定列表
v.assign({12, 23, 12});  // v现在包含元素12,23,12

    vector数据的插入与删除

    插入方法 insert push_back
    删除方法 erase/clear pop_back

            数组的插入与删除,涉及到创建新数组、遍历赋值等一系列费时操作。而vector提供了封装好的插入删除方法,可以直接的调用,大大提高程序的性能和效率。

    1. 插入操作(insert、push_back)

    插入操作允许在vector的任意位置添加新元素。常见方法包括:

    • push_back方法:在vector末尾添加一个元素。这是一个高效的操作,平均时间复杂度为o(1)(摊销时间)。由于vector使用动态扩容策略,当触发扩容时时间复杂度为o(n)。
    • insert方法:在指定位置插入一个或多个元素。例如,在索引处插入元素,需要移动后续元素,平均时间复杂度为o(n),其中n是vector的大小。需要注意的是insert函数中,第一个参数并不是int类型的索引,而是迭代器。

            插入操作可能导致内存重新分配,从而增加开销。在C++中,使用reserve方法可以预分配内存以减少扩容次数。(在vector空间预留部分,我们会解释为什么会增加开销)

    std::vector<int> vec = {10, 20, 30};  // 容器内容:10,20,30
    
    vec.push_back(40);         // 末尾插入40 容器内容:10,20,30,40
    // 在索引1处插入15 
    vec.insert(vec.begin() + 1, 15); // 容器内容:10,15,20,30,40
    
    2. 删除操作(pop_back、erase)

    删除操作移除vector中的元素,常见方法包括:

    • pop_back方法:删除vector末尾的元素。时间复杂度为o(1),因为它只需减小大小,容量大小不变。
    • erase方法:删除指定位置或范围的元素。删除索引处的元素,需要移动后续元素,平均时间复杂度为o(n)。
    • clear方法:删除容器中的所有元素。

            删除操作不会自动释放所有内存,vector保留容量以备后续使用。如果需要彻底释放内存,可以使用shrink_to_fit方法,或参照vector内存交换部分,使用swap函数实现内存释放。

    std::vector<int> vec = {10, 20, 30};
    std::cout << vec.size() << " " << vec.capacity() << std::endl; // 3 3
    
    vec.pop_back();         // 删除末尾元素 10 20
    std::cout << vec.size() << " " << vec.capacity() << std::endl; // 2 3
    
    vec.erase(vec.begin()); // 删除索引0处的元素  20
    std::cout << vec.size() << " " << vec.capacity() << std::endl; // 1 3
    
    vec.clear();            // 删除所有元素
    std::cout << vec.size() << " " << vec.capacity() << std::endl; // 0 3
    
    vec.shrink_to_fit();    // 释放冗余内存
    std::cout << vec.size() << " " << vec.capacity() << std::endl; // 0 0

    vector扩充机制

           “扩容”(resizing)指的是当某个容器(如数组、列表、哈希表等)的存储空间不足以容纳新数据时,动态增加其容量的过程。 vector同顺序表一样都存在两个变量size和capacity,size表示当前元素的数量,可以通过size()函数获取;而capacity表示当前分配的内存可容纳的元素上限,可以通过capacity()函数获取。当size == capacity时,再新增元素,当前分配的内存不足以再存储新的元素,就会触发扩容的操作。

           过程我们可以参照下图。 扩容过程可以描述为:当size==capacity时,再想添加新元素到容器,发现容量已满,强行插入会造成下标越界,这时需要找一块更大内存的空间。先计算新的内存块的大小,分配新的内存块,将旧的内存块上进行遍历将元素逐个复制到新的内存块上,销毁旧的内存空间。可以发现,每次扩容都会有新内存的创建、对vector容器进行遍历复制、旧内存的释放,且容器元素越多所花费时间就越多,时间复杂度为o(n),是一个非常费时的操作。

            我们具体来分析一下扩容的过程:

    std::vector<int> vec;  // 初始capacity=0
    cout << vec.size() << " " << vec.capacity() << endl; // 0 0   
    
    vec.push_back(1);      // 首次分配
    cout << vec.size() << " " << vec.capacity() << endl; // 1 1
    
    vec.push_back(2);      // capacity=2
    cout << vec.size() << " " << vec.capacity() << endl;  // 2 2
    
    vec.push_back(3);vec.push_back(3);vec.push_back(3);vec.push_back(3);      
    cout << vec.size() << " " << vec.capacity() << endl; // 6 6
    
    vec.push_back(3);
    cout << vec.size() << " " << vec.capacity() << endl; // 7 9
    1. 创建一个空的vector,这时vector的size和capacity的大小都为0
    2. 通过push_back函数,在vector中添加新元素,这时size和capacity都扩容至1
    3. 再通过push_back函数,在vector中添加新元素,这时size和capacity都扩容至2
    4. 通过push_back函数,反复添加,添加4个元素,这时size和capacity都扩容至6
    5. 最后通过push_back函数,添加1个元素,可以发现size和capacity分布变为7 9

            这个过程中存在多次扩容,1到2:capacity从0到1,2到3:capacity从1到2,4到5:capacity从6到9。我们可以通过分析push_back的函数源码实现来了解扩容的机制,通过进入bush_back的源码实现。

    push_back源码实现      

            我们可以发现当_Mylast != _My_data._Myend 时候,即(size < capacity)的时候,会调用_Emplace_back_with_unused_capacity 函数进行添加元素。反之则(size == capacity)需要进行扩容操作,则调用_Emplace_reallocate 函数。

    _Emplace_reallocate函数

    const size_type _Newsize = _Oldsize + 1;
    size_type _Newcapacity   = _Calculate_growth(_Newsize);

          我们重点关注这个函数的以上两行,计算新的capacity的大小存储到_Newcapacity变量中,传入参数为_Oldsize + 1,即原容量+1。进入_Calculate_growth函数,_Oldsize + 1(原容量+1)作为形参_Newsize。

    _Calculate_growth函数

            可以看到 const size_type _Geometric = _Oldcapacity + _Oldcapacity / 2; 采用1.5倍的乘法因子(扩容因子),当然由于是整除会向下取整。

            同时可以关注到if (_Geometric < _Newsize) 判断条件,1.5倍得到的容量会和_Newsize进行比较,也就是会和_Oldsize + 1(原容量+1)进行比较,取较大的值作为新的容量的大小。

    因此在1到2的过程(capacity从0到1)中:_Oldsize + 1 = 1 ,通过扩容因子得到的新容量为0(0  + 0/2),因此返回1(_Oldsize + 1)。

    2到3的过程(capacity从1到2)中:_Oldsize + 1 = 2 ,通过扩容因子得到的新容量为1(1  + 1/2),因此返回2(_Oldsize + 1)。

    4到5的过程(capacity从6到9)中:_Oldsize + 1 = 7 ,通过扩容因子得到的新容量为9(6  + 6/2),因此返回9(扩容因子计算)。


    vector随机访问

            随机访问是指能够以常数时间直接获取容器中任意位置的元素(随机访问的时间复杂度是常数时间,即o(1)。)。在vector中,每个元素都有一个唯一的索引(从0开始),用户可以通过索引立即访问该元素,无需像链表那样从头开始顺序查找。在包含n个元素的vector中,访问第i个元素的操作是即时的。这表示无论vector的大小如何,访问任何元素所需的时间基本相同。相比之下,顺序访问结构(如链表)的时间复杂度为o(n),因为需要遍历元素。

            vector支持随机访问的核心原因是其内存布局:元素在内存中是连续存储的。这意味着所有元素被分配在相邻的内存地址上,因此可以通过简单的数学计算直接定位元素地址。具体来说:

            随机访问主要有两种方式:通过[ ]访问(下标访问/索引访问),通过运算符重载实现;通过at()函数实现(安全索引访问)。用法也很简单

    std::vector<int> vec = {10, 20, 30};
        
    std::cout << "[]访问: vec[1] = " << vec[1] << std::endl; // 输出: 20 
    std::cout << "at访问: vec.at(1) = " << vec.at(1) << std::endl; // 输出: 20

            两者的区别主要在于是否存在异常检测,当索引超出容器的大小会导致索引的越界,若没有异常检测,程序可能访问无效内存地址,导致崩溃。同样,我们看两个函数实现的源码。

    [ ]运算符重载实现

    at函数实现

            可以发现只有_CONTAINER_DEBUG_LEVEL > 0 条件满足的时候,[ ]重载访问函数才会有异常检测,而at函数只要调用就会有异常检测。可知[ ]访问追求速度,但风险更高;at访问强调安全性,代价是轻微性能损失。因此在能确保索引不越界的情况下尽可能的使用更高效率的[ ]访问。

    std::vector<int> vec = {10, 20, 30};
        
    // []访问示例:高效但无检查
    std::cout << "[]访问: vec[1] = " << vec[1] << std::endl; // 输出: 20 (索引1有效)
    // 越界访问可能崩溃: vec[3] 未定义
    // at访问示例:安全有检查
    try {
        std::cout << "at访问: vec.at(1) = " << vec.at(1) << std::endl; // 输出: 20
        std::cout << "at访问越界测试: vec.at(3) = ..." << std::endl;
        vec.at(3); // 索引3无效,抛出异常
    } catch (const std::out_of_range& e) {
        std::cout << "错误: " << e.what() << std::endl; // 捕获并处理异常
    }    
    

    vector内存交换

            内存交换(memory swapping)是vector的一个重要操作,用于高效地交换两个vector的内部存储,从而避免不必要的元素复制,优化性能并减少内存开销。主要借助于swap()成员函数实现vector的swap成员函数用于交换两个vector的全部内部数据,包括:

    • 存储元素的内存缓冲区地址(指针)
    • size和capacity的值

            交换操作是常数时间 o (1) 的,因为它仅交换内部指针和属性,不涉及元素的复制或移动(除非元素类型本身的交换有额外开销)。

    常见应用场景

    • 快速交换内容:在算法中(如排序或数据迁移),交换两个vector的内容而不复制元素。
    • 优化空间:当vector容量过大时,通过交换缩小内存占用。使用交换技巧可以立即释放未使用的内存(避免内存泄漏)。

    1.快速交换内容

            swap()函数最基本的功能,vector的内存交换(通过swap成员函数)是一个仅交换内部管理信息的轻量操作,其核心是通过交换两个vector的 "元数据"(而非元素本身)来实现内存转移。下面从vector的内部结构出发,详细拆解内存交换的完整过程。vector类似于顺序表,内部有一块连续内存块的地址和对应的size、capacity。

    // 逻辑上的vector内部结构(简化版)
    template <typename T>
    struct vector {
        T* data;       // 指向存储元素的内存缓冲区(堆上)
        size_t size;   // 当前元素数量
        size_t capacity;// 缓冲区容量(可容纳的最大元素数)
    };

            vector的swap成员函数的核心功能是:交换两个vector对象的data指针、sizecapacity这三个核心成员

    std::vector<int> v1 = { 1, 2, 3, 4, 5 };
    std::vector<int> v2 = { 2, 5, 2 };
    
    v1.swap(v2);
    
    std::cout << v1.size() << " " << v1.capacity() << std::endl; // 3 3
    std::cout << v2.size() << " " << v2.capacity() << std::endl; // 5 5

    2.释放内存

            当vector的capacity远大于size时(冗余内存),可通过与一个临时vector交换,让临时对象带走冗余内存并在销毁时释放。

    原理如下:

    1. 用当前vector的元素(size个)初始化一个临时vector(临时对象的capacity会等于size,因为它是新创建的,仅分配刚好够用的内存)
    2. 用swap交换当前vector和临时vector的内容 —— 此时当前vector会拥有临时对象的size和capacity(即capacity= size),而临时对象会拥有原来的冗余内存
    3. 临时对象在作用域结束时被销毁,自动释放其持有的冗余内存
    std::vector<int> v;
        
    // 插入1000个元素,触发扩容,capacity会大于等于1000
    for (int i = 0; i < 1000; ++i) {
        v.push_back(i);
    }
    std::cout << v.size() << ", " << v.capacity() << std::endl; // 1000 1066
    
        
    // 删除900个元素,size减小,但capacity不变
    v.erase(v.begin(), v.begin() + 900);
    std::cout << v.size() << ", " << v.capacity() << std::endl; // 100 1066
    
        
    // 用swap释放冗余内存
    std::vector<int>(v).swap(v);  // 匿名对象 关键操作
    std::cout << v.size() << ", " << v.capacity() << std::endl; // 100 100

            我们分析上述代码的运行过程,创建一个容器,不断向容器中添加新元素,容器的size和capacity也不短的扩充。通过erase删除900个元素,size减小至100个元素,capacity保持不变,因capacity远大于size,(size=100,capacity=1000)有大量内存冗余

            想要释放冗余内存可以借助内存交换,通过创建一个临时vector(借助拷贝构造,将原容器中的数据拷贝到临时vector中,同时新创建的vector满足capacity=size)。借助swap()函数,将临时vector与原容器进行内存交换,这时原容器中的数据保证不变,capacity缩小至size大小,同时临时对象也会随着该语句的结束,占用的内存会被释放。


    vector空间预留

            空间预留(Space Reservation)是一种优化技术,通过预先分配内存来避免频繁的内存重新分配(扩容),从而提高程序性能。在vector扩充机制部分,我们介绍了当size=capacity时,再添加元素会触发扩容。而每次扩容都会有大量的时间消耗,如果对一个容量小的容器持续的添加元素会频繁扩容,有大量时间消耗。比如如果对一个空vector添加100个元素,会频繁的触发扩容。例如capacity0到1,1到2,2到3,3到4,4到6.。。。

            若分配足够大的capacity的话,就不会触发size=capacity,也就不会频繁的扩容。即预留足够capacity大小后,添加元素不会触发重新分配,直到元素数量超过预留容量。空间预留主要借助于reserve()函数实现。如果预留的容量小于当前容量,reserve()可能无效;如果大于当前容量,则分配新内存。预留不会初始化元素:内存是“未使用”的,实际元素需通过bush_back或emplace_back添加。

    std::vector<int> v;
    for (int i = 0; i<100; ++i)
    {
        std::cout << v.capacity() << " " << v.size() << std::endl;
        v.push_back(i);
    }
    std::vector<int> v2;
    v2.reserve(100);
    for (int i = 0; i<100; ++i)
    {
        std::cout << v2.capacity() << " " << v2.size() << std::endl;
        v2.push_back(i);
    }

            通过reserve()方法预先分配内存,显著提升插入操作的效率(避免过多扩容触发)。它适用于需要高性能和可预测内存使用的场景。建议在代码中根据需求合理使用,以平衡内存开销和性能增益。


    vector高效删除

            在vector数据的插入和删除部分,我们介绍了erase函数,该函数可以实现指定索引进行删除,但是该删除方法时间复杂度为o(n),需要删除索引后的元素不断的覆盖前一元素。如果不考虑容器中元素的顺序,那么我们可以采用一种更为高效的删除方法:删除索引元素与尾部元素进行交换,使用pop_back()函数,删除交换后的索引元素。该方法的时间复杂度为o(1),但是会对vector中数据的顺序产生影响。

    void delVector(std::vector<int>& v, int index)
    {
        std::swap(v[index], v.back());
        v.pop_back();
    }
    void printVector(std::vector<int>& v)
    {
        for (int i = 0; i < v.size(); ++i)
            std::cout << v[i] << " ";
        std::cout << std::endl;
    }
    
    std::vector<int> v1 = { 1, 2, 3, 4, 5 };
    printVector(v1);        // 1 2 3 4 5
    
    delVector(v1, 1);
    printVector(v1);        // 1 5 3 4

    vecotr数据排序        

            vector中的数据进行排序主要借助algorithm头文件中的sort函数。sort函数是一个高效、通用的排序函数,能够对vector这类容器中的元素进行快速排序,且支持自定义排序方向,平均时间复杂度为 o (n log n)

            参数1、参数2为容器的其实迭代器,即排序的范围。参数3为可选参数,自定义比较函数,用于定义元素排序的顺序方向。具体实现如下,利用整数列表初始化一个容器,同时定义一个比较函数,该函数返回值为布尔类型,调用sort函数对该容器进行排序。

    void printVector(const std::vector<int>& v)
    {
    	for (const int& n : v)
    		std::cout << n << " ";
    	std::cout << std::endl;
    }
    bool cmp(int a, int b)
    {
    	return a < b;
    }
    
    std::vector<int> v = {12, 232, 34, 1, 75};
    
    printVector(v);
    sort(v.begin(), v.end(), cmp);
    printVector(v);

            我们分析一下sort函数的源码实现,具体每个类型不详细介绍。

    template <class _RanIt, class _Pr>
    _CONSTEXPR20 void _Sort_unchecked(_RanIt _First, _RanIt _Last, _Iter_diff_t<_RanIt> _Ideal, _Pr _Pred) {
        // order [_First, _Last)
        for (;;) {
            if (_Last - _First <= _ISORT_MAX) { // small
                _STD _Insertion_sort_unchecked(_First, _Last, _Pred);
                return;
            }
    
            if (_Ideal <= 0) { // heap sort if too many divisions
                _STD _Make_heap_unchecked(_First, _Last, _Pred);
                _STD _Sort_heap_unchecked(_First, _Last, _Pred);
                return;
            }
    
            // divide and conquer by quicksort
            auto _Mid = _STD _Partition_by_median_guess_unchecked(_First, _Last, _Pred);
    
            _Ideal = (_Ideal >> 1) + (_Ideal >> 2); // allow 1.5 log2(N) divisions
    
            if (_Mid.first - _First < _Last - _Mid.second) { // loop on second half
                _STD _Sort_unchecked(_First, _Mid.first, _Ideal, _Pred);
                _First = _Mid.second;
            } else { // loop on first half
                _STD _Sort_unchecked(_Mid.second, _Last, _Ideal, _Pred);
                _Last = _Mid.first;
            }
        }
    }

    _First_Last排序范围的起始和结束迭代器(左闭右开区间[_First, _Last)

    _Pred具体的比较函数(如之前写到的 bool cmp(int a, int b)函数,控制排序方向)。

    [_First, _Last)范围内的元素进行排序,内部根据数据规模自动选择最优排序算法。

    1.小规模数据:插入排序

    if (_Last - _First <= _ISORT_MAX) { // small
        _STD _Insertion_sort_unchecked(_First, _Last, _Pred);
        return;
    }

            当待排序元素数量_Last - _First)小于等于_ISORT_MAX(通常是一个小常数如 32)时,使用插入排序。插入排序的时间复杂度是O(n²),但在小规模数据(n较小时)上,其常数因子极小(内存访问局部性好,几乎无额外开销),实际性能优于快速排序(快速排序有递归和分割的额外开销)。

    2.递归过深:堆排序

    if (_Ideal <= 0) { // heap sort if too many divisions
        _STD _Make_heap_unchecked(_First, _Last, _Pred);
        _STD _Sort_heap_unchecked(_First, _Last, _Pred);
        return;
    }

            当_Ideal(递归深度阈值)减至 0 时,改用堆排序。快速排序在最坏情况下(如数据已排序、所有元素相等)会退化为O(n²)时间复杂度,且递归深度可能达到O(n)(导致栈溢出)。堆排序的时间复杂度稳定为o(n log n),且递归深度可控,此处作为 “安全兜底”。

    3.中等规模数据:快速排序

    // 1. 选择枢轴并分割
    auto _Mid = _STD _Partition_by_median_guess_unchecked(_First, _Last, _Pred);
    
    // 2. 调整递归深度阈值
    _Ideal = (_Ideal >> 1) + (_Ideal >> 2); // 等价于 _Ideal = _Ideal * 3/4
    
    // 3. 递归处理较小子范围,循环处理较大子范围
    if (_Mid.first - _First < _Last - _Mid.second) { 
        _STD _Sort_unchecked(_First, _Mid.first, _Ideal, _Pred);
        _First = _Mid.second; // 循环处理较大子范围
    } else { 
        _STD _Sort_unchecked(_Mid.second, _Last, _Ideal, _Pred);
        _Last = _Mid.first; // 循环处理较大子范围
    }

            对于容器元素数量中等规模采用快速排序,快速排序是一种基于分治法的排序算法,核心流程为包括选择枢轴(Pivot)、分割(Partition)、递归处理。平均时间复杂度:o (n log n),实际性能优于多数同复杂度算法。

            三种算法对于不同规模容器有不同的特点:

    1. 小数据用插入排序:利用插入排序在小规模数据上的常数优势。
    2. 中等数据用快速排序:利用快速排序的平均o(n log n)时间和良好的缓存友好性。
    3. 递归过深用堆排序:避免快速排序的最坏情况,保证稳定性。

    这种混合策略结合了三种算法的优点,使得sort排序在绝大多数场景下都能达到接近最优的性能(实际效率通常比单一算法高 20%-50%)。

    Logo

    码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

    更多推荐