1冒泡、2插入、3选择、4快排、5堆排、6归并、7希尔、8计数、9桶排、10基数。
是否稳定分析:https://www.cnblogs.com/codingmylife/archive/2012/10/21/2732980.html
//主要参考:以下两个博客总结
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(1)
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(n)
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;
}