一文通关八大排序算法

一、选择排序

思路:从数组中选择最小元素,将它与数组的第一个元素交换位置。再从剩下的元素中选择出最小的元素,将它与第二个元素交换位置。不断进行这样的操作,直到遍历完整个数组。

时间复杂度:O(n^2)
空间复杂度:O(1)
稳定性(两个相等元素的绝对位置交换前后是否发生改变):不稳定

public static void SelectSort(int[] arr){

        int minIndex;

        //依此遍历找剩下元素的最小
        for (int i=0;i<arr.length;i++){
            minIndex=i;
            for (int j=i+1;j<arr.length;j++){
                if (arr[j]<arr[minIndex]){
                    minIndex=j;
                }
            }

          
            //交换元素
            if (minIndex!=i){
                int tmp=arr[minIndex];
                arr[minIndex]=arr[i];
                arr[i]=tmp;

            }

        }

    }

二、冒泡排序

思路:从左到右不断交换相邻逆序的元素,在一轮的循环之后,可以让未排序的最大元素上浮到右侧。在一轮循环中,如果没有发生交换,那么说明数组已经是有序的,此时可以直接退出。
时间复杂度:O(n^2)
空间复杂度:O(1)
稳定性:稳定

    public static void bubbleSort(int[] arr) {

        //该轮是否排序了
        boolean isSort = true;
        
        //如果上一轮没有发生交换,直接跳出循环
        for (int i = 0; i < arr.length && isSort; i++) {
            isSort = false;
            for (int j = 1; j < arr.length - i; j++) {
                if (arr[j - 1] > arr[j]) {
                    isSort = true;
                    //交换元素
                    int tmp = arr[j - 1];
                    arr[j - 1] = arr[j];
                    arr[j] = tmp;
                }
            }

        }

    }

三、插入排序

思路:每次都将当前元素插入到左侧已经排序的数组中,使得插入之后左侧数组依然有序。
时间复杂度:O(N)~O(N^2)和初始顺序有关
空间复杂度:O(1)
稳定性:稳定

    public static void insertSort(int[] arr) {


        for (int i = 1; i < arr.length; i++) {
            
            //寻找适合的位置插入
            if (arr[i] < arr[i - 1]) {
                int tmp = arr[i];
                int j;
                for (j = i - 1; j >= 0 && arr[j] > tmp; j--) {
                    arr[j + 1] = arr[j];
                }

                arr[j + 1] = tmp;
            }

        }

    }

四、希尔排序

思路:插入排序只能交换相邻的元素,对于大规模的数组,其插入排序很慢,希尔排序使用插入排序对时间间隔h的序列进行排序,通过不断减小h,最后令h=1。
时间复杂度:依赖于增量序列,优于插入排序
空间复杂度:O(1)
稳定性:不稳定

    public static void shellSort(int[] arr) {

        //初始间隔d,一直到1
        for (int d = arr.length / 2; d > 0; d = d / 2) {
            //从d开始
            for (int i = d; i < arr.length; i++) {
                
                for (int j = i - d; j >= 0; j -= d) {
                    if (arr[j + d] < arr[j]) {
                        int tmp = arr[j + d];
                        arr[j + d] = arr[j];
                        arr[j] = tmp;
                    }

                }

            }

        }

    }

五、快速排序

思路:快速排序通过一个切分元素将数组分为两个子数组,左子数组小于等于切分元素,右子数组大于等于切分元素,将这两个子数组排序也就将整个数组排序了。

快速排序最好的情况下是每次都正好将数组对半分,这样递归调用次数才是最少的。这种情况下比较次数为 CN=2CN/2+N,复杂度为 O(NlogN)。
最坏的情况下,第一次从最小的元素切分,第二次从第二小的元素切分,如此这般。因此最坏的情况下需要比较 N2/2。为了防止数组最开始就是有序的,在进行快速排序时需要随机打乱数组。
时间复杂度:O(NlogN)
空间复杂度:O(logN)
稳定性:不稳定

    public static void quickSort(int[] arr, int start, int end) {

        if (start < end) {
            //确定切分元素
            int stard = arr[start];
            int low = start, high = end;

            while (low < high) {

                while (low < high && arr[high] >= stard) {
                    high--;
                }

                arr[low] = arr[high];

                while (low < high && arr[low] < stard) {
                    low++;
                }

                arr[high] = arr[low];

            }

            arr[low] = stard;

            //处理前面的
            quickSort(arr, start, low - 1);

            //后面
            quickSort(arr, low + 1, end);

        }

    }

六、归并排序

思路:归并排序的思想是将数组分成两部分,分别进行排序,然后归并起来。
时间复杂度:O(NlogN)
空间复杂度:O(N)
稳定性:稳定

    public static void mergeSort(int[] arr,int low,int high){

        int middle=(low+high)/2;
        if (low<high){

            //处理左边
            mergeSort(arr,low,middle);

            //处理右边
            mergeSort(arr,low+1,high);

            //排序
            merge(arr,low,middle,high);

        }


    }

    /**
     *@description
     * 将两个已经排序的数组并成一个
     *@author lugton
     *@date 2020/3/23
     *@return
     */
    public static void merge(int[] arr,int low,int middle,int high){

        int i=low,j=middle+1;
        int[] tmp=new int[arr.length];

        //复制辅助数组
        for (int k=low;k<=high;k++){
            tmp[k]=arr[k];
        }

        for (int k=low;k<=high;k++){

            //前面数组已经排完
            if (i>middle){
                arr[k]=tmp[j++];
            }else if (j>high){
                //后面数组已经排完
                arr[k]=tmp[i++];
            }else if (tmp[i]<=tmp[j]){
                arr[k]=tmp[i++];
            }else {
                arr[k]=tmp[j++];
            }

        }

    }

七、堆排序

思路:构建大顶堆,然后依此将堆顶放入数组,从后往前放。
时间复杂度:O(NlogN)
空间复杂度:O(1)
稳定性:不稳定

    public static void heapSort(int[] arr){

        //开始位置是最后一个非叶子节点,也就是最后一个节点的父节点
        int start=(arr.length-1)/2-1;

        //调整为大顶堆
        for (int i=start;i>=0;i--){
            maxHeap(arr,arr.length,i);
        }

        //把数组第0个和堆中最后一个交换位置
        for (int i=arr.length-1;i>0;i--){

            int tmp=arr[0];
            arr[0]=arr[i];
            arr[i]=tmp;

            maxHeap(arr,i,0);

        }



    }


    public static void maxHeap(int[] arr,int size,int index){

        //左子节点
        int left=2*index+1;
        int right=2*index+2;
        int max=index;

        //找出最大的节点

        if (left<size && arr[left]>arr[max]){
            max=left;
        }
        if (right<size && arr[right] > arr[max]){
            max=right;
        }

        //交换位置
        if (max!=index){

            int tmp=arr[index];
            arr[index]=arr[max];
            arr[max]=tmp;

            //交换位置以后,可能会破坏之前的堆,所以要重新进行排序
            maxHeap(arr,size,max);

        }

    }

也可以利用优先队列构建小顶堆

 public static void heap(int[] arr){

        //小顶堆
        PriorityQueue<Integer> priorityQueue=new PriorityQueue<>();

        for (int num:arr
             ) {
            priorityQueue.add(num);
        }

        for (int i=0;i<arr.length;i++){
            arr[i]=priorityQueue.poll();
        }


    }

八、基数排序

思路:数字都是由0-9组成的,所以可以用10个桶来进行排序。先依据序列的个为分配到指定的桶中,然后再对十位...百位...做相应排序。
时间复杂度:O(n)
空间复杂度:O(n+k)k为桶的数量
稳定性:稳定

参考自:https://www.cnblogs.com/yadiel-cc/p/11829398.html

    /**
     * @return
     * @description digit 最多有多少位数字
     * @author lugton
     * @date 2020/6/26
     */
    public void randix(int[] arr, int digit) {

        //10个桶
        int radix = 10;

        int begin = 0, end = arr.length - 1;

        int i = 0, j = 0;
        //存放每个桶的数据个数
        int[] count = new int[radix];

        int[] bucket = new int[end - begin + 1];

        //按照从低位到高位的顺序进行排序 也就是从个位开始
        for (int d = 1; d <= digit; d++) {

            //初始化
            for (i = 0; i < radix; i++) {
                count[i] = 0;
            }

            //统计每个桶要装入数据的个数
            for (i = begin; i <= end; i++) {

                j = getDigit(arr[i], d);
                count[j]++;
            }

            //每个桶的右边界索引
            for (i = 1; i < radix; i++) {
                count[i] = count[i] + count[i - 1];
            }

            //数字依次入桶
            for (i = end; i >= begin; i--) {

                j = getDigit(arr[i], d);
                //放入桶的对应位置
                bucket[count[j] - 1] = arr[i];
                //索引对应的也要减一位
                count[j]--;
            }

            //返回按个位排序的数组
            for (i = begin, j = 0; i <= end; i++, j++) {
                arr[i] = bucket[j];
            }

        }


    }

    /**
     * @return
     * @description 获取数字x第d位上的数字
     * @author lugton
     * @date 2020/6/26
     */
    public int getDigit(int x, int d) {

        while (--d > 0) {
            x = x / 10;
        }
        return x % 10;
    }

九、二分查找

    public static void BinarySearch(int[] arr,int target){

        int begin=0;
        int end=arr.length-1;

        int index=-1;

        int mid=(begin+end)/2;

        while (true){

            if (target==arr[mid]){
                index=mid;
                break;
            }else {

                if (target<arr[mid]){
                    end=mid-1;
                }else {
                    begin=mid+1;
                }
            }

            mid=(begin+end)/2;

        }

        System.out.println("index:"+index);

    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。