数据结构与算法总结——常见排序算法

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)
  • 迭代器需要可以随机访问的
  • 需要保持稳定性需要调用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, 无需边间判断
    • 三项切分(处理重复元素情况)
  • 希尔排序

    • 增量数列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);
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值