STL算法之排序

stl 算法库中提供的排序相关算法主要有以下几种,除了 q_sort 定义在 cstdlib 头文件中,其余都定义在 algorithm 头文件。

算法功能
sort排序
stable_sort稳定排序:保证等值情况时的原有顺序
partial_sort部分排序:选择(mid-first)个最小值按升序排列
partial_sort_copy对排序结果,部分拷贝
nth_element按指定nth元素,划分左右
is_sorted检测指定范围是否按指定排序方式排序
is_sorted_until返回第一个未按指定排序方式排序的元素迭代器
q_sortc语言库中提供的快速排序


以上排序算法默认按照升序排列,若需要降序排列,可以指定比较器comp为 greater<type>() ( #include < functional > ) 。对于 C/C++ 非内置类型,需要提供 仿函数lambda表达式 或者 友元比较函数


一、sort


函数原型:

template <class RandomAccessIterator>
  void sort (RandomAccessIterator first, RandomAccessIterator last);

template <class RandomAccessIterator, class Compare>
  void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp)
  • 默认以 升序 排列[ first , last ) 区间内的元素。只接受随机迭代器(5种迭代器中,继承层次最深)。

  • 第一个函数原型,将默认使用 operator < 进行比较。所以对于此种类型,自定义的类必须提供 友元 operator < 运算符重载函数 或者 类成员operator < 函数 或者 全局的operator < 运算符重载函数 ,但是后面两种方式,要求涉及比较的成员变量非private属性。对于内置类型,默认使用less<type>()仿函数(即按升序排列),若需要降序排列,指定比较器 greater<type>()

  • 第二个函数原型,使用comp比较函数(二元谓词函数,以两个元素为参数,返回一个可转换成bool类型的值),可以是仿函数、函数指针 和 lambda表达式。comp只有返回 false 时,才会导致两个参数交换位置。

  • 遵循严格弱序 —— strict weak order ( 让比较函数对相等的值返回 false )

  • 两个元素相等的情况下,并不保证保持他们的原有顺序。如果想保持原有顺序,请使用 stable_sort()。


1.1 内置类型 数组的排序

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

#define CLASSFOO_VECTOR(type, name, ...) \
static const type name##_a[] = __VA_ARGS__; \
std::vector<type> name(name##_a, name##_a + sizeof(name##_a) / sizeof(*name##_a))

namespace ClassFoo{
    bool IsGreater(int m, int n) { // 自定义的比较器comp , 普通函数
        return m > n;
    }
    struct _IsLess{
        bool operator()(int m, int n) {  // 仿函数
            return m < n;
        }
    }IsLess;

    void Sort_1() {
        CLASSFOO_VECTOR(int, BigVector1, { 8, 23, -5, 7, 29, 0, 7, 7, -7, 1, -1 });

        // 使用 operator <
        std::sort(
            std::begin(BigVector1),
            std::end(BigVector1)
            );  // 对于内置类型,原生支持 比较操作

        // 输出结果
        std::copy(
            BigVector1.begin(),
            BigVector1.end(),
            std::ostream_iterator<int>(std::cout, " "));
        std::cout << std::endl;

        // 使用 自定义函数
        std::sort(
            std::begin(BigVector1),
            std::end(BigVector1),
            IsGreater
            );

        // 输出结果
        std::copy(
            BigVector1.begin(),
            BigVector1.end(),
            std::ostream_iterator<int>(std::cout, " "));
        std::cout << std::endl;

        // 使用 函数对象(仿函数)
        std::sort(
            std::begin(BigVector1),
            std::end(BigVector1),
            IsLess
            );

        // 输出结果
        std::copy(
            BigVector1.begin(),
            BigVector1.end(),
            std::ostream_iterator<int>(std::cout, " "));
        std::cout << std::endl;
    }
}

int main()
{
    ClassFoo::Sort_1();
    return 0;
}


1.2 自定义类型 数组排序

#include <iostream>
#include <algorithm> //sort
#include <vector>
#include <iterator> //ostream_iterator 

using namespace std;

namespace ClassFoo{
    class Node{
    public:
        Node(int m, int n) : x(m), y(n) {}
        int x;
        int y;

        friend bool operator < (const Node&a,const Node&b)
        {  
           //对于自定义的类,如果采用第一种原型,必须定义一个友元仿函数(operator <)。
           //友元函数:是指某些虽然不是类的成员,却能够访问类的所有成员的函数。友元函数本身不属于类,但是可以访问类的私有成员。
          // cout << "<" <<endl;
            if (a.x == b.x)
                return a.y < b.y;

            return a.x < b.x;
        }

        friend bool operator > (const Node&a,const Node&b)
        {  
            cout << ">" <<endl;

            if (a.x == b.x)
                return a.y > b.y;

            return a.x > b.x;
        }

        friend std::ostream & operator<<(std::ostream& o,const Node& a) // 重载的 << 运算符
         {
            o << "(" << a.x << "," << a.y << ")";
            return o;
        }
    };

      //这种方式来重写输出函数也可以,但是只能访问Node的公有成员
    /* 
    ostream& operator << (ostream & out,const Node& a)
    {
        out << a.a;
        return out;
    }
    */

    // 此二元谓词函数 只能访问Node类的公有成员
    bool MyNodeLessFunc(Node& a, Node& b) {
        if (a.x == b.x) 
            return a.y < b.y;
        return a.x < b.x;
    }

    void Sort_2() {
        // 初始化对象数组
        std::vector<Node> NodeVector;
        NodeVector.push_back(Node(3, 7));
        NodeVector.push_back(Node(1, 9));
        NodeVector.push_back(Node(1, 3));
        NodeVector.push_back(Node(6, 3));
        NodeVector.push_back(Node(7, 2));
        NodeVector.push_back(Node(6, 2));

        // 排序
        std::sort(
            std::begin(NodeVector),
            std::end(NodeVector) 
            //,MyNodeLessFunc
            );

        // 输出
        copy(NodeVector.begin(),NodeVector.end(),std::ostream_iterator<Node>(std::cout," "));

        std::cout << std::endl;
    }
}

int main()
{
    ClassFoo::Sort_2();

    return 0;
}


1.3 比较函数定义为lambda表达式

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

namespace ClassFoo{
    class Node{
    public:
        Node(int m, int n) : x(m), y(n) {}
        int x;
        int y;
    };
    std::ostream& operator<<(std::ostream& o, Node& a) {
        o << "(" << a.x << "," << a.y << ")";
        return o;
    }

    void Sort_3() {
        // 初始化整数数组
        std::vector<int> BigVector = { 8, 23, -5, 7, 29, 0, 7, 7, -7, 1, -1 };
        // 初始化对象数组
        std::vector<Node> NodeVector = { {3, 7}, {1, 9}, {1, 3}, {6, 3}, {7, 2}, {6, 2} };

        // 排序整数数组
        // 按从大到小排序
        std::sort(
            BigVector.begin(),
            BigVector.end(),
            [](int m, int n) { return m > n; }
        );
        // 输出结果
        std::copy(
            BigVector.begin(),
            BigVector.end(),
            std::ostream_iterator<int>(std::cout, " "));
        std::cout << std::endl;

        // 排序对象数组
        std::sort(
            std::begin(NodeVector),
            std::end(NodeVector),
            [](Node& a, Node& b) {
                if (a.x == b.x)
                    return a.y < b.y;
                return a.x < b.x;
            }
        );
        // 输出
        for (std::vector<Node>::iterator it = NodeVector.begin();
            it != NodeVector.end(); ++it) {
            std::cout << *it << " ";
        }
        std::cout << std::endl;
    }
}
int main()
{
    ClassFoo::Sort_3();
    return 0;
}


二、stable_sort


函数原型:

void stable_sort ( RandomAccessIterator first, RandomAccessIterator last ); 

void stable_sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );
  • 稳定排序:等值元素的先后关系保持不变,而 std::sort 不能保证该点。

  • 其他基本使用方法,跟sort()一样。

示例可以参考上述代码。


三、partial_sort


函数原型:

void partial_sort (RandomAccessIterator first, RandomAccessIterator middle,
                     RandomAccessIterator last);
void partial_sort (RandomAccessIterator first, RandomAccessIterator middle,
                     RandomAccessIterator last, Compare comp);
  • 部分排序:默认从[first,last)中选择(middle - first)个最小的元素,并按升序排列。其余元素不排序。

  • 其余使用方法跟 sort() 类似。

示例4:

#include <iostream>     // std::cout
#include <algorithm>    // std::partial_sort
#include <vector>       // std::vector

bool myfunction (int i,int j) { return (i<j); }

int main () {
  int myints[] = {9,8,7,6,5,4,3,2,1};
  std::vector<int> myvector (myints, myints+9);

  // using default comparison (operator <):
  std::partial_sort (myvector.begin(), myvector.begin()+5, myvector.end());

  // using function as comp
  std::partial_sort (myvector.begin(), myvector.begin()+5, myvector.end(),myfunction);

  // print out content:
  std::cout << "myvector contains:";
  for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}


四、partial_sort_copy


函数原型:

inline _RandomAccessIterator
    partial_sort_copy(_InputIterator __first, _InputIterator __last,
              _RandomAccessIterator __result_first,
              _RandomAccessIterator __result_last)

inline _RandomAccessIterator
    partial_sort_copy(_InputIterator __first, _InputIterator __last,
              _RandomAccessIterator __result_first,
              _RandomAccessIterator __result_last,
              _Compare __comp)
  • 排序结果部分拷贝:对排序后的结果,部分拷贝到 [__result_first,__result_last)。将排序后的第一个元素复制到__result_first指定的位置,其后依次类推。默认按升序排列(除非指定排序方式comp)。

示例5:

#include <iostream>     // std::cout
#include <algorithm>    // std::partial_sort_copy
#include <vector>       // std::vector

bool myfunction (int i,int j) { return (i<j); }

int main () {
  int myints[] = {9,8,7,6,5,4,3,2,1};
  std::vector<int> myvector (5);

  // using default comparison (operator <):
  std::partial_sort_copy (myints, myints+9, myvector.begin(), myvector.end());

  // using function as comp
  std::partial_sort_copy (myints, myints+9, myvector.begin(), myvector.end(), myfunction);

  // print out content:
  std::cout << "myvector contains:";
  for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}


五、nth_element


函数原型:

template <class RandomAccessIterator>
  void nth_element (RandomAccessIterator first, RandomAccessIterator nth,
                    RandomAccessIterator last);

template <class RandomAccessIterator, class Compare>
  void nth_element (RandomAccessIterator first, RandomAccessIterator nth,
                    RandomAccessIterator last, Compare comp);
  • 对[first,last)中的元素重新排(非排序),使得nth左边的都是小于它的,nth右边的都是大于它的。注意:不排序,只是按照nth重新划分。

示例6:

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

#define CLASSFOO_VECTOR(type, name, ...) \
static const type name##_a[] = __VA_ARGS__; \
std::vector<type> name(name##_a, name##_a + sizeof(name##_a) / sizeof(*name##_a))

namespace ClassFoo{
    void NthElement_1() {
        CLASSFOO_VECTOR(int, BigVector1, { 8, 23, -5, 7, 29, 0, 5, 7, -7, 1, -1 });

        std::nth_element(
            std::begin(BigVector1),
            std::begin(BigVector1) + 6, // 按第 7 个元素(值为 5)划分
            std::end(BigVector1)
            );

        // 输出结果
        std::copy(
            BigVector1.begin(),
            BigVector1.end(),
            std::ostream_iterator<int>(std::cout, " "));
        std::cout << std::endl;
        //参考结果:0 -1 -5 -7 5 1 7 7 8 29 23
    }
}
int main()
{
    ClassFoo::NthElement_1();
    return 0;
}


六、is_sorted(c++11)


函数原型:

template <class ForwardIterator>
  bool is_sorted (ForwardIterator first, ForwardIterator last);

template <class ForwardIterator, class Compare>
  bool is_sorted (ForwardIterator first, ForwardIterator last, Compare comp);
  • 检测指定范围是否按照希望的排序方式排序(默认升序)。


七、is_sorted_until(c++11)


函数原型:

template <class ForwardIterator>
    ForwardIterator is_sorted_until (
        ForwardIterator first, 
        ForwardIterator last);

template <class ForwardIterator>
    ForwardIterator is_sorted_until (
        ForwardIterator first, 
        ForwardIterator last,
        Compare comp);
  • 检测指定范围是否按照希望的排序方式排序(默认升序),并且返回一个迭代器,其指向第一个不按给定顺序排序的元素。

示例7:

#include <iostream>     // std::cout
#include <algorithm>    // std::is_sorted_until, std::prev_permutation
#include <array>        // std::array

int main () {
  std::array<int,4> foo {2,4,1,3};
  std::array<int,4>::iterator it;

  do {
    // try a new permutation:
    std::prev_permutation(foo.begin(),foo.end());

    // print range:
    std::cout << "foo:";
    for (int& x:foo) 
        std::cout << ' ' << x;
    it=std::is_sorted_until(foo.begin(),foo.end());

    std::cout << " (" << (it-foo.begin()) << " elements sorted)\n";

  } while (it!=foo.end());

  std::cout << "the range is sorted!\n";

  return 0;
}


八、q_sort


函数原型:

void qsort (void* base, size_t num, size_t size,
            int (*compare)(const void* p1,const void* p2));
  • base : 指向被排序数组中第一个对象的指针,且被转换成 void*。
  • num : 数组中元素的个数。
  • size : 数组中各个元素的字节大小。
  • compare : 函数指针,其指向的函数用于比较两个元素。

    • 当返回值 < 0 时,表示 p1 指向的元素在 p2 指向的元素前面。
    • 当返回值为 0 时,表示 p1 指向的元素与 p2 指向的元素等价。
    • 当返回值 > 0 时,表示 p1 指向的元素在 p2 指向的元素后面。

示例8:

#include <iostream>
#include <cstdlib>

int MyIntCompare(const void* m, const void* n) {
    return (*(int*)m - *(int*)n);
}

void QSort_1() {
    int foo[] = { 8, 23, -5, 7, 29, 0, 7, 7, -7, 1, -1 };
    int count = sizeof(foo) / sizeof(foo[0]);
    std::qsort(
        foo,
        count,
        sizeof(foo[0]),
        MyIntCompare);
    for (int i = 0; i < count; i++){
        std::cout << foo[i] << " ";
    }
    std::cout << std::endl;
}
int main()
{
    QSort_1();
    return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值