以下算法均按数值从小到大的排序
1、冒泡排序(Bubble Sort)稳定的排序方法
算法原理:
比较相邻的元素。如果前面的数比后面的数大,就交换他们两个。对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这一轮比较结束后,最后的元素应该会是最大的数。针对所有的元素重复以上的步骤,除了最后一个。持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
时间复杂度:
最好的时间复杂度为O(n)
最坏的时间复杂度为O(n^2)
总的平均时间复杂度为O(n^2)
空间复杂度:
O(1)
void bubble_sort(int a[N]){
int i, j, temp;
for (j = 0; j < N - 1; j++)
for (i = 0; i < N - 1 - j; i++){ //i为比较的次数
if (a[i]>a[i + 1]){
temp = a[i];
a[i] = a[i + 1];
a[i + 1] = temp;
}
}
cout << "Bubble Sort:";
for (int i = 0; i < N; i++)
cout << a[i] << ",";
cout << endl;
}
2、选择排序(Selection sort)不稳定的排序方法
算法原理
设置数组中第一个元素为最小值,对比这个最小值和后面的其他数,如果后面的元素比当前最小值小则将此值作为当前的最小值,并用一个变量k来记住他的位置,接着比较,等到循环结束的时候,我们应该找到了最小的那个数的下标了,然后进行判断,如果这个元素的下标不是第一个元素的下标,就让第一个元素跟他交换一下值,这样就找到整个数组中最小的数了。然后找到数组中第二小的数,让他跟数组中第二个元素交换一下值,以此类推。
时间复杂度:
最好的时间复杂度为O(n^2)
最坏的时间复杂度为O(n^2)
总的平均时间复杂度为O(n^2)
空间复杂度:
O(1)
void selection_sort(int a[N]){
int min,j,k;
for (int i = 0; i < N ; i++){
min = a[i];
for (j = i+1; j < N;j++){
if (a[j] < min){
min = a[j];
k = j;
}
}
if (min != a[i]){
int temp;
temp = a[i];
a[i] = a[k];
a[k] = temp;
}
}
cout << "Selection Sort:";
for (int i = 0; i < N; i++)
cout << a[i] << ",";
cout << endl;
}
3、直接插入排序(Insertion Sort)稳定的排序算法
算法思想:
直接插入排序就是每一步都将一个待排数据按其大小插入到已经排序的数据中的适当位置,直到全部插入完毕。
时间复杂度:
最好的时间复杂度为O(n)
最坏的时间复杂度为O(n^2)
总的平均时间复杂度为O(n^2)
空间复杂度:
O(1)
void insertion_sort(int a[N]){
int temp,i,j;//temp存放取出的元素
for (i = 1; i < N; i++){ //i为未排序的索引
temp = a[i];
for (j = i - 1; j >= -1 ; j--){ //j为已排序的索引
if (a[j] > temp){
a[j+1] = a[j];
}
else{
a[j + 1] = temp;
break;
}
}
}
cout << "Insertion Sort:";
for (int i = 0; i < N; i++)
cout << a[i] << ",";
cout << endl;
}
4、归并排序(Merge Sort)
算法原理:
归并排序是一个分治算法。归并排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个有序的子序列,再把有序的子序列合并为整体有序序列。就是将已排好序的各个部分合并成一个有序的部分。
归并过程:
比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中。
时间复杂度:
最好的时间复杂度为O(n)
最坏的时间复杂度为O(n*logn)
总的平均时间复杂度为O(n*logn)
void merge_array(int a[N],int first,int mid,int last,int temp[]){
int i = first, j = mid + 1;
int m = mid, n = last;
int k = 0;
while (i <= m && j <= n){
if (a[i] <= a[j])
temp[k++] = a[i++];
else
temp[k++] = a[j++];
}
while (i <= m)
temp[k++] = a[i++];
while (j <= n)
temp[k++] = a[j++];
for (i = 0; i < k; i++)
a[first + i] = temp[i];
}
void merge_sort(int a[], int first, int last, int temp[]){
if (first < last){
int mid = (first + last) / 2;
merge_sort(a, first, mid, temp); //左边有序
merge_sort(a, mid + 1, last, temp); //右边有序
merge_array(a, first, mid, last, temp); //再将两个有序数列合并
}
}
5、快速排序(Quick Sort)不稳定的排序算法
主要思想:让坐标数前的数小于等于坐标数,坐标数后的元素大于或等于坐标数。
对于每一个未排序的部分,设置第一个未排序的元素为坐标数,从下一个元素开始依次向后,如果大于坐标数,位置不变,如果小于坐标数,将这个元素和第一个大于坐标数的元素互换,直到最后一个元素之后,将小于坐标数的最后一个元素和坐标数互换,坐标数的位置为序列的正确位置。一趟快速排序之后,将所有比它小的数都放到它前面,所有比它大的数都放到它后面。然后再按此方法对这两部分数据分别进行快速排序。
时间复杂度:
最好的时间复杂度为O(n*logn)
最坏的时间复杂度为O(n*logn)
总的平均时间复杂度为O(n^2)
空间复杂度:
最优:O(logn)
最差:O(n)
void quick_sort(int a[N], int left, int right){
if (left >= right){
return;
}
int i = left;
int j = right;
int key = a[left];
while (i < j){
while (i < j && key <= a[j])
j--;
a[i] = a[j];
while (i < j && key >= a[i])
i++;
a[j] = a[i];
}
a[i] = key;
quick_sort(a, left, i - 1);
quick_sort(a, i + 1, right);
}
总体的主函数如下
void main(){
int a[N] = {3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};
cout << "Original Sort:";
for (int i = 0; i < N; i++)
cout << a[i] << ",";
cout << endl;
//冒泡,选择,插入排序的调用
//bubble_sort(a);
//selection_sort(a);
//insertion_sort(a);
//归并排序的调用
//int p[N];
//merge_sort(a, 0, N - 1, p);
//cout << "Merge Sort:";
//for (int i = 0; i < N; i++)
//cout << a[i] << ",";
//cout << endl;
//快速排序的调用
quick_sort(a, 0, N-1);
cout << "Quick Sort:";
for (int i = 0; i < N; i++)
cout << a[i] << ",";
cout << endl;
}
上述算法的可视化演示在下面的网站上可以看到
https://zh.visualgo.net/sorting
还有基数排序,计数排序(桶排序,箱子排序),堆排序,希尔排序等等。后续还会继续更新哦。