常见排序算法整理(附Java代码)

此文章主要用于回顾常见的几种排序算法,对算法的原理并没有很详细的说明。

冒泡排序

原理:每次两两进行比较交换次序,以便每次将最大值将“沉”到已排好序的最后一个位置。

//冒泡排序
public class BubbleSort {
    public static int[] sort(int[] arr){
        int len = arr.length;
        for (int i = 0; i < len; i++) { //次数
            for (int j = 0; j < len-i-1; j++) { //这里注意还要减一,避免越界
                if(arr[j] > arr[j+1]){
                    swap(arr,j,j+1);	//交换函数
                }
            }
        }
        return arr;
    }
}

插入排序

原理:减治法。每次将当前数据插入到前面已排好序的数列中。插入的时候从后往前遍历找到合适位置。

//插入排序,减治法
public class InsertSort {
    public static int[] sort(int[] arr){
        int len = arr.length;
        for (int i = 1; i < len; i++) { //注意这里从1开始
            for(int j = i;j > 0 && arr[j] < arr[j-1];j--){
                swap(arr,j,j-1);
            }
        }
        return arr;
    }
}

tips:插入时,可以二分查找插入,提高效率。

选择排序

原理:第i次排序从第i-1个元素到最后一个元素中找出最小的元素,放到第i个位置上。

//选择排序
public class SelectSort {
    public static int[] sort(int[] arr){
        int len = arr.length;
        for (int i = 0; i < len-1; i++) {
            int min = i;;
            for (int j = i+1; j < len; j++) {
                if(arr[j] < arr[min]){
                    min = j;
                }
            }
            swap(arr,i,min);
        }
        return arr;
    }
}

归并排序

原理:分治法。相当于将数组分成两份,将左右两边分别排好序之后再归并起来。用递归的方法实现。

//归并排序,递归,分治法
public class MergeSort {
    public static int[] sort(int[] arr){
        mergeSort(arr,0,arr.length-1);
        return arr;
    }

    public static void mergeSort(int[] arr,int start,int end){
        if(end - start == 1){
            if(arr[start] > arr[end]){
                swap(arr,start,end);
            }
            return;
        }
        if(end == start) return;

        int center = (start+end)/2;
        mergeSort(arr,start,center);
        mergeSort(arr,center+1,end);
        merge(arr,start,center,end);
    }

    //归并,相当于归并两个数组
    public static void merge(int[] arr,int start,int center,int end){
        int[] newArr = new int[end-start+1];
        int i = start;
        int j = center+1;
        int k = 0;
        while(i<=center && j<=end){
            if(arr[i] < arr[j]){
                newArr[k++] = arr[i++];
            }else{
                newArr[k++] = arr[j++];
            }
        }

        if(i<=center){
            for(;i<=center;i++)
                newArr[k++] = arr[i];
        }
        if(j<=end){
            for(;j<=end;j++)
                newArr[k++] = arr[j];
        }
        k = 0;
        for (int l = start; l <= end; l++) {
            arr[l] = newArr[k++];
        }
    }

}

快排算法

原理:分治法。每次选出一个基准数据(一般认为是第一个数据)。将基准插入到合适位置(这个位置左边的数都小于基准,右边的数都大于基准)。递归实现。

//快排,递归,分治
public class QuickSort {
    public static int[] sort(int[] arr){
        quickSort(arr,0,arr.length-1);
        return arr;
    }

    public static void quickSort(int[] arr,int start,int end){
        if(start >= end)    return;
        if(end - start == 1){   //为了优化,可以不要这个判断
            if(arr[end] < arr[start]){
                swap(arr,end,start);
            }
            return;
        }
        int center = findPosition(arr,start,end);
        quickSort(arr,start,center-1);
        quickSort(arr,center+1,end);
    }


    public static int findPosition(int[] arr,int start,int end){
        int centerValue = arr[start];
        //找出center所在位置
        int i = start,j = end+1; //为了++i和--j
        while(true){
            while(arr[++i] <= centerValue) {if(i == end) break;}
            while(arr[--j] >= centerValue) {if(j == start) break;}
            if(i>=j) break;
            swap(arr,i,j);
        }
        swap(arr,start,j);
        return j;
    }
}

堆排序

原理:生成一个大顶堆(或小顶堆),每次将堆顶与最后一个数据交换位置,取出堆顶,剩余的数据重新调整堆结构。这里调整堆结构不太好理解。

//堆排序
public class HeapSort {
    public static int[] sort(int[] arr){ //用数组来表示二叉树树结构
        int[] arr2 = new int[arr.length+1];
        for (int i = 1; i < arr.length+1; i++) {    //向后移动一位,形成二叉树的位置关系,left = 2*root
            arr2[i] = arr[i-1];
        }
        int len = arr2.length;
        while(len != 1){
            arr2 = shiftHeapByInsert(arr2,len);    //对数组[1,len]的位置形成大顶堆
            swap(arr2,1,len-1);              //将大顶堆的堆顶放入尾部(并非最后)
            len--;
        }
        for (int i = 0; i < arr2.length-1; i++) {
            arr[i] = arr2[i+1];
        }
        return arr;
    }

    public static int[] shiftHeapByInsert(int[] arr,int len){
        int[] arr2 = arr;
        for (int i = 2; i < len; i++) {
            int k = i; //代表插入arr中的位置
            arr2[k] = arr[i];
            while(k != 1){
                int j = k/2;
                if(arr2[k] > arr2[j]){
                    swap(arr2,k,j);
                    k = j;
                }else{
                    break;
                }
            }
        }
        return arr2;
    }
}

希尔排序

原理:将小于n的整数d1作为第一个距离增量,第一次让所有距离为d1的数据排序。第二次让所有为d2的数据排序(d2<d1),,,直到最后一次让所有距离为1的数据排序,也就是所有数据排序。这里的距离增量可以人为设置。其中每次让所有距离为d的数据排序的算法为直接插入排序。

//希尔排序
public class ShellSort {
    public static int[] sort(int[] arr){
        int h=1;	//增量
        int length = arr.length;
        while (h < length/3)
            h = 3*h + 1;
        while(h >= 1){
            for (int i = h; i <length ; i++) {
                for(int j = i; j >= h && arr[j]<arr[j-h] ; j -= h )
                    swap(arr, j, j-h);
            }
            h = h/3;
        }
        return arr;
    }
}

参考书籍:《算法 第4版》,《算法分析与设计 第2版》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值