STL中的排序算法
原型:
template< typename RandomIt>
void sort( RandomIt first, RandomIt last);
template< typename RandomIt, typename Compare>
void sort( RandomIt first, RandomIt last, Compare comp);
- 包含在
<algorithm>
头文件中 - 非内置类型需要自己传入比较函数
- 相等时比较函数应该返回false
- 在partition函数中,这样做虽然会导致不必要的交换,但是避免了切分后左右数据大小差异过大(这会使得复杂度在遇到很多重复数据时接近n^2)
- 相等时比较函数应该返回false
- 迭代器需要可以随机访问的
- 需要保持稳定性需要调用stable_sort
- 一般是使用快速排序,小于某个阈值(5~20)切换到插入排序;有时会使用堆排序
- 快排比较较多,归并移动多。JAVA中比较开销大,故对于非原始类型默认使用归并;C++11前移动(复制)开销大,故默认使用快排
相关知识点
-
排序相关
- 一般来说快速排序和归并排序是最快的,但是归并排序会使用额外的内存
- 希尔排序的复杂度和选择的递增数列有关,现在最快的复杂度是n^4/3
- 当待处理的数据规模变得较小时,采用插入排序比较快
- 堆排序由于不符合局部性原则,cache命中率低于快排,所以时间一般比快排慢
- 插入算法由于前面的数据都是排序好的,可以采用折半插入的方法(类似二分查找)
-
C++相关
- 尽量使用vector代替数组
- 尽量使用std::move代替传值
- ++i 比 i++ 更高效,后者需要复制出一个临时副本来完成当前操作
- comparator(比较器),当数据类型本身不支持比较(如自定义类),而你又不想改变这个数据类型本身,于是需要从外部传入一个比较类。为了简化书写,我们使用比较类的operator()函数来实现比较,具体可见main函数
- 当for循环是递减的而且终止条件涉及0的时候,最好循环变量用int而不是size_t,因为可能出现负值
本文包含的排序算法
-
冒泡排序
-
插入排序
-
选择排序
-
归并排序
- 递归版和非递归版
-
快速排序
- 三取样切分(选取partition)
- 选取arr[low], arr[mid],arr[high],将中间值设为par
- 此时arr[low] <= par. arr[high] >= par, 无需边间判断
- 三项切分(处理重复元素情况)
- 三取样切分(选取partition)
-
希尔排序
- 增量数列h必须满足的条件是h1 = 1
-
堆排序
-
排序稳定性
- 稳定算法
- 冒泡,插入,归并
- 不稳定算法
- 快速,堆,希尔,选择
- 稳定算法
-
数据敏感度
- 数据敏感度是指排序快慢是否和数据数据性质有关
- 数据敏感算法
- 冒泡,插入,快排
- 数据不敏感
- 选择,堆,归并
//main.cpp
#include <iostream>
#include <string>
#include "BST.cpp"
#include "sort.cpp"
using namespace std;
class Obj
{
public:
Obj() :
s("0") {}
Obj(string && str) :
s(str) {}
string s;
};
//比较类
class Cmp
{
public:
int operator() (const Obj & a, const Obj & b) //具体比较方法可以自定义
{
if (a.s.at(0) < b.s.at(0))
return 1;
else
return 0;
}
};
int main(int argc, char* argcv[])
{
vector<Obj> arr = { Obj("a"), Obj("c"), Obj("b"), Obj("h"), Obj("j"), Obj("e"), Obj("d")};
Sort<Obj, Cmp> sort;
sort.merge(arr);//可替代为别的算法
for (Obj x : arr)
cout << x.s << endl;
return 0;
}
//sort.h
#ifndef SORT_H
#define SORT_H
#include <iostream>
#include <functional>
#include <vector>
#include <cmath>
using namespace std;
template <typename Object, typename Comparator = less<Object>>//默认为调用<functional>中的less比较函数
class Sort
{
public:
void bubble(vector<Object> & arr);
void insert(vector<Object> & arr);
void select(vector<Object> & arr);
void merge(vector<Object> & arr);
void mergeWithoutRecursive(vector<Object> & arr);
void quick(vector<Object> & arr);
void shell(vector<Object> & arr);
void heap(vector<Object> & arr);
void radix(vector<Object> & arr);
private:
Comparator lessThan;
void swap(Object & a, Object & b);
void merge(vector<Object> & arr,size_t low, size_t high, vector<Object> & tempArr);
void mergeHelper(vector<Object> & arr, size_t low, size_t mid, size_t high, vector<Object> & tempArr);
void quick(vector<Object> & arr, int low, int high);
void quickWithDuplication(vector<Object> & arr, int low, int high);
int partition(vector<Object> & arr, int low, int high);
int midThreePartition(vector<Object> & arr, int low, int high);
void sink(vector<Object> & arr, int pos, int N);
};
#endif // !SORT_H
//sort.cpp
#include "sort.h"
//升序排列
template <typename Object, typename Comparator>
void Sort<Object, Comparator>::bubble(vector<Object> & arr)
{
for (size_t i = arr.size() - 1; i > 0 ; --i)
for (size_t j = 0; j < i; ++j)
if (lessThan(arr.at(j + 1), arr.at(j)))
swap(arr.at(j + 1), arr.at(j));
}
template <typename Object, typename Comparator>
void Sort<Object, Comparator>::insert(vector<Object> & arr)
{
for (size_t i = 1; i < arr.size(); ++i)//i应该初始化为size_t,因为arr.size()返回值是无符号的
{
auto temp = std::move(arr.at(i));
size_t j = i;// j不要初始化为i - 1,否则第24行必须是 j+1
for (; j >= 1 && lessThan(temp, arr.at(j - 1)); --j)//可以将判断条件移至循环头
arr.at(j) = std::move(arr.at(j - 1));
arr.at(j) = std::move(temp);
}
}
template <typename Object, typename Comparator>
void Sort<Object, Comparator>::select(vector<Object> & arr)
{
for (size_t i = 0; i < arr.size() - 1; ++i)
{
auto offset = i;
for (size_t j = i + 1; j < arr.size(); ++j)
{
if (lessThan(arr.at(j), arr.at(offset)))
offset = j;
}
swap(arr.at(i), arr.at(offset));
}
}
//递归版归并排序
template <typename Object, typename Comparator>
void Sort<Object, Comparator>::merge(vector<Object> & arr)
{
vector<Object> tempArr(arr.size());
merge(arr, 0, arr.size() - 1, tempArr);
}
//非递归版归并排序
template <typename Object, typename Comparator>
void Sort<Object, Comparator>::mergeWithoutRecursive(vector<Object> & arr)
{
size_t N = arr.size();
vector<Object> tempArr(N);
for (size_t size = 1; size < N; size *= 2)
for (size_t low = 0; low < N - size; low += 2 * size)
{
size_t high = (low + size + size - 1 > N - 1) ? N - 1 : low + size + size - 1;
mergeHelper(arr, low, low + size - 1, high, tempArr);
}
}
template <typename Object, typename Comparator>
void Sort<Object, Comparator>::quick(vector<Object> & arr)
{
quickWithDuplication(arr, 0, arr.size() - 1);
}
template <typename Object, typename Comparator>
void Sort<Object, Comparator>::shell(vector<Object> & arr)
{
size_t len = arr.size();
size_t N = len / 2;
while (N > 0)
{
for (size_t i = N; i < len; ++i)
{
auto temp = std::move(arr.at(i));
size_t j = i;
for (; j >= N; j -= N)
{
if (lessThan(temp, arr.at(j - N)))
arr.at(j) = std::move(arr.at(j - N));
else
break;
}
arr.at(j) = std::move(temp);
}
N /= 2;
}
}
template <typename Object, typename Comparator>
void Sort<Object, Comparator>::heap(vector<Object> & arr)
{
//构造堆
int N = arr.size() - 1;
for (int k = (N - 1) / 2; k >= 0; --k) //涉及减法的循环最好还是用int型循环变量
sink(arr, k, N);
//依次将最大数放到最后
while (N > 0)
{
swap(arr.at(0), arr.at(N--));
sink(arr, 0, N);
}
}
/*
private
*/
template <typename Object, typename Comparator>
void Sort<Object, Comparator>::sink(vector<Object> & arr, int pos, int N)
{
while ((2 * pos + 1) <= N) //一般的堆是从1开始计数的,这里从0开始,所以不是通常的2*pos
{
int j = 2 * pos + 1;
if (j < N && lessThan(arr.at(j), arr.at(j + 1))) //挑更大的交换上去
++j;
if (lessThan(arr.at(pos), arr.at(j)))
swap(arr.at(pos), arr.at(j));
else
break;
pos = j;
}
}
template <typename Object, typename Comparator>
void Sort<Object, Comparator>::quick(vector<Object> & arr, int low, int high)
{
if (low >= high)
return;
int position = midThreePartition(arr, low, high);
quick(arr, low, position - 1);
quick(arr, position + 1, high);
}
template <typename Object, typename Comparator>
void Sort<Object, Comparator>::quickWithDuplication(vector<Object> & arr, int low, int high)
{
if (low >= high)
return;
int lt = low, i = lt + 1, gt = high;
auto par = arr.at(low);
while (i <= gt)
{
if (lessThan(arr.at(i), par))
swap(arr.at(i++), arr.at(lt++));
else if (lessThan(par, arr.at(i)))
swap(arr.at(i), arr.at(gt--));
else
i++;
}
quickWithDuplication(arr, low, lt - 1);
quickWithDuplication(arr, gt + 1, high);
}
template <typename Object, typename Comparator>
int Sort<Object, Comparator>::partition(vector<Object> & arr, int low, int high)
{
int shuffle = low + rand() % (high - low + 1);
swap(arr.at(low), arr.at(shuffle));
auto par = arr.at(low);
int i = low, j = high + 1;
while (true)
{
while (lessThan(arr.at(++i), par))
if (i == high) //由于切分元素可能是最大值,所以不可忽略这一步
break;
while (lessThan(par, arr.at(--j)))
if (j == low)
break;
if (i >= j) //应该在这里判断,而不是while循环头
break;
swap(arr.at(i), arr.at(j));
}
swap(arr.at(low), arr.at(j));
return j;
}
template <typename Object, typename Comparator>
int Sort<Object, Comparator>::midThreePartition(vector<Object> & arr, int low, int high)
{
int mid = (low + high) / 2;
if (lessThan(arr.at(mid), arr.at(low)))
swap(arr.at(mid), arr.at(low));
if (lessThan(arr.at(high), arr.at(low)))
swap(arr.at(high), arr.at(low));
if (lessThan(arr.at(high), arr.at(mid)))
swap(arr.at(high), arr.at(mid));
swap(arr.at(high - 1), arr.at(mid));
//由于mid是向下取整的,所以只能把par放在右边而不是左边,否则在low与high相邻的时候会下标越界
int i = low, j = high - 1;
auto par = arr.at(high - 1);
while (true)
{
while (lessThan(arr.at(++i), par))
;
while (lessThan(par, arr.at(--j)))
;
if (i >= j)
break;
swap(arr.at(i), arr.at(j));
}
swap(arr.at(i), arr.at(high - 1));
return i;
}
template <typename Object, typename Comparator>
void Sort<Object, Comparator>::merge(vector<Object> & arr, size_t low, size_t high, vector<Object> & tempArr)
{
if (low >= high)
return;
size_t mid = (low + high) / 2;
merge(arr, low, mid, tempArr);
merge(arr, mid + 1, high, tempArr);
mergeHelper(arr, low, mid, high, tempArr);
}
template <typename Object, typename Comparator>
void Sort<Object, Comparator>::mergeHelper(vector<Object> & arr, size_t low, size_t mid, size_t high, vector<Object> & tempArr)
{
size_t i = low, j = mid + 1;
for (size_t k = low; k <= high; ++k)
{
if (i > mid)
tempArr.at(k) = std::move(arr.at(j++));
else if (j > high)
tempArr.at(k) = std::move(arr.at(i++));
else if (lessThan(arr.at(i), arr.at(j)))
tempArr.at(k) = std::move(arr.at(i++));
else
tempArr.at(k) = std::move(arr.at(j++));
}
for (size_t p = low; p <= high; p++)
arr.at(p) = std::move(tempArr.at(p));
}
template <typename Object, typename Comparator>
inline void Sort<Object, Comparator>::swap(Object & a, Object & b)
{
auto temp = std::move(b);
b = std::move(a);
a = std::move(temp);
}