堆排序
计数排序
桶排序
基数排序
总结
排序算法 | 平均时间复杂度 | 最好情况 | 最坏情况 | 空间复杂度 | 稳定性 |
---|---|---|---|---|---|
冒泡排序 | 稳定 | ||||
插入排序 | 稳定 | ||||
希尔排序 | 不稳定 | ||||
选择排序 | 不稳定 |
一、冒泡排序(Bubble Sort)
1.算法描述
平均时间复杂度:
空间复杂度:
- 从前向后依次检查每一对相邻元素,一旦发现逆序(前面一个元素大于后面)即交换二者的位置;
- 完成一趟扫描之后,最大元素抵达应处的位置;
- 对余下的元素重复上述步骤。
2.动图
3.实现
void bubbleSort(int arr[], int n)
{
for (int i = 0; i < n - 1; i++) //外循环为排序趟数,n个数进行n-1趟
{
bool sorted = true; //整体有序标志
for (int j = 0; j < n - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
sorted = false;
}
}
if (sorted) // 一旦经过某趟扫描之后未发现任何逆序的相邻元素,意味着排序任务完成。
break; // 算法终止
}
}
二、插入排序(Insertion Sort)
1.算法描述
平均时间复杂度:
空间复杂度:
- 整个序列包括有序的前缀和无序的后缀
- 反复的将后缀的首元素移至前缀中
2.动图
3.实现
void insertionSort(int arr[], int n)
{
for (int i = 1; i < n; i++)
{
for (int j = i; j > 0; j--) //有序前缀[0, i)
{
// 后序的首元素arr[i] 找到合适的插入位置
if (arr[j] < arr[j - 1])
{
int temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
else
break;
}
// 内存for结束后 有序前缀范围扩大至[0, i]
}
}
三、希尔排序(Shell Sort)
1.算法描述
平均时间复杂度:
空间复杂度:
取一个递增的增量序列:
(--)
{
使用增量的一趟排序之后,间隔为的元素都被排序了
}
2.动图
3.实现
增量序列设计与选择的方法有很多,这里选择
void shellSort(int arr[], int n)
{
int increment = n / 2; //增量
while (increment >= 1)
{
for (int i = increment; i < n; i++)
{
for (int j = i - increment; j >= 0; j -= increment)
{
// 将 a[i] 插入到分组正确的位置
// 这里并不是处理完一个增量序列再处理另一个的
// 是按照数组循序处理的 arr[0] arr[1] ……
/*
j = i - increment;
i = j + increment;
*/
if (arr[j] > arr[j + increment])
{
int temp = arr[j];
arr[j] = arr[j + increment];
arr[j + increment] = temp;
}
}
}
increment /= 2;
}
}
四、选择排序(Selection Sort)
1.算法描述
平均时间复杂度:
空间复杂度:
- 分为有序前缀 和无序后缀
- 并且前缀的值不大于后缀
- 每次从后缀中选出最小者,并作为最大元素移入前缀中
2.动图
3.实现
void selectSort(int arr[], int n)
{
for (int i = 0; i< n - 1; i++)
{
//有序前缀[0, i)
int index = i;
for (int j = i + 1; j < n; j++)
if (arr[j] < arr[index]) //寻找无序区内的最小值
index = j;
if (index != i) //将其移至有序区末尾
{
int tmp = arr[index];
arr[index] = arr[i];
arr[i] = tmp;
}
//一轮外循环后,有序前缀[0, i]
}
}
五、快速排序(Quick Sort)
1.算法描述
平均时间复杂度:
空间复杂度:
int Partation(int arr[], int lo, int hi)
{
int pivot = arr[lo];
while (lo < hi)
{
while ((lo < hi) && (pivot <= arr[hi]))
hi--;
arr[lo] = arr[hi];
while ((lo < hi) && (arr[lo] <= pivot))
lo++;
arr[hi] = arr[lo];
}
arr[lo] = pivot;
return lo;
}
void quickSort(int arr[], int lo, int hi)
{
if (lo < hi)
{
int mi = Partation(arr, lo, hi);
quickSort(arr, lo, mi - 1);
quickSort(arr, mi + 1, hi);
}
}
六、归并排序(Merge Sort)
void merge(int arr[], int lo, int mi, int hi, int temp[])
{
int i = lo; // [lo, mi] [mi + 1, hi]
int j = mi + 1;
int t = 0;
while ((i <= mi) && (j <= hi))
{
if (arr[i] <= arr[j])
temp[t++] = arr[i++];
else
temp[t++] = arr[j++];
}
while(i <= mi)
temp[t++] = arr[i++];
while(j <= hi)
temp[t++] = arr[j++];
t = 0;
while (lo <= hi)
{
arr[lo++] = temp[t++];
}
}
void mergeSort(int arr[], int lo, int hi, int temp[])
{
if (lo < hi)
{
int mi = lo + (hi - lo) / 2;
mergeSort(arr, lo, mi, temp);
mergeSort(arr, mi + 1, hi, temp);
merge(arr, lo, mi, hi, temp);
}
}
七、桶排序(Bucket Sort)
void bucketSort(vector<int>& vec)
{
int length=vec.size();
vector<int> buckets(length,0);//准备一堆桶,容器的下标即待排序数组的键值或键值经过转化后的值
//此时每个桶中都是没有放值的,所以都是0
for(int i=0;i<length;++i)
{
buckets[vec[i]]++;//把每个值放入到对应的桶中
}
int index=0;
for(int i=0;i<length;++i)
{//把值取出,空桶则直接跳过
for(int j=0;j<buckets[i];j++)
{
vec[index++]=i;
}
}
}