java面试总结—常用的排序算法

更多内容可以到专栏查看:https://blog.csdn.net/sunshine543123/category_10899368.html
本博客中都是按照从小到大排列

1.冒泡排序

对序列中所有数实行前后元素对比,小的在前大的在后,这样从头到尾进行n-1次

public class bubbleSort {
    
    
    public static void main(String[] args) {
    
    
        int[] a={
    
    1,34,79,3,78,20,5,2,50,71,66,21};
        int len=a.length;
        int temp=a[0];
        for (int i = 0; i < len; i++) {
    
    
            for (int j = 0; j < len-i-1; j++) {
    
    
                if (a[j]>a[j+1]){
    
    
                    temp=a[j];
                    a[j]=a[j+1];
                    a[j+1]=temp;
                }
            }

        }
        for (int i = 0; i < len; i++) {
    
    
            System.out.print(a[i]+",");
        }
    }

}

时间复杂度O(n^2)

2.直接选择排序(简单选择排序)

通过n-i次关键字的比较,从n-i+1个记录中选出关键字最小的记录,并和第i个记录交换

public class directSort {
    
    
    public static void main(String[] args) {
    
    
        int[] a={
    
    1,34,79,3,78,20,5,2,50,71,66,21};
        int min;
        for (int i = 0; i < a.length; i++) {
    
    
            min=i;
            for (int j = i; j < a.length; j++) {
    
    
                if (a[min]>a[j]){
    
    
                    min=j;
                }
            }
            if (min!=i){
    
    
                swap(a,i,min);
            }
        }
        for (int i = 0; i < a.length; i++) {
    
    
            System.out.print(a[i]+",");
        }
    }
    public static void swap(int[] a, int i, int j) {
    
    
        int t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
}

时间复杂度O(n^2)

3.插入排序

将一个记录插入到已经排好序的有序表中,从而得到一个新的,记录数增1的有序表

public class insertSort {
    
    
    public static void main(String[] args) {
    
    
        int[] a={
    
    34,79,3,78,20,5,2,50,71,66,21};

        int temp;
        int j;
        for (int i = 1; i < a.length; i++) {
    
    
            if (a[i]<a[i-1]){
    
    
                temp=a[i];
                for (j = i;j>0&&temp<a[j-1]; j--) {
    
    
                    a[j]=a[j-1]; //后移
                }
                a[j]=temp;
            }
        }


        for (int i = 0; i < a.length; i++) {
    
    
            System.out.print(a[i]+",");
        }
    }
}

最好时间复杂度O(n),最坏时间复杂度O(n^2)

4.希尔排序

在插入排序的基础上,将相隔某个增量的记录组成一个子序列,将子序列进行直接插入排序后得到基本有序序列(小的基本在前,大的基本在后),再对全体记录进行一次直接插入排序

public class ShellSort {
    
    
    public static void main(String[] args) {
    
    
        int[] a={
    
    1,34,79,3,78,20,5,2,50,71,66,21};

        int j,i;
        int increment=a.length;
        int temp;

        do {
    
    
            increment=increment/3+1; //增量序列   增量序列的最后一个值必须等于1

            for (i=increment;i< a.length;i=i+increment){
    
    
                if (a[i]<a[i-increment]){
    
    
                    temp=a[i];   //暂存在temp
                    for (j=i; j> 0 && temp<a[j-increment]; j=j-increment){
    
    

                        a[j]=a[j-increment];
                    }
                    a[j]=temp;
                }
            }

        }while (increment>1);



        for (i = 0; i < a.length; i++) {
    
    
            System.out.print(a[i]+",");
        }
    }
}

时间复杂度O(n³/²)

5.堆排序

简单选择排序的升级
堆结构:
堆是具有下列性质的完全二叉树:每个节点的值都大于等于左右孩子结点值,称为大顶堆;每个节点的值都小于等于左右孩子结点值,称为小顶堆;
基本思想:将待排序列构建成一个大顶堆。此时,整个序列的最大值就是堆顶的根节点。将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次大值,如此反复就能得到一个有序序列了。

import java.util.Arrays;

public class HeapSort {
    
    
    public static void main(String[] args) {
    
    
        int[] arr={
    
    50,10,90,30,70,40,80,60,20};
        System.out.println("排序前:"+ Arrays.toString(arr));

        //将arr构建为大顶堆
        for (int i = arr.length/2-1; i >=0 ; i--) {
    
      //从第一个有子节点的位置排序(从左到右,从下到上)
            heapAdjust(arr,i,arr.length);
        }

        for (int j = arr.length-1; j>0 ; j--) {
    
    
            swap(arr,0,j);  //将当前堆中最大的和未排序的最后一个交换
            heapAdjust(arr,0,j);
        }
        System.out.println("排序后:"+Arrays.toString(arr));
    }
    //实现大顶堆
    public static void heapAdjust(int[] a,int i,int len){
    
    
        int temp=a[i];//取出当前元素

        for (int k=2*i+1;k<len;k=2*k+1){
    
      //沿值较大的孩子结点向下筛选
            if (k+1<len&&a[k]<a[k+1]){
    
      //比较根节点a[i]的左右孩子大小
                k=k+1;  //记录较大的结点位置
            }
            if (temp > a[k]){
    
    

                break;   //比左右孩子结点大,不需要交换
            }

            //否则交换
            a[i]=a[k];
            a[k]=temp;
            //若交换后的子节点存在子节点则继续进行排序(自上向下)
            i=k;
        }

    }
    public static void swap(int []arr,int a ,int b){
    
    
        int temp=arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
}

时间复杂度O(n*logn)

6.归并排序

冒泡排序的升级
假设初始序列含有n个记录,则可以看成n个有序的子序列,每个子序列的的长度为1,然后两两归并,得到[n/2]个长度为2或1的子序列,再两两归并,…,如此重复知道得到一个长度为n的有序序列为止,这种排序方法被称为2路排序归并
使用递归算法:

import java.util.Arrays;
// 使用递归算法,先递归拆分再归并
public class MergeSort {
    
    
    public static void main(String[] args) {
    
    
        int[] arr={
    
    50,10,90,30,70,40,80,60,20};
        System.out.println("排序前:"+Arrays.toString(arr));
        int[] TR1=new int[arr.length];

        Msort(arr,TR1,0,arr.length-1);
        System.out.println("排序后:"+ Arrays.toString(TR1));
    }
    public static void Msort(int[] arr,int[] TR1,int s,int t){
    
    
        int m;
        int[] TR2=new int[arr.length];
        if (s==t){
    
    
            TR1[s]=arr[s];
        }
        else{
    
    
            m=(s+t)/2;
            Msort(arr,TR2,s,m);
            Msort(arr,TR2,m+1,t);
            Merge(TR2,TR1,s,m,t);
        }
    }
    //将有序的arr[i,m],arr[m+1,n]归并为有序的TR[i,n]
    public static void Merge(int[] arr,int[] TR1,int i,int m,int n){
    
    
        int j,k;
        for (k=i,j=m+1;i<=m&&j<=n;k++){
    
    
            if (arr[i]<arr[j]){
    
    
                TR1[k]=arr[i];
                i=i+1;
            }
            else{
    
    
                TR1[k]=arr[j];
                j=j+1;
            }
        }
        while (i<=m){
    
    
            TR1[k]=arr[i];  //将剩余的arr[i,m]复制到TR1[]
            k++;
            i++;
        }
        while (j<=n){
    
    
            TR1[k]=arr[j]; 将剩余的arr[j,n]复制到TR1[]
            k++;
            j++;

        }
    }
}

减少空间复杂度的非递归算法

import java.util.Arrays;

/**
 * 使用迭代,从最小的序列开始直至完成
 */
public class MergeSort2 {
    
    
    public static void main(String[] args) {
    
    
        int[] arr={
    
    50,10,90,30,70,40,80,60,20};
        System.out.println("排序前:"+Arrays.toString(arr));
        int[] TR1=new int[arr.length];

        int k=1;
        while (k<arr.length){
    
    
            MergePass(arr,TR1,k,arr.length);
            k=2*k;
            MergePass(TR1,arr,k,arr.length); //将归并到TR1中的序列再次两两归并回arr
            k=2*k;
        }
        System.out.println("排序后:"+ Arrays.toString(arr));
    }
    public static void MergePass(int[] arr, int[] TR1, int s, int n){
    
      //s指每个子序列的长度s={1,2,4...2k}(2k<n),n指整个序列的的长度
        int i=0;
        while (i <= n-2*s){
    
      //两两归并的次数
            Merge(arr,TR1,i,i+s-1,i+2*s-1);
            i=i+2*s; //下一个两两归并序列的第一个元素
        }
        if (i<n-s){
    
      //归并最后两个
            Merge(arr,TR1,i,i+s-1,n-1);
        }
        else {
    
        //只剩单个的一个子序列
            for (int j = i; j < n; j++) {
    
    
                TR1[j]=arr[j];
            }
        }
    }
    //将有序的arr[i,m],arr[m+1,n]归并为有序的TR[i,n]
    public static void Merge(int[] arr,int[] TR1,int i,int m,int n){
    
    
        int j,k;
        for (k=i,j=m+1;i<=m&&j<=n;k++){
    
    
            if (arr[i]<arr[j]){
    
    
                TR1[k]=arr[i];
                i=i+1;
            }
            else{
    
    
                TR1[k]=arr[j];
                j=j+1;
            }
        }
        while (i<=m){
    
    
            TR1[k]=arr[i];  //将剩余的arr[i,m]复制到TR1[]
            k++;
            i++;
        }
        while (j<=n){
    
    
            TR1[k]=arr[j]; 将剩余的arr[j,n]复制到TR1[]
            k++;
            j++;

        }
    }
}

时间复杂度O(nlogn)

7.快速排序

快速排序的基本思想是任取待排序序列的一个元素作为中心元素(可以用第一个,最后一个,也可以是中间任何一个),习惯将其称为pivot,枢轴元素; 将所有比枢轴元素小的放在其左边; 将所有比它大的放在其右边; 形成左右两个子表; 然后对左右两个子表再按照前面的算法进行排序,直到每个子表的元素只剩下一个。

import java.util.Arrays;

public class quickSort {
    
     //快速排序
    public static void main(String[] args) {
    
    
        int[] arr={
    
    50,10,90,30,70,40,80,60,20};
        QSort(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }
    public static void QSort(int[] arr,int low,int high){
    
    
        int pivot;
        if (low<high){
    
    
            pivot=Partition(arr,low,high);
            QSort(arr,low,pivot-1);
            QSort(arr,pivot+1,high);
        }
    }
    public static int Partition(int[] arr,int low,int high){
    
    
        int pivotKey=arr[low];
        while (low<high){
    
    
            while(low<high&&arr[high]>=pivotKey){
    
    
                high--;
            }
            swap(arr,high,low); //将比枢轴元素小的交换到低端
            while (low<high&&arr[low]<pivotKey){
    
    
                low++;
            }
            swap(arr,low,high);
        }
        return low; //返回枢轴元素所在的位置
    }
    public static void swap(int []arr,int a ,int b){
    
    
        int temp=arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
}

最优时间复杂度:O(nlogn)
最坏时间复杂度:O(n^2)
平均时间复杂度:O(nlogn)

猜你喜欢

转载自blog.csdn.net/sunshine543123/article/details/115085696