代码说明
代码是我亲自码的,调试通过的,代码中有算法思想和详细的注释,一目了然。
项目已经上传到我的github:https://github.com/yisun03/sort
项目中还有另外得九种排序算法的c++实现代码以及其思想。
十种排序算法清代如下(附我的blog链接):
1 选择排序:https://blog.csdn.net/weixin_39408343/article/details/107063290
2 插入排序:https://blog.csdn.net/weixin_39408343/article/details/107070155
3 冒泡排序:https://blog.csdn.net/weixin_39408343/article/details/107070658
4 希尔排序:https://blog.csdn.net/weixin_39408343/article/details/107071758
5.1 归并排序递归实现:https://blog.csdn.net/weixin_39408343/article/details/107083607
5.2 归并排序非递归实现:https://blog.csdn.net/weixin_39408343/article/details/107084688
6.1 快速排序递归实现:https://blog.csdn.net/weixin_39408343/article/details/107086104
6.2 快速排序非递归实现:https://blog.csdn.net/weixin_39408343/article/details/107087359
7 堆排序:https://blog.csdn.net/weixin_39408343/article/details/107092851
8 计数排序:https://blog.csdn.net/weixin_39408343/article/details/107094547
9 桶排序:https://blog.csdn.net/weixin_39408343/article/details/107113821
10 基数排序:https://blog.csdn.net/weixin_39408343/article/details/107115403
术语说明
1、稳定排序:如果 a 原本在 b 的前面,且 a == b,排序之后 a 仍然在 b 的前面,则为稳定排序。
2、非稳定排序:如果 a 原本在 b 的前面,且 a == b,排序之后 a 可能不在 b 的前面,则为非稳定排序。
3、原地排序:原地排序指在排序过程中不申请多余的存储空间,只利用原来存储待排数据的存储空间进行比较和交换的数据排序。
4、非原地排序:需要利用额外的数组来辅助排序。
5、时间复杂度:一个算法执行所消耗的时间。
6、空间复杂度:运行完一个算法所需的内存大小。
性能分析
时间复杂度:时间复杂的稍微有些复杂,他的复杂度还取决于对桶内元素所使用的排序算法的选择,我们选择的是非递归的快排,
1,3需要遍历原始序列,我们设原始序列长度为n,则计算量为O(2*n),设桶个数为m,则加上遍历所有桶进行快排部 分总的时间复杂度为O(2*n + m + n(long(n/m))化简为:O(n+m+n(long(n)-long(m)),一般我们把时间复杂的记为
O(n+m)。
空间复杂度:O(n+m)
非稳定的非原地排序
void sort::sort_bucket(std::vector &data)
{
// 思想:
// 桶排序是计数排序的一个优化,它解决了计数排序只适用于整数排序的限制,更是解决了不适用于最大值和最小值差值很大的情况.
// 桶排序的思想就是对最小值和最小值之间的元素进行瓜分,将他们分为多个区间,每个区间用一个桶(其实就是一个容器)来装.
// 前一个桶里的元素全都小于后一个桶里的元素,只需要利用别的常规排序算法将桶里面的元素进行排序使之有序即可使得原序列有序.
// 这里我们使用快速排序对桶内的元素进行排序.
// 1.遍历待排序序列获取其中最大值和最小值,并计算他们的差值d.
int max = data.at(0);
int min = data.at(0);
for(int i = 1; i < static_cast(data.size()); i++)
{
if(max < data.at(i))
{
max = data.at(i);
}
if(min > data.at(i))
{
min= data.at(i);
}
}
int d = max - min;
// 2.初始化桶,桶因为要频繁插入元素,所以用List数据结构,然后所有的桶放在vector容器中.
std::vector> bucket_list;
// 我们将桶的个数设置为原序列元素个数.
int bucket_num = data.size();
bucket_list.resize(bucket_num);
// 3.遍历原序列,将元素放到合适的桶中.
for(int value : data)
{
// 定位元素所属的桶的索引.
// 桶所有的桶平均划分最大值和最小值d的区间,value-min是当前元素与最小值的差值(区间).
// bucket_num-1是总的区间个数,则d/(bucket_num-1)代表一个区间的长度.
// 那么整个表达式得到的index则为当前元素value所跨越的区间个数,也就是当前元素所在的桶的索引.
int index = (value-min)/(d/(bucket_num-1));
// 将当前元素放进桶里面去.
bucket_list.at(index).push_back(value);
}
// 4.对每个桶进行排序,我们采用快速排序.
// 依次将每个桶里的元素排好序后放入sorted_sequence中.
std::vector sorted_sequence;
for(auto bucket : bucket_list)
{
// 因为我们之前写的快排是对vector进行排序,所以我们使用一个辅助容器.
// 我们完全可以重新写一个针对list的快排算法,这样会提高时间和空间复杂度,此处我们就使用现成的.
std::vector auxiliary;
auxiliary.assign(bucket.begin(),bucket.end());
sort_quick_non_recursive(auxiliary,0, static_cast(auxiliary.size()-1));
// 将当前桶内元素排好序后放入sorted_sequence容器尾部.
sorted_sequence.insert(sorted_sequence.end(),auxiliary.begin(),auxiliary.end());
}
// 5.将有序序列赋给data.
data = sorted_sequence;
}