最近参加内推,四轮技术面里头有三轮都问到了排序(各种排序)。无奈表示我还没复习数据结构和算法部分.....今天正好有空,把几个被问到的排序算法都写出来比较下到底哪个更快,快多少。
需要注意的是:两路归并排序这个O(NlogN)时间复杂度的我没(Bu)写(Hui)。原因在快速排序里面已经展现了。其次,每次参与的数组均由随机函数生成。
先说结论:
1、快排名副其实的“快”,在不发生递归栈溢出的情况下速度惊人;
2、堆排序同学成绩稳定,在大数据量情况下,N^2的冒泡法同学哭晕在了厕所;
下面是截图:
1、测试数组长度为 1K的时候:
可以看到“快速排序”这个算法绝非浪得虚名啊 。当然,后面还有更猛的。
2、 测试数组长度为 5K的时候:

3、 测试数组长度为 10K的时候:

Oh,My God!!! 一直以速度著称的快排同学终于因为短跑改成了长跑体力不支倒(stack)下(over)了(flow)。那么我们看看剩下两名选手的成绩吧。嗯,堆排序同学耗时依然只有冒泡法一半不到。那么接下来这两名选手就要参加本次实验的终极挑战了!
终极挑战!!!
4、 测试数组长度为 50K的时候:

堆排序同学凭借稳定的发挥,一举夺魁。而 时间复杂度N^2的冒泡法同学耐力虽好,无奈速度实在不行,最后如龟爬一般的完成了比赛。最后用时是堆排序的2.94≈3倍。
最后的最后,翠花,上代码:
需要注意的是:两路归并排序这个O(NlogN)时间复杂度的我没(Bu)写(Hui)。原因在快速排序里面已经展现了。其次,每次参与的数组均由随机函数生成。
先说结论:
1、快排名副其实的“快”,在不发生递归栈溢出的情况下速度惊人;
2、堆排序同学成绩稳定,在大数据量情况下,N^2的冒泡法同学哭晕在了厕所;
下面是截图:
1、测试数组长度为 1K的时候:

可以看到“快速排序”这个算法绝非浪得虚名啊 。当然,后面还有更猛的。
2、 测试数组长度为 5K的时候:

3、 测试数组长度为 10K的时候:

Oh,My God!!! 一直以速度著称的快排同学终于因为短跑改成了长跑体力不支倒(stack)下(over)了(flow)。那么我们看看剩下两名选手的成绩吧。嗯,堆排序同学耗时依然只有冒泡法一半不到。那么接下来这两名选手就要参加本次实验的终极挑战了!
终极挑战!!!
4、 测试数组长度为 50K的时候:

堆排序同学凭借稳定的发挥,一举夺魁。而 时间复杂度N^2的冒泡法同学耐力虽好,无奈速度实在不行,最后如龟爬一般的完成了比赛。最后用时是堆排序的2.94≈3倍。
最后的最后,翠花,上代码:
/*
因为用了模板类。我用了一个mysortalgrithm.h单独存放这些排序算法
*/
#pragma once
#include <iostream>
#include <string>
template<typename T>
class MySortAlgrithm
{
public:
/*
冒泡法排序
*/
static void bubbleSort(T* a, size_t length)
{
int i = 0;
int j = length - 1;
for (j = length - 1; j>0; j--)//从最后一个数开始。J标记了已经排好序的数组部分,直到J==0;表明整个数组都已经排序完毕了
for (i = 0; i < j; i++)//从第一个数开始。I标记了被考察的数
{
if (a[i]>a[i + 1])
{
mySwap(a[i], a[i + 1]);
}
}
}
/*
小根堆排序
*/
static void minHeapSort(T* a, size_t length)
{
int tempLength = length;
for (int i = 0; i < tempLength; i++)
{
minHeapify(a, length - i);
//将最小值放进数组中已经排序的部分
mySwap(a[0],a[length-i-1]);
}
}
/*
快速排序的调用接口
*/
static void fastSort(T*a, size_t length)
{
subFastSort(a,0,length-1);
}
private:
/*
真正的快速排序,被包装在一个fastSort(T* a, size_t length)中
*/
static void subFastSort(T* a, int from, int to)
{
if (to < from)
return;
int i = from;
int j = to;
T temp = a[from];
while (i < j)
{
//最开始从右侧向左查找第一个
while ( i < j && a[j]>=temp)
j -= 1;
//注意,这个i<j判断很重要
if (i < j)
{
a[i] = a[j];//将小于temp的值移动到temp的左边
i += 1;
}
while (i < j && a[i]< temp)
i += 1;
if (i < j)
{
a[j] = a[i];//将大于temp的值移动到temp的右边
j -= 1;
}
}
a[i] = temp;
subFastSort(a,from,i-1);
subFastSort(a,i+1,to);
}
/*
将数组调整为小根堆
a:被调整的数组(乱序堆)
length:数组长度(堆大小)
startPos:从哪个位置开始调整堆
*/
static void minHeapify(T* a,size_t length)
{
//-----------------------------------------------------------------
//--前方高能预警:堆调整的时候必须从“叶节点”开始"向上"调整!!!---
//-----------------------------------------------------------------
for (int i = length-1; i >=0 ; i--)
{
size_t lChild = i * 2 + 1;
size_t rChild = i * 2 + 2;
//如果没有左子树,自然就没有没有右子树,那就不用检查这个点是否满足堆的性质了
if (lChild > length-1)
continue;
size_t lessPos;//左右子树中较小的那个数
//如果左子树存在,但右子树不存在
if (lChild <= length - 1 && rChild > length - 1)
lessPos = lChild;
//如果这个点比它的左右子树中较小的那个大,就互换
else if (lChild <= length - 1 && rChild <= length - 1)
lessPos= a[lChild] > a[rChild] ? rChild : lChild;
if (a[i]>a[lessPos])
mySwap(a[i],a[lessPos]);
}
}
/*
交换两个数
*/
static void mySwap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
};
/*
---------------------------------------主函数-----------------------------------------
*/
#pragma once
#include <iostream>
#include <string>
#include <ctime>
#include "MySortAlgrithm.h"
using namespace std;
#define ARRAY_LENGTH 5000
int main()
{
int a[ARRAY_LENGTH];
for (int i = 0; i < ARRAY_LENGTH; i++)
{
a[i] = rand()%100;
}
int length = end(a) - begin(a);
clock_t start_time = clock();
{
MySortAlgrithm<int>::bubbleSort(a,length);
}
clock_t end_time = clock();
std::cout << "冒泡法耗时: " <<static_cast<double>(end_time - start_time) / CLOCKS_PER_SEC * 1000 << "ms" << endl;//输出运行时间
clock_t start_time2 = clock();
{
MySortAlgrithm<int>::minHeapSort(a, length);
}
clock_t end_time2 = clock();
std::cout << "堆排序耗时: " <<static_cast<double>(end_time2 - start_time2) / CLOCKS_PER_SEC * 1000 << "ms" << endl;//输出运行时间
clock_t start_time3 = clock();
{
MySortAlgrithm<int>::fastSort(a, length);
}
clock_t end_time3 = clock();
std::cout << "快排耗时: " <<static_cast<double>(end_time3 - start_time3) / CLOCKS_PER_SEC * 1000 << "ms" << endl;//输出运行时间
return 0;
}
收工~