《排序的底层逻辑:比较、交换与分治》

本文系统讲解插入排序(直接插入、希尔)、选择排序(简单选择、堆排序)、交换排序(冒泡、快速及其非递归)和归并排序(递归与非递归)的底层逻辑,涵盖分治、比较、交换等核心思想,分析各算法时间/空间复杂度、稳定性及Java实现要点。

0.总览

在这里插入图片描述

一.插入排序

1.1直接插入排序

1).首先我们将元素划分为两组,分别是已排序区间[0,bound)和待排序区间[bound,size)
2).取待排序区间的第一个元素[bound]往已排序区间插入
3).中间要与已排序区间的元素排大小,不断覆盖
时间复杂度:o(n2)
空间复杂度:o(1);
是否稳定:稳定

    public static void insertSort(int[] arr){
        int bound = 1;
        for(;bound<arr.length;bound++){
            int value = arr[bound];
            int cur = bound-1;
            for(;cur>=0;cur--){
                if(arr[cur]>value){
                    arr[cur+1]= arr[cur];
                }
                else{
                    break;
                }
            }
          arr[cur+1] = value;
        }
    }

测试:

 public static void main(String[] args){
//        测试直接插入排序
        int[] arr = new int[]{9,1,2,5,7,4,8,1,3,5};
        insertSort(arr);
        System.out.println(Arrays.toString(arr));
    }

在这里插入图片描述

1.2希尔排序

这个希尔排序其实就是直接插入排序的延伸,它是分成好多的组,好多个组在进行插入排序

1)首先要分间隔,例如元素
== 9,1,2,5,7,4,8,1,3,5==
当gap取5
在这里插入图片描述
在这里插入图片描述
可以看到明显有序多了
在这里插入图片描述

看下标元素,然后再继续逐步缩小gap,一直到整体有序

最后保底gap为1,其实就是直接插入排序

时间复杂度取决于BAP,最好能达到o(n1.3)
gap大:分组的元素比较少
gap下:分组的元素整体比较有序
是否稳定:不稳定

二.选择排序

2.1选择排序

  1. .选择排序的代码非常简单,就类似于打擂台,给一个最大值,谁打赢了就是最大的,;
    private static void swap(int[] arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    public static void selectSort(int[] arr){
        int bound = 0;
        for(;bound < arr.length;bound++){
            int minindex = bound;

            for(int cur = bound+1;cur<arr.length;cur++) {
                if (arr[cur] < arr[minindex]) {
                    minindex = cur;
                }
            }
swap(arr,bound,minindex);
        }
    }

2.2堆排序

1)把数组创建成优先级队列堆;
2)这里取从小到大的堆排序,将跟节点与最后一个有效节点heapSize节点交换,heapSiz–;
3)不断循环;
建堆

    public static void creatHeap(int[] arr){

        for(int i = (arr.length-1-1)/2;i>=0;i--){
            shifDown(arr,arr.length,i);
        }
    }

向下

    public static void shifDown(int[] arr,int size,int root){
        int parent = root;
        int child = 2*parent+1;
        while(child<size){
            if(child+1<size&&arr[child+1]>arr[child]){
                child = child+1;
            }
            if(arr[parent]<arr[child]){
                swap(arr,parent,child);
                child = parent;
                child = 2*parent+1;
            }
            else{
                break;
            }
        }
    }

堆排序

//    堆排序
    public static void heapSort(int[] arr){
        int heapSize = arr.length;
        creatHeap(arr);
        for(int i = 0;i<arr.length-1;i++){
            swap(arr,0,heapSize-1);
            heapSize--;
            shifDown(arr,heapSize,0);
        }
    }

测试

//        测试堆排序
        heapSort(arr);
        System.out.println(Arrays.toString(arr));

在这里插入图片描述

三.交换排序

3.1冒泡排序

时间复杂度:o(n2)
空间复杂度:o(1)
是否稳定:稳定

//    冒泡排序
    public static void bubbleSort(int[] arr){
        for(int i = 0;i<arr.length;i++){
            boolean fla = true;
            for (int j = 0; j < arr.length-1-i; j++) {
                if(arr[j]>arr[j+1]){
                    swap(arr,j,j+1);
                    fla = false;
                }
            }
            if(fla == true){
                break;
            }
        }
    }

测试

        bubbleSort(arr);
        System.out.println(Arrays.toString(arr));

在这里插入图片描述

3.2快速排序

这个非常重要,至少在古法编程中是非常重要的;
1)先写快速排序的辅助方法,寻找基准值
2)根据基准值划分两个区间,然后递归的进行区分拆解;
3)基准值取最右边

//    快速排序
    public static void quickSort(int[] arr){
        quickSortHelper(arr,0,arr.length-1);
    }
    public static void quickSortHelper(int[] arr,int left,int right) {
        if(left>=right){
return ;
        }
//        先拿到基准值,分组大致整体有序
        int index = partition(arr, left, right);
        quickSortHelper(arr,left,index-1);
        quickSortHelper(arr,index+1,right);
    }
    public static int partition(int[] arr,int left,int right){
        int l = left;
        int r = right;
        while(l<r){
            while(l<r&&arr[l]<=arr[right]){
                l++;
            }
            while(l<r&&arr[r]>=arr[right]){
                r--;
            }
            swap(arr,l,r);
        }
        swap(arr,l,right);
        return l;
    }

测试

//        测试快速排序
        quickSort(arr);
        System.out.println(Arrays.toString(arr));
    }

在这里插入图片描述

3.3快速排序非递归实现

1)先将区间左右界限依次入栈;
2)找到基准值,把基准值的左右排好整体顺序
3)注意栈是后进先出,不然出入栈会出现问题

//    非递归快速排序;
    public static void quickSortByloop(int[] arr){
        Stack<Integer> stack = new Stack<>();
        stack.push(arr.length-1);
        stack.push(0);
        while(!stack.empty()){
            int left = stack.pop();
            int right = stack.pop();
            if(left>=right){
                continue;
            }
            int index = partition(arr,left,right);
//先传右边区间
            stack.push(right);
            stack.push(index+1);
//            在传左边区间
            stack.push(index-1);
            stack.push(left);
        }
    }

测试

//        测试非递归快速排序
        quickSortByloop(arr);
        System.out.println(Arrays.toString(arr));

在这里插入图片描述

四.归并排序

归并排序和快速排序的思想是一样的,都是分治思想

4.1归并排序

1)图解
在这里插入图片描述
手绘,可以看到先分出来,然后再往回归并,最后变得有序
1)找到中间值,进行区间划分,一直到最后不能分
2)运用递归不断划分区间

// 归并排序
    public static void mergeSort(int[] arr){
        mergeSortHelper(arr,0,arr.length);
    }
    public static void mergeSortHelper(int[] arr,int left,int right){
        if(right-left>=1){
            return;
        }
        int mid = (left+right)/2;
        mergeSortHelper(arr,left,mid);
        mergeSortHelper(arr,mid,right);
        merge(arr,left,mid,right);
    }
    public static void merge(int[] arr,int left,int mid,int right){
        int[] temp = new int[right-left];
        int tempIndex = 0;
        int cur1 = left;
        int cur2 = mid;
        while(cur1<cur2&&cur2<right){
            if(arr[cur1]<=cur2){
                arr[tempIndex] = arr[cur1];
                tempIndex++;
            }
            else{
                arr[tempIndex] = arr[cur2];
                tempIndex++;
            }
        }
        while(cur1<cur2){
            arr[tempIndex] = arr[cur1];
            tempIndex++;
        }
        while(cur2<right){
            arr[tempIndex] = arr[cur2];
            tempIndex++;
        }
    }

4.2归并排序非递归实现

这个很容易理解,就是合并尺寸为1的数组,有了尺寸为2的数组然后依次往后合并
1)初始设置尺寸为1;
2)合并完成在合并2的数组

   public static void mergeSortByloop(int[] arr){
           int size = 1;
           for(;size<arr.length;size*=2) {
               for (int i = 0; i < arr.length; i += 2 * size) {
                   int left = i;
                   int mid = i + size;
                   if (mid > arr.length) {
                       mid = arr.length;
                   }
                   int right = i + 2 * size;
                   if (right > arr.length) {
                       right = arr.length;
                   }
                   merge(arr, left, mid, right);
               }
           }
   }
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bro_Java666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值