JAVA 修炼秘籍第十一章:《排序,没有最好最全,只有更好更全》

18 篇文章 0 订阅
13 篇文章 0 订阅

往期:
JAVA 修炼秘籍第一章:《痛苦的折磨》
JAVA 修炼秘籍第二章:《逐渐魔化》
JAVA 修炼秘籍第三章:《绝地反击》
JAVA 修炼秘籍第四章:《闭关修炼》
JAVA 修炼秘籍第五章:《卧薪尝胆》
JAVA 修炼秘籍第六章:《鏖战》
JAVA 修炼秘籍第七章:《面向对象编程》
JAVA 修炼秘籍第八章:《String类》
JAVA 修炼秘籍第九章:《List / ArrayList / LinkedList 》
JAVA 修炼秘籍第十章:《优先级队列(堆)PriorityQueue》
JAVA修炼秘籍(番外篇)第一章:《这四道代码题,你真的会吗?》
JAVA修炼秘籍(番外篇)第二章:《图书馆管理系统》


——————————————————————生活以痛吻我,我却报之以歌。

在这里插入图片描述


一、插入排序

  1. 时间复杂度:O(n²)。
  2. 空间复杂度:O(1)。
  3. 当一组数据,数据量不大且趋近于有序时,推荐使用插入排序更快
    在这里插入图片描述
public static void InsertSort(int[] arr){
        for(int i=1;i<arr.length;i++){
            int tmp=arr[i];
            int j=i-1;
            for(;j>=0;j--){
                if(arr[j]>tmp){
                    arr[j+1]=arr[j];
                }else{
                    break;
                }
            }
            arr[j+1]=tmp;
        }
    }

二、折半插入排序

  1. 时间复杂度:O(n²)。
  2. 空间复杂度:O(1)。
  3. 通过直接插入排序可以发现,每次比较时,i下标前的数据时有序的。
  4. 折半插入排序利用此特性将i下标的值与前面有序数据进行二分查找。
  5. 算是直接插入排序的一种优化。
    在这里插入图片描述
public static void HalveInsertSort(int[] arr){
        for(int i=1;i<arr.length;i++){
            int left=0;
            int right=i-1;
            int tmp=arr[i];
            while(right>=left){
                int mid=(left+right)/2;
                if(arr[mid]>tmp){
                    right=mid-1;
                }else{
                    left=mid+1;
                }
            }
            for(int j=i-1;j>right;j--){
                arr[j+1]=arr[j];
            }
            arr[right+1]=tmp;
        }
    }

三、希尔排序

  1. 时间复杂度:O(n1.3)。
  2. 空间复杂度:O(1)。
  3. 希尔排序的巧妙处与插入排序有异曲同工之处。
  4. 中心思想在于gap的取值,取值方法有很多中,但都大同小异,其余思想与插入排序无太大差别。
    在这里插入图片描述
public static void shellSort(int[] arr){
        int gap=arr.length;
        while(gap>0){
            mySort(arr,gap);
            gap/=2;
        }
    }
    public static void mySort(int[] arr,int gap){
        for(int i=gap;i<=arr.length;i++){
            int tmp=arr[i];
            int j=i-gap;
            for(;j>=0;j-=gap){
                if(arr[j]>tmp){
                    arr[j+gap]=arr[j];
                }else{
                    break;
                }
            }
            arr[j+gap]=tmp;
        }
    }

四、选择排序

  1. 时间复杂度:O(n²)。
  2. 空间复杂度:O(1)。
  3. 顾名思义,选择排序,选择好了再排序。
  4. 每次从数组中选择一个最大或最小的数据与头或尾交换。
  5. 再将交换后的边界缩小。
    在这里插入图片描述
public static void selectSort(int[] arr){
        for(int i=0;i<arr.length;i++){
            int max=0;
            for(int j=1;j<arr.length-i;j++){
                if(arr[j]>arr[max]){
                    max=j;
                }
            }
            int tmp=arr[max];
            arr[max]=arr[arr.length-1-i];
            arr[arr.length-1-i]=tmp;
        }
    }

五、双向选择排序

  1. 时间复杂度:O(n²)。
  2. 空间复杂度:O(1)。
  3. 与选择排序中心思想相同,这次是一次找出最大与最小同时交换
  4. 此算法中而每次取值的最小值下标有头下标交换时,如果头下标的位置刚好时是最大值,此时交换后max下标指向则不是最大值而是最小值,最后的if()判断很重要。
public static void TwoWaySelectSort(int[] arr){
        int left=0;
        int right=arr.length-1;
        while(left<=right){
            int min=left;
            int max=left;
            for(int i=left+1;i<=right;i++){
                if(arr[i]>arr[max]){
                    max=i;
                }
                if(arr[i]<arr[min]){
                    min=i;
                }
            }
            swap(arr,min,left);
            if(max==left){
                max=min;
            }
            swap(arr,max,right);
            left++;
            right--;
        }
    }

六、堆排序

  1. 时间复杂度:O(logn)。
  2. 空间复杂度:O(1)。
  3. 假设要排序升序,首先将数组变为大堆存储形式。
  4. 再循环从后向前把每个元素与0下标元素交换。
  5. 每次交换后都要进行一次大堆调整。
    在这里插入图片描述
public static void shiftDown(int[] arr,int parent,int len){
        int child=parent*2+1;
        while(child<len){
            if(child+1<len&&arr[child]<arr[child+1]){
                child++;
            }
            if(arr[child]>arr[parent]){
                swap(arr,child,parent);
                parent=child;
                child=parent*2+1;
            }else{
                break;
            }
        }
    }
    public static void MySort(int[] arr){
        for(int i=(arr.length-1)/2;i>=0;i--){
            shiftDown(arr,i,arr.length);
        }
    }
    public static void heapSort(int[] arr){
        MySort(arr);
        int end=arr.length-1;
        while(end>0){
            swap(arr,0,end);
            shiftDown(arr,0,end);
            end--;
        }
    }

七、冒泡排序

  1. 时间复杂度:O(n²)。
  2. 空间复杂度:O(1)。
  3. 两两比较,最终将数组最大元素放在最后位置。
  4. 调整边界,因上次循环结束后最后以为已是有序,每次比较长度-1。
  5. 若一次循环下来,没有任何数据交换,此时证明当前数据集已经有序,可以直接结束循环。
    在这里插入图片描述
public static void bubbleSort(int[] arr){
        for(int i=0;i<arr.length-1;i++){
            boolean bool=true;
            for(int j=0;j<arr.length-1-i;j++){
                if(arr[j+1]<arr[j]){
                    swap(arr,j+1,j);
                    bool=false;
                }
            }
            if(bool){
                break;
            }
        }
    }

八、快速排序(挖坑)

  1. 时间复杂度:O(logn)。
  2. 空间复杂度:O(logn)。
  3. 顾名思义,选择一个基准值,将小于基准值大放到基准值左,大于基准值放在右。
    在这里插入图片描述
public static int partition(int[] arr,int start,int end){
        int tmp=arr[start];
        while(start<end){
            while(start<end&&arr[end]>=tmp){
                end--;
            }
            arr[start]=arr[end];
            while(start<end&&arr[start]<=tmp){
                start++;
            }
            arr[end]=arr[start];
        }
        arr[start]=tmp;
        return start;
    }
    public static void quickSorts(int[] arr,int left,int right){
        if(left>=right){
            return;
        }
        int pivot=partition(arr,left,right);
        quickSorts(arr,left,pivot-1);
        quickSorts(arr,pivot+1,right);
    }
    public static void quickSort(int[] arr){
        quickSorts(arr,0,arr.length-1);
    }

九、快速排序(Hoare)

  1. 时间复杂度:O(logn)。
  2. 空间复杂度:O(logn)。
  3. 思想于挖坑法大致相同,此方法只是将每次的大于基准值与小于基准值同时交换。
public static int partition(int[] arr,int start,int end){
        int i=start;
        int j=end;
        int tmp=arr[i];
        while(i<j){
            while(i<j&&arr[j]>=tmp){
                j--;
            }
            while(i<j&&arr[i]<=tmp){
                i++;
            }
            swap(arr,i,j);
        }
        swap(arr, start,i);
        return i;
    }
    public static void quickSorts(int[] arr,int left,int right){
        if(left>=right){
            return;
        }
        int pivot=partition(arr,left,right);
        quickSorts(arr,left,pivot-1);
        quickSorts(arr,pivot+1,right);
    }
    public static void quickSort(int[] arr){
        quickSorts(arr,0,arr.length-1);
    }

十、快速排序(非递归)

  1. 时间复杂度:O(logn)。
  2. 空间复杂度:O(logn)。
  3. 非递归思想需要借助一个栈来记录基准值左右的下标。
  4. 代码运行流程与递归无太大差别。
public static int partition(int[] arr,int start,int end){
        int tmp=arr[start];
        while(start<end){
            while(start<end&&arr[end]>=tmp){
                end--;
            }
            arr[start]=arr[end];
            while(start<end&&arr[start]<=tmp){
                start++;
            }
            arr[end]=arr[start];
        }
        arr[start]=tmp;
        return start;
    }
    public static void quickSort(int[] arr){
        int left=0;
        int right=arr.length-1;
        Stack<Integer> stack=new Stack<>();
        int pivot=partition(arr,left,right);
        if(left+1<pivot){
            stack.add(left);
            stack.add(pivot-1);
        }
        if(right-1>pivot){
            stack.add(pivot+1);
            stack.add(right);
        }
        while(!stack.isEmpty()){
            right=stack.pop();
            left=stack.pop();
            pivot=partition(arr,left,right);
            if(left+1<pivot){
                stack.add(left);
                stack.add(pivot-1);
            }
            if(right-1>pivot){
                stack.add(pivot+1);
                stack.add(right);
            }
        }
    }

十一、归并排序(递归)

  1. 时间复杂度:O(n logn)。
  2. 空间复杂度:O(n)。
  3. 把一个大问题拆分成一个一个的小问题,把每一个小问题都排序好,再组合。
    在这里插入图片描述
public static void merge(int[] arr,int low,int mid,int high,int[] tmp){
        int i = 0;
        int j = low,k = mid+1; 
        while(j <= mid && k <= high){
            if(arr[j] < arr[k]){
                tmp[i++] = arr[j++];
            }else{
                tmp[i++] = arr[k++];
            }
        }
        while(j <= mid){
            tmp[i++] = arr[j++];
        }

        while(k <= high){
            tmp[i++] = arr[k++];
        }

        for(int t=0;t<i;t++){
            arr[low+t] = tmp[t];
        }
    }

    public static void mergeSort(int[] arr,int low,int high,int[] tmp){
        if(low<high){
            int mid = (low+high)/2;
            mergeSort(arr,low,mid,tmp);
            mergeSort(arr,mid+1,high,tmp); 
            merge(arr,low,mid,high,tmp);  
        }
    }

十二、归并排序(非递归)

  1. 时间复杂度:O(nlogn)。
  2. 空间复杂度:O(n)。
  3. 控制好边界就好。
public static void mergeSorts(int[] arr,int gap){
        int s1=0;
        int e1=s1+gap-1;
        int s2=e1+1;
        int e2=Math.min(arr.length-1,s2+gap-1);
        int[] tmp=new int[arr.length];
        int k=0;
        while(s2<arr.length){
            while(s1<=e1&&s2<=e2){
                if(arr[s1]<=arr[s2]){
                    tmp[k++]=arr[s1++];
                }else{
                    tmp[k++]=arr[s2++];
                }
            }
            while(s1<=e1){
                tmp[k++]=arr[s1++];
            }
            while(s2<=e2){
                tmp[k++]=arr[s2++];
            }
            s1=e2+1;
            e1=s1+gap-1;
            s2=e1+1;
            e2=Math.min(arr.length-1,s2+gap-1);
        }
        while(s1<=arr.length-1){
            tmp[k++]=arr[s1++];
        }
        for(int i=0;i<k;i++){
            arr[i]=tmp[i];
        }
    }
    public static void mergeSort(int[] arr){
        for(int gap=1;gap<arr.length;gap*=2){
            mergeSorts(arr,gap);
        }
    }
  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值