Java-七大排序算法,你学废了吗

写在开头

很久没有更新啦,今天来说一说排序的那些事。
排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。平时一般提到的排序一般都是指升序。主要的排序算法有七种:插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序、归并排序。
下面看我一一道来。

插入排序

//1.从无序区间拿出一个数
//2.与有序区间上的数比较
//3.插入合适的位置
//时间复杂度:最好 O(n) 最坏 O(n^2) 平均 O(n^2)
//空间复杂度:O(1)
//稳定
public static void insertSort(long[] array){
    for(int i=0;i<array.length;i++){
        long key=array[i+1];
        for(int j=i;j>=0;j--){
            if(key<array[j]){
                array[j+1]=array[j];
            }else{
                break;
            }
            array[j+1]=key;
        }
    }
}

希尔排序

//1.选定一个间隔,把数组分成几个组
//2.组内排序
//3.间隔缩小再排序 直到gap小于等于1
//时间复杂度:最好 O(n)  最坏 O(n^2)  平均 O(n^1.3)
//空间复杂度:O(1)
//不稳定
public static void shellSort(long[] array){
    int gap=array.length/2;
    while(true){
        insertSortGap(array,gap);
        if(gap==1){
            break;
        }
        gap=gap/2;
    }
}

private static void insertSortGap(long[] array, int gap) {
    for(int i=gap;i<array.length;i++){
        long key=array[i];
        int j;
        for(j=i-gap;j>=0;j=j-gap){
            if(array[i]<array[j]){
                array[j+gap]=array[i];
            }else{
                break;
            }
        }
        array[j+gap]=key;
    }
}

选择排序

//1.遍历选出无序数组中的最大数 记下它的下标
//2.把它放到最后变成有序部分
//3.不断找出最大数往有序部分里放 直到遍历完
//时间复杂度:O(n^2)
//空间复杂度:O(1)
//不稳定
public static void selectSort(long[] array){
    int maxIndex=0;
    for(int i=0;i<array.length-1;i++){
        for(int j=0;j<array.length-i;j++){
            if(array[j]>array[maxIndex]){
                maxIndex=j;
            }
        }
        long t=array[maxIndex];
        array[maxIndex]=array[array.length-i-1];
        array[array.length-i-1]=array[maxIndex];
    }
}

堆排序

//1.建大堆(最大的数在堆顶)
//2.把最大的数交换到最后(后面的部分逐渐有序)
//3.剩下无序部分向下调整 
//4.重复交换 向下调整 直到有序
//时间复杂度:O(n*log(n))
//空间复杂度:O(1)
//不稳定
public static void heapSort(long[] array){
    creatHeap(array,array.length);
    for(int i=0;i<array.length-1;i++){
        long t=array[0];
        array[0]=array[array.length-i-1];
        array[array.length-i-1]=t;
        shiftDown(array,array.length-i-1,0);
    }
}

private static void shiftDown(long[] array, int size, int index) {
    while(2*index+1<size){//有左孩子
        int maxIndex=2*index+1;
        if(maxIndex+1<size&&array[maxIndex+1]>array[maxIndex]){
            maxIndex++;
        }//如果左孩子比右孩子小
        if(array[index]>=array[maxIndex]){
            break;
        }//父节点比孩子节点大就不用换
        long t=array[maxIndex];
        array[maxIndex]=array[index];
        array[index]=t;//交换
        index=maxIndex;//继续向下比较
    }
}

private static void creatHeap(long[] array, int size) {
    for(int i=(size-2)/2;i>=0;i--){
        shiftDown(array,size,i);
    }//从最后一个有子树的下标开始向下调整 一直到第一个
}

冒泡排序

//1.在无序区间中相邻数比较 大数往后走 一次遍历找到一个最大的放在最后
//2.一直遍历比较 直到数组有序
//时间复杂度:最好 O(n) 最坏 O(n^2) 平均 O(n^2)
//空间复杂度:O(1)
//稳定
public static void bubbleSort(long[] array){
    for(int i=0;i<array.length;i++){
        boolean isSorted=true;
        for(int j=0;j<array.length-1-i;j++){
            if(array[j]>array[j+1]){
                long t=array[j];
                array[j]=array[j+1];
                array[j+1]=t;
                isSorted=false;
            }
        }
        if(isSorted){
            break;
        }
    }
}

快速排序

//1.选择第一个数 作为基准
//2.对其做partition 遍历数组 将比它小的数放在它的左侧 比它大的数放在右侧
//3.对左右两部分 进行相同的操作 递归
//时间复杂度: 最好 O(n*log(n)) 平均 O(n*log(n)) 最坏 O(n^2)
//空间复杂度:最好 O(log(n))  平均 O(log(n)) 最坏 O(n)
//不稳定
public static void quickSort(long[] array){
    quickSortInternal(array,0,array.length-1);
}

private static void quickSortInternal(long[] array, int leftIndex, int rightIndex) {
    if(leftIndex>=rightIndex){
        return;
    }
    int key=partition(array,leftIndex,rightIndex);
    quickSortInternal(array,leftIndex,key-1);
    quickSortInternal(array,key+1,rightIndex);
}

private static int partition(long[] array, int lowIndex, int highIndex) {
    long key=array[lowIndex];
    int leftIndex=lowIndex;
    int rightIndex=highIndex;
    while(leftIndex<rightIndex){
        while(leftIndex<rightIndex&&array[rightIndex]>=key){
            rightIndex--;
        }//右下标往左走 找到比key小的数停下来
        while (leftIndex<rightIndex&&array[leftIndex]<=key){
            leftIndex++;
        }//左下标往右走 找到比key大的数 停下
        long t=array[leftIndex];
        array[leftIndex]=array[rightIndex];
        array[rightIndex]=t;
        //交换
    }//两下标相遇 跳出循环
    long m=array[leftIndex];
    array[leftIndex]=array[lowIndex];
    array[lowIndex]=m;
    //左下标停下的数与基准数交换
    return leftIndex;
}

归并排序

//1.把数组分成两部分 不断划分 进行相同的操作 直到区间只剩下一个数 必然有序
//2.将有序的区间合并 递归
//时间复杂度:O(n*log(n))
//空间复杂度:O(n)    
//稳定
public static void mergeSort(long[] array){
    mergeSortInternal(array,0,array.length);
}

private static void mergeSortInternal(long[] array, int lowIndex, int highIndex) {
    int size=highIndex-lowIndex;
    if(size<=1){
        return ;
    }
    int middleIndex=(highIndex+lowIndex)/2;
    mergeSortInternal(array,lowIndex,middleIndex);
    mergeSortInternal(array,middleIndex,highIndex);
    merge(array,lowIndex,middleIndex,highIndex);
}

private static void merge(long[] array, int lowIndex, int middleIndex, int highIndex) {
    int size=highIndex-lowIndex;
    long[] extraArray=new long[size];
    int leftIndex=lowIndex;
    int rightIndex=middleIndex;
    int extraIndex=0;
    while(leftIndex<middleIndex&&rightIndex<highIndex){
        if(array[leftIndex]<=array[rightIndex]){
            extraArray[extraIndex++]=array[leftIndex++];
        }else{
            extraArray[extraIndex++]=array[rightIndex++];
        }
    }
    if(leftIndex<middleIndex) {
        while (leftIndex < middleIndex) {
            extraArray[extraIndex++] = array[leftIndex++];
        }
    }else{
        while(rightIndex<highIndex){
            extraArray[extraIndex++]=array[rightIndex++];
        }
    }
    for(int i=0;i<size;i++){
        array[lowIndex+i]=extraArray[i];
    }
}

好啦,排序算法就总结到这里啦,码字不易,欢迎批评指正!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值