下面是本人学习排序算法时的总结和笔记,如有纰漏请多多指正。
一、冒泡排序
冒泡排序时间复杂度O(n^2),额外空间复杂度O(1),是一种稳定的排序算法。
冒泡排序是最简单、最基本的排序算法之一。
冒泡排序通过交换相邻元素移动最小/最大的元素位置的一种排序算法。冒泡排序可以直接在原数组进行操作,只需要占用交换数据时使用的O(1)空间复杂度。
我们以数组arr[6]={7, 8, 1, 4, 3, 6}为例,研究冒泡排序的执行过程:
1. 从arr[0]遍历到arr[4],如果后面的数字比前面的数字小,两数交换位置,这样,最大的数8就会被挪动到数组的最后,即arr[5]的位置。遍历结束后,数组变为{7,1,4,3,6,8}
2.从arr[0]遍历到arr[3],如果后面的数字比前面的数字小,两数交换位置,这样,arr[0]到arr[4]五个数中最大的数就会被挪动到数组的倒数第二位,即arr[4]的位置。,数组变为{1,4,3,6,7,8}
3.重复以上步骤,最终我们会把最大的数放置在数组的最后一位,第二大的数字放置在数组的倒数第二位......最小的数字放置在第一位,排序结束。
代码实现如下:
#include<stdio.h>
int change(int* x,int* y){
int tmp=*x;
*x=*y;
*y=tmp;
}//交换两个元素
int main(){
int numsSize;//数组元素的个数
scanf("%d",&numsSize);
if(numsSize<=0) return 0x7fffffff;//不合法的输入,直接返回
int arr[numsSize];
for(int i=0;i<numsSize;i++){
scanf("%d",&arr[i]);
}
for(int i=numsSize-1;i>=0;i--){
for(int j=0;j<i;j++){
if(arr[j]>arr[j+1]) change(&arr[j],&arr[j+1]);
}
}
for(int i=0;i<numsSize;i++){
printf("%d ",arr[i]);
}
return 0;
}
我们可以看到代码中存在两层的循环嵌套,可以分析出花费的时间复杂度为O(n^2)
二、插入排序
插入排序平均的时间复杂度O(n^2),额外空间复杂度O(1),是一种稳定的排序算法。
插入排序也是一种比较简单的排序算法。它的核心思想就是插入,将无序部分逐一插入到有序部分中去。
我们以数组arr[6]={7, 8, 1, 4, 3, 6}为例,研究插入排序的执行过程:
单一元素必然有序。我们从arr[1]开始,向前插入,使得前两个元素保持有序。
第一轮插入结果为{7,8,1,4,3,6}
第二轮将arr[2]向前插入,显然,1应当被插入arr[0]的位置。数组变为{1,7,8,4,3,6}
第三轮将arr[3]向前插入,4应当被插入至arr[1]的位置,数组变为{1,4,7,8,3,6}
重复以上过程,直到遍历结束,数组有序。
代码实现:
#include<stdio.h>
int main(){
int numsSize;
scanf("%d",&numsSize);
if(numsSize<=0){
return 0x7fffffff;
}
int arr[numsSize];
for(int i=0;i<numsSize;i++)
{
scanf("%d",&arr[i]);
}
for(int i=1;i<numsSize;i++){
for(int j=i;j>0;j--){
if(arr[j]<arr[j-1]){
int temp=arr[j];
arr[j]=arr[j-1];
arr[j-1]=temp;
}
}
}
for(int i=0;i<numsSize;i++){
printf("%d ",arr[i]);
}
}
我们可以看到,代码中有两层的嵌套循环。当原数组完全有序时,内层循环不被执行,最好情况下时间复杂度为O(n),最坏情况下数组完全倒序(从大到小),每一个元素都要被挪动到数组的第一个位置,最坏时间复杂度为O(n^2)。
程序仅仅需要交换变量时花费的常数空间,额外空间复杂度为O(1)。
三、选择排序
选择排序一次可以消除多个逆序对,算法效率高,时间复杂度为O(n^2),额外空间复杂度为O(1)。选择排序不稳定。
选择排序的基本原理就是选择,也就是从整个数组里去挑一个最小的放在前面。
我们以数组arr[6]={7, 8, 1, 4, 3, 6}为例,研究选择排序的执行过程:
先遍历整个数组,挑出了最小的数1,让它与arr[0]互换,挪到第一个位置。第一趟排序结果为{1,8,7,4,3,6}
然后从arr[1]开始向后遍历数组,挑出了最小的数3,让它与arr[1]互换,结果为{1,3,7,4,8,6}
重复以上步骤,直到数组有序。
代码实现:
#include<stdio.h>
int main(){
int numsSize;
scanf("%d",&numsSize);
int arr[numsSize];
for(int i=0;i<numsSize;i++){
scanf("%d",&arr[i]);
}
for(int i=0;i<numsSize-1;i++){
int min=arr[i];
int address=i;
for(int j=i+1;j<numsSize;j++){
if(arr[j]<min){
min=arr[j];
address=j;
}
}
int tmp=arr[i];
arr[i]=arr[address];
arr[address]=tmp;
}
for(int i=0;i<numsSize;i++){
printf("%d ",arr[i]);
}
}
用到了两层循环,时间复杂度O(n^2),需要交换变量花费的O(1)空间复杂度。