常用的排序算法(一)

下面是本人学习排序算法时的总结和笔记,如有纰漏请多多指正。

一、冒泡排序 

冒泡排序时间复杂度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)空间复杂度。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值