C++_经典排序算法

1冒泡、2插入、3选择、4快排、5堆排、6归并、7希尔、8计数、9桶排、10基数。

//主要参考:以下两个博客总结
//https://blog.csdn.net/yushiyi6453/article/details/76407640
//https://blog.csdn.net/kellen_f/article/details/79029066
#include <iostream>
using namespace std;
template <class T>
void swap(T* num, int i, int j){
    T tmp;
    tmp = num[i];
    num[i] = num[j];
    num[j]= tmp;
}
//1.冒泡排序,时间复杂度O(n^2),空间复杂度O(1)
template <class T>
void BubbleSort(T *num, int size){
    if(size <= 1) return;
    for(int i = 0; i < size; i++){
        bool flag = false;
        for(int j = 0; j < size - i - 1; j++){
            if(num[j] > num[j+1]){
                swap(num, j, j+1);
                flag = true;
            }
        }
        if(!flag) return; //排好序则直接退出
    }
}
//2.插入排序,时间复杂度O(n^2),空间复杂度O(1)
template <class T>
void InsertSort(T *num, int size){
    if(size <= 1) return;
    for (int i = 1; i < size; i++){
        T tmp = num[i];
        int j;
        for(j = i - 1; j >= 0; j--){
            if(tmp < num[j]) num[j + 1] = num[j];
            else break;
        }
        num[j+1] = tmp;
    }
}
//3.简单选择排序,时间复杂度O(n^2),空间复杂度O(1)
template <class T>
void SelectSort(T *num, int size){
    if(size <= 1) return;
    for(int i = 0; i < size; i++){
        int min = num[i];
        int min_index = i;
        for (int j = i + 1; j < size; ++j) {
            if(num[j] < min){
                min = num[j];
                min_index = j;
                swap(num, min_index, i);
            }
        }
    }
}
//4.快排,时间复杂度O(nlogn),空间复杂度O(n)
//在数组中随机选一个数(默认数组首个元素),数组中小于等于此数的放在左边,
//大于此数的放在右边,再对数组两边递归调用快速排序,重复这个过程。
template <class T>
void QuickSort(T *num, int s, int t){
    if(t <= 0) return;
    T tmp = num[s];
    int i = s;
    int j = t;
    if (s >= t) return;
    while(i < j){
        while(i < j && num[j] > tmp) j--;
        num[i] = num[j];
        while(i < j && num[i] < tmp) i++;
        num[j] = num[i];
    }
    num[i] = tmp;
    QuickSort(num, s, i - 1);
    QuickSort(num, i + 1, t);
}

//5.堆排序,时间复杂度O(nlogn),空间复杂度O(nlogn)
template <class T>
void HeapAdjust(T *num, int i, int size){
    // 调整以形成大顶堆
    int child = 2 * i + 1;//左孩子节点下标
    while(child < size){
        if(child + 1 < size && num[child] < num[child + 1]) child++;//右孩子更大
        if(num[child] > num[i]){
            swap(num, child, i);
            i = child;
            child = 2 * i + 1;
        }
        else break;//满足根大于左右孩子,结束调整大顶堆
    }
}
template <class T>
void HeapSort(T* num, int size){
    if (size <=1 ) return;
    // 建立大顶堆
    for(int i = size / 2 - 1; i >= 0; --i){
        HeapAdjust(num, i, size);
    }
    // 取出堆顶,放到结尾,并重新调整堆
    for (int i = size - 1; i > 0; --i){
        swap(num, 0, i);
        HeapAdjust(num, 0, i); //第i个数据已经排序完成
    }
}
//6.归并排序,时间复杂度O(nlogn), 空间复杂度O(nlogn)
template <class T>
void Merge(T *num, int begin, int mid, int end){
    if(begin >= end) return;
    T* tmp = new T[end - begin + 1];
    int id1 = begin, id2 = mid + 1;
    //合并两段
    int i = 0;
    while(id1 <= mid && id2 <= end){
        if(num[id1] <= num[id2])
            tmp[i++] = num[id1++];
        else
            tmp[i++] = num[id2++];
    }
    // 继续合并
    while(id1 <= mid) tmp[i++] = num[id1++];
    while(id2 <= end) tmp[i++] = num[id2++];
    // 将临时数据写回
    for(int j = 0; j < end - begin + 1; j++)
        num[begin + j] = tmp[j];
    delete []tmp;
}

template<class T>
void MergeSortway(T *num, int begin, int end){
    if(begin < end){
        int mid = (begin + end) / 2;
        MergeSortway(num, begin, mid);
        MergeSortway(num, mid + 1, end);
        Merge(num, begin, mid, end);
    }
}
template<class T>
void MergeSort(T *num, int size){
    if (size <= 1) return;
    MergeSortway(num, 0, size - 1);
}
//7.希尔排序,时间复杂度O(nlogn),空间复杂度O(1)
template <class T>
void ShellSort(T *num, int size){
    // 简单插入排序的改进
    if(size <= 1) return;
    //增量div
    for(int div = size/2; div >= 1; div = div / 2){
        //分成div组
        for(int i = 0; i < div; ++i){
            // 对每组进行插入排序
            for(int j = i; j < size - div; j += div){
                for(int k = j; k < size; k += div){
                    if(num[j] > num[k]) swap(num, j, k);
                }
            }
        }
    }
}
//8.计数排序,时间复杂度O(n+k),k是整数的范围,空间复杂度O(n+k)
void CountSort(int num[], int size){
  /*- 找出待排序的数组中最大和最小的元素
    - 统计数组中每个值为i的元素出现的次数,存入数组C的第i项
    - 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
    - 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1
    */
    if(size <= 1) return;
    int min = num[0];
    int max = num[0];
    for(int i = 1; i < size; ++i){
        if (min > num[i]) min = num[i];
        if (max < num[i]) max = num[i];
    }
    int tmp_size = max - min + 1;
    int count_num[tmp_size];
    for(int i = 0; i < size; ++i){
        count_num[num[i] - min]++;
    }
    int index = 0;
    for(int i = 0; i < tmp_size; ++i){
        while(count_num[i]-- > 0){
            num[index++] = i + min;
        }
    }

}
//9. 桶排序,时间复杂度O(n),空间复杂度O(n)
//计数排序是简单而特殊的桶排序
/*
 桶排序将[0,1)区间划分为n个相同的大小的子区间,这些子区间被称为桶。
 然后将n个输入元素分别放入各自的桶中。因为输入时均匀独立的,所以一般不会有很多数同时落在一个桶中的情况。
 这样,我们想对各个桶中的数据进行排序,然后遍历每个桶,按照次序把各个桶中的元素列出来即可。
 */

//10.基数排序,时间复杂度O(n*digit),空间复杂度O(n),digit数字的位数
/*
 * 数排序又称为“桶子法”,从低位开始将待排序的数按照这一位的值放到相应的编号为0~9的桶中。
 * 等到低位排完得到一个子序列,再将这个序列按照次低位的大小进入相应的桶中,一直排到最高位为止,
 * 数组排序完成。
 */
int main(){
    int num[10] = {2, 5, 1, 3, 0, 7, 9, 8, 4, 6};
    CountSort(num, 10);
    for(int i = 0; i < 10; i++)
        cout<<num[i]<<" ";
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Gentlemanman/article/details/85162595
今日推荐