常见七大排序算法

常见七大排序算法

一、简单排序

1.选择排序
1.1 选择排序思想

​ 将数组中第一个数与后面的所有数进行比较,若大则交换,直到选出小的数放在第一个位置,依次往后循环。

1.2 时间复杂度

​ 选择排序的时间复杂度为O(n^2)。

1.3 选择排序代码
//选择排序
public static int[] selectSort(int[] arr){
    int temp;
    for (int i=0;i<arr.length-1;i++){
        for (int j=i;j<arr.length;j++){
            if (arr[i]>arr[j]){
                swap(arr,i,j);
            }
        }
    }
    return arr;
}

//交换方法(使用异或的方式,推荐使用)
public static void swap(int[] arr,int i,int j){
    arr[i]=arr[i]^arr[j];
    arr[j]=arr[i]^arr[j];
    arr[i]=arr[i]^arr[j];
}

//交换方法(普通方法)
public static void swap(int[] arr,int i,int j){
    int temp;
    temp=a[i];
    a[i]=a[j];
    a[j]=temp;
}
2.冒泡排序
2.1 冒泡排序思想

​ 将相邻的两个数进行比较,按照大的拍后面的规则,一直将大的拍到最后一个,接下来继续按照这个规则拍前N-1的数组。

2.2 时间复杂度

​ 冒泡排序的时间复杂度为O(n^2)。

2.2 冒泡排序代码
//冒泡排序代码
public static int[] bubbleSort(int[] arr){
    int temp;
    for (int i=arr.length-1;i>=0;i--){
        for (int j=0;j<i;j++){
            if (arr[j]>arr[j+1]){
                swap(arr,j,j+1);
            }
        }
    }
    return arr;
}

//交换方法(使用异或的方式,推荐使用)
public static void swap(int[] arr,int i,int j){
    arr[i]=arr[i]^arr[j];
    arr[j]=arr[i]^arr[j];
    arr[i]=arr[i]^arr[j];
}

//交换方法(普通方法)
public static void swap(int[] arr,int i,int j){
    int temp;
    temp=a[i];
    a[i]=a[j];
    a[j]=temp;
}
3.插入排序
3.1 插入排序思想

​ 当下标为0时,0之前没有数据不做排序;下标为1时,将下标为1的数据和前面所有的数据进行排序;下标为2时,将下标为2的数据和前面所有的数据进行排序…

​ 其实就是第一个for控制第二个for的长度,第二个for实际就是冒泡
在这里插入图片描述

3.2 时间复杂度

​ 插入排序的时间复杂度为O(n^2)。

3.3 插入排序代码
//插入排序
public static int[] insertSort(int[] arr){
    for (int i=1;i<arr.length;i++){
        for (int j=i;j>=0;j--){
            if (arr[j]<arr[j-1]){
                swap(arr,j,j-1);
            }else {
                break;
            }
        }
    }
    return arr;
}

//交换方法(使用异或的方式,推荐使用)
public static void swap(int[] arr,int i,int j){
    arr[i]=arr[i]^arr[j];
    arr[j]=arr[i]^arr[j];
    arr[i]=arr[i]^arr[j];
}
4.希尔排序
4.1 希尔排序思想

​ 先将整个待排记录分割成若干个子序列,分别进行直接插入排序,待整个序列的记录”基本有序“的时候,再对全体记录进行一次直接插入排序

4.2 时间复杂度

​ 希尔排序的时间复杂度为O(nlogn)。

4.3 希尔排序代码
//希尔排序
public static int[] shellSort(int[] arr){
    int incr=arr.length/2;
    //进行步长的变化,当小于等于0的时候就结束
    for (int i=incr;i>0;i/=2){
        //对数据进行分组
        for (int j=i;j<arr.length;j++){
            //此处的i就是本次循环的步长
            for (int k=j;k>=i;k-=i){
                if (arr[k]<arr[k-1]){
                    swap(arr,k,k-1);
                }
            }
        }
    }
    return arr;
}

//交换方法(使用异或的方式,推荐使用)
public static void swap(int[] arr,int i,int j){
    arr[i]=arr[i]^arr[j];
    arr[j]=arr[i]^arr[j];
    arr[i]=arr[i]^arr[j];
}
5.快速排序
5.1 快速排序思想

​ 设置两个指针分别指向数组的最前边和最后边,始终将将数组的第一个数当作key,将数组拍成key前都是比key小的数,key后都是比key大的数。

5.2 时间复杂度

​ 快排的时间复杂度为O(nlog2n)

5.3 快排代码
/**
 * 快排算法
 * @param arr 数组名称
 * @param left 数组最初始的时候,最左边的下标,初始为0
 * @param right 数组最初始的时候,最右边的下标,初始为arr.length-1
 */
public static void quick(int[] arr,int left,int right) {

    //是递归结束的条件,当传来的数组长度小于等于1的时候,就没必要排序了,直接返回
    if (arr==null ||arr.length <= 1 || left>=right) {
        return;
    }

    int l = left;//从左边开始
    int r = right;//从右边开始
    int key = arr[left];//key始终是数组最左边的数字

    //当l和r不相同的时候
    //若l和r相同,那么说明第一次快排已经完成
    while (l != r) {
        //先从右边开始判断是否比key大
        //右边大于等于key的可以进来,直到右边小于key的时候听下,得到此时的下标
        while (arr[r] >= key & l<r) {
            r--;
        }
        //找到右边的之后,再从左边开始找,找到大于key的下标
        while (arr[l] <= key & l<r) {
            l++;
        }
        //此时已经找到了右边小于key的小标和左边大于key的下标
        //进行交换
        if (l < r) {
            arr[l] = arr[l] ^ arr[r];
            arr[r] = arr[l] ^ arr[r];
            arr[l] = arr[l] ^ arr[r];
        }
    }
    //进行到这说明左指针和右指针已经重合,此时应该将指针的数字和key进行交换
    //这块的arr[left]是数组最边的数组,也就是key
    arr[left]=arr[l];
    arr[l]=key;
    //进行到这说明第一次快排已经完成
    //可以直到key其实将数组分成了两半,左边是比key都小的,右边是比key都大的
    //那么继续可以使用快排思想,将剩下的两半进行快排
    quick(arr,left,l-1);
    quick(arr,r+1,right);
}
6.归并排序
6.1 归并排序思想

​ 将数组不断的拆分,直到拆分成两个不能再被拆分的最小单位(即只有两个数),然后将这两组中的数据进行排列并暂时存入到另外一个新数组中
在这里插入图片描述

6.2 时间复杂度

​ 归并排序的时间复杂度为O(nlogn)

6.3 归并排序代码
/**
 * 将数组拆分成两个数组一组的,方便比较,使用递归
 * @param arr 数组
 * @param low 数组最小位对应的下标
 * @param high 数组最高位对应的下标
 */
public static void mergeSort(int[] arr,int low,int high){
    //准备一个数组将排完序的数据进行存放
    int[] temp=new int[arr.length];
    //当数组被拆分成小的之后,最小拆分单位是两个数据
    //当拆分成最小单位的时候就不会被拆分,return
    if (low<high){
        //每次拆分的时候都是一半一半拆分
        int mid=(low+high)/2;
        //拆分左边一半
        mergeSort(arr,low,mid);
        //拆分右边一半
        mergeSort(arr,mid+1,high);
        //拆分成最小单位之后,对其进行比较排序
        merge(arr,low,mid,high,temp);
    }
}

/**
 * 对拆分之后的数据进行排序
 * @param arr 数组
 * @param mid 数组中间数据的下标
 * @param low 数组最左边数据的下标
 * @param high 数组最右边数据的下标
 * @param temp 排序之后放的新数组
 */
public static void merge(int[] arr,int low,int mid,int high,int[] temp){
    //给新数组中添加元素,作为元素下标
    int k=0;
    //指向左边数据的下标
    int m=low;
    //指向右边数据的下标
    int n=mid+1;
    //对两个小数组进行判断,并且将排序之后的数据放入新数组中
    while (m<=mid && n<=high){
        if (arr[m]<arr[n]){
            temp[k++]=arr[m++];
        }else {
            temp[k++]=arr[n++];
        }
    }
    //上面的while不一定将所有的数据全部都放入了新数组,只是将大的数组放入了新数组
    //如果有排好的数据,左边全是小的,右边全是大的,那么就会导致有一部分数据没有存入新数组
    while (m<=low){
        temp[k++]=arr[m++];
    }
    while (n<=high){
        temp[k++]=arr[n++];
    }
    //新的数组temp中存着排好的数据,接下来将这些数据重写存入arr中
    for (int i = 0; i < k; i++) {
        arr[low+i]=temp[i];
    }
}
7.堆排序
7.1 堆排序思想

​ 堆排序就是将数组换成树的形式,但不是二叉树,然后通过数组下标模拟树的位置,再通过树的思想去排序。

将数组换为树的形式
在这里插入图片描述

树的位置在数组下标上的体现
在这里插入图片描述

排序思想
在这里插入图片描述

7.2 时间复杂度

​ 堆排序的时间复杂度为O(nlogn)

7.3 堆排序代码
/**
 * 堆排序
 * @param arr 数组名称
 * @param start 数组起始下标
 * @param end 数组最后一位数的下标,需要递归则end-1
 */
public static void heapSort(int[] arr,int start,int end){
    //当头和尾相等的时候就直接返回,这时候只有两个数
    if (start==end){
        return;
    }
    //计算最后一个有孩子的节点,需要整型提升
    int lastFather=((start+end)%2==0)?(start+end)/2-1:(start+end)/2;
    //从最后一个有孩子的父节点向前遍历
    for (int father=lastFather;father>=0;father--){
        maxHeap(arr,father,end);
    }
    //进行到这说明最大的值已经在父节点上了,即最大的值在数组第一个位置上
    //那么需要将第一个位置上的数与最后一位的数交换
    arr[start]=arr[start]^arr[end];
    arr[end]=arr[start]^arr[end];
    arr[start]=arr[start]^arr[end];
    //进行到这块说明最大的一个数已经在数组的最后一位
    //那么需要将最后一位剔除出去,给其他的数据继续进行排序,得出最大的数
    //这块使用递归,只需要将end-1即可,不包括最后一位
    heapSort(arr,start,end-1);
}

/**
 * 对一个节点的数据和其左右孩子进行比较,取出最大的值放在父节点中
 * @param arr 数组
 * @param father 父节点的数组下标
 * @param end 这个数组未排序的最后一位下标
 */
public static void maxHeap(int[] arr,int father,int end){
    //一个节点在数组中的下标:n
    //一个节点的左子树在数组中的下标:2n+1
    //一个节点的右子树在数组中的下标:2n+2
    int leftChild=2*father+1;
    int rightChild=2*father+2;
    //判断父节点和右子树的数据大小
    //如果右子树值比父节点大,并且右子树的下标位置>=最后一个位置,则交换
    if (rightChild<=end && arr[rightChild]>arr[father]){
        arr[rightChild]=arr[rightChild]^arr[father];
        arr[father]=arr[rightChild]^arr[father];
        arr[rightChild]=arr[rightChild]^arr[father];
    }
    //判断父节点和左子树的数据大小
    if (arr[leftChild]>arr[father]){
        arr[leftChild]=arr[leftChild]^arr[father];
        arr[father]=arr[leftChild]^arr[father];
        arr[leftChild]=arr[leftChild]^arr[father];
    }
    //进行到这块说明最大的值已经在父节点上了
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值