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

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

0.总览

一.插入排序

1.1直接插入排序

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

java 复制代码
    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;
        }
    }

测试:

java 复制代码
 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. .选择排序的代码非常简单,就类似于打擂台,给一个最大值,谁打赢了就是最大的,;
java 复制代码
    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)不断循环;

建堆

java 复制代码
    public static void creatHeap(int[] arr){

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

向下

java 复制代码
    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;
            }
        }
    }

堆排序

java 复制代码
//    堆排序
    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);
        }
    }

测试

java 复制代码
//        测试堆排序
        heapSort(arr);
        System.out.println(Arrays.toString(arr));

三.交换排序

3.1冒泡排序

时间复杂度:o(n2)

空间复杂度:o(1)

是否稳定:稳定

java 复制代码
//    冒泡排序
    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;
            }
        }
    }

测试

java 复制代码
        bubbleSort(arr);
        System.out.println(Arrays.toString(arr));

3.2快速排序

这个非常重要,至少在古法编程中是非常重要的;

1)先写快速排序的辅助方法,寻找基准值

2)根据基准值划分两个区间,然后递归的进行区分拆解;

3)基准值取最右边

java 复制代码
//    快速排序
    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;
    }

测试

java 复制代码
//        测试快速排序
        quickSort(arr);
        System.out.println(Arrays.toString(arr));
    }

3.3快速排序非递归实现

1)先将区间左右界限依次入栈;

2)找到基准值,把基准值的左右排好整体顺序

3)注意栈是后进先出,不然出入栈会出现问题

java 复制代码
//    非递归快速排序;
    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);
        }
    }

测试

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

四.归并排序

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

4.1归并排序

1)图解

手绘,可以看到先分出来,然后再往回归并,最后变得有序

1)找到中间值,进行区间划分,一直到最后不能分

2)运用递归不断划分区间

java 复制代码
// 归并排序
    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的数组

java 复制代码
   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);
               }
           }
   }
相关推荐
爱喝雪碧的可乐26 分钟前
MATLAB
开发语言·算法·matlab
叼烟扛炮1 小时前
Linux 学习笔记(六十):单线程的逆袭——epoll 高并发服务器实战
linux·服务器·网络·笔记·学习·算法
careathers2 小时前
【数据结构】基于比较的排序算法 - 交换排序
数据结构·算法·排序算法
文丑颜不良啊2 小时前
LeetCode2081~2100题目解析
java·leetcode
玖米GEO运营王总监2 小时前
2026年账号矩阵协同效应怎么量化:三个指标与公式结构
java·大数据·数据库
Rabitebla2 小时前
【Linux操作系统】进程篇(十一):进程程序替换——从底层原理到 exec 函数族
linux·服务器·c++·笔记·学习·算法
tellmewhoisi3 小时前
深度学习0:数学知识:正态分布1
人工智能·深度学习·算法
-梅3 小时前
算法(1) 动态规划
算法·动态规划
青少儿编程课堂3 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:Bellman-Ford与SPFA含负权最短路及负环检测全解析
c++·python·算法·bfs·信息学竞赛