代碼說明
代碼是我親自碼的,調試通過的,代碼中有算法思想和詳細的註釋,一目瞭然。
項目已經上傳到我的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<int> &data)
{
// 思想:
// 桶排序是計數排序的一個優化,它解決了計數排序只適用於整數排序的限制,更是解決了不適用於最大值和最小值差值很大的情況.
// 桶排序的思想就是對最小值和最小值之間的元素進行瓜分,將他們分爲多個區間,每個區間用一個桶(其實就是一個容器)來裝.
// 前一個桶裏的元素全都小於後一個桶裏的元素,只需要利用別的常規排序算法將桶裏面的元素進行排序使之有序即可使得原序列有序.
// 這裏我們使用快速排序對桶內的元素進行排序.
// 1.遍歷待排序序列獲取其中最大值和最小值,並計算他們的差值d.
int max = data.at(0);
int min = data.at(0);
for(int i = 1; i < static_cast<int>(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<std::list<int>> 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<int> sorted_sequence;
for(auto bucket : bucket_list)
{
// 因爲我們之前寫的快排是對vector<int>進行排序,所以我們使用一個輔助容器.
// 我們完全可以重新寫一個針對list<int>的快排算法,這樣會提高時間和空間複雜度,此處我們就使用現成的.
std::vector<int> auxiliary;
auxiliary.assign(bucket.begin(),bucket.end());
sort_quick_non_recursive(auxiliary,0, static_cast<int>(auxiliary.size()-1));
// 將當前桶內元素排好序後放入sorted_sequence容器尾部.
sorted_sequence.insert(sorted_sequence.end(),auxiliary.begin(),auxiliary.end());
}
// 5.將有序序列賦給data.
data = sorted_sequence;
}