六千字快速复习七种常用排序

Posted 只yao为你发光

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了六千字快速复习七种常用排序相关的知识,希望对你有一定的参考价值。

文章目录

一、插入排序

1.原理

 将整个区间分为两个区间:1.有序区间  2.无序区间,每次将无序区间的第一个元素,在有序区间的合适位置插入.

2.代码实现

   public static void insertSort(int[] array)
       //有序区间[0,i)
       //无序区间[i,array.length)
       for(int i = 1; i < array.length;i++)
           int v = array[i];//无序区间第一个数
           int j = i-1;//有序区间最后一个下标
           for(; j >= 0 && array[j] > v;j--)
               array[j+1] = array[j];
           
           //如果不交换此时下标在i-1
           array[j+1] = v;
       
   
时间复杂度为O(N^2) ;空间复杂度为O(1)
稳定性 : 稳定排序;  如果array[j] > v换成array[j] >=  v就变成不稳地的了.
特点: 1.数组越短,速度越快
      2.数组越接近有序,速度越快

二、希尔排序

1.原理

进阶版本的插入排序,先分组,再针对每个组进行排序,逐渐缩小组的个数,最终整个数组就有序了.

2.代码实现

    public static void shellSort(int[] arr)
        int gap = arr.length / 2;//将数组分为gap组
        while (gap > 1 )
        //传入组数和数组,带组数的插入排序
            insertSortGap(arr,gap);
            gap = gap / 2;
        
        insertSortGap(arr,1);
    

    private static void insertSortGap(int[] arr, int gap) 
    //[0,i)为已排序区间;[i,arr.length)为未排序区间
        for(int i = gap ;i < arr.length;i++)
            int v = arr[i];
            int cur = i - gap;
            for( ; cur >= 0&& arr[cur]> v ;cur -= gap)
                arr[cur+gap] = arr[cur];
            
            arr[cur + gap] = v;
        
    
时间复杂度为O(N^1.3);空间复杂度为O(1)
时间复杂度最好为O(N),最坏为O(N^2);
特点:插入排序的优化版
稳定性 : 不稳定排序

三、选择排序

1.原理

基于打擂台的方式:选数组首元素为擂主,循环遍历数组剩余元素,如果发现比擂主小的元素,就交换两个数.
遍历完成后让擂主加一,重复前面的动作.

2.代码实现

    public static void selectSort(int[] arr)
        for(int bound  = 0; bound < arr.length; bound++) 
            //bound 位置元素作为擂主,循环进行比较
            //如果打擂成功就和擂主交换
            for(int cur = bound + 1 ; cur < arr.length; cur++) 
                if(arr[bound] > arr[cur])
                    int tmp = arr[bound];
                    arr[bound] = arr[cur];
                    arr[cur] = tmp ;
                
            
        
    
时间复杂度:O(N^2) ;空间复杂度:O(1);
稳定性 : 不稳定排序

四、堆排序

1.原理

 升序排列:将数组建一个大堆,然后将堆顶元素和堆底元素交换,重新生成一个大堆,并且将堆的大小减一,每一次循环
 都会让数组的最后一个元素是较大者,重复这个过程就实现了堆排序.  数组就是升序.

2.代码实现

    public static void heapSort(int[] arr)
        //第一步先将传入的数组创建成一个大堆
        createHeap(arr);
        //循环将堆顶元素与堆底元素交换,并且调整堆
        //当堆中是剩一个元素的时候也就不用循环了,所以少循环一次 -1
        for(int i = 0 ;i < arr.length -1 ;i ++)
                //交换堆顶和堆底元素
            //堆顶下标为0 ;堆底下标为arr.length - i -1
            swap(arr , 0 ,arr.length - i -1 );
            //交换完成再进行向下调整堆; 让堆的大小每次小 1
            shiftDown(arr , arr.length - i -1 , 0 );
        
    

    private static void shiftDown(int[] arr, int heapLength, int index) 
        int parent = index;
        int child = 2 * parent + 1;
        while( child < heapLength)
            //判断parent左右子树较大者
            if( child + 1 < heapLength && arr[child + 1] > arr[child])
                child = child + 1;
            
            //判断孩子是否大于,如果大于交换,否则满足大堆直接break
            if( arr[child] > arr[parent])
                swap(arr, child ,parent);
            else
                break;
            
            parent = child;
            child = 2 * parent + 1;
        
    

    private static void createHeap(int[] arr) 
        int cur  = (arr.length - 1 - 1) / 2 ;
        for( int i = cur ; i >= 0 ;i--)
            shiftDown(arr, arr.length, i);
        
    

    private static void swap(int[] arr, int i, int j) 
        int tmp =  arr[i];
        arr[i] = arr[j];
        arr[j] = tmp ;
    
时间复杂度:O(N*log(N)) ;空间复杂度:O(1);
稳定性 : 不稳定排序

五、冒泡排序

1.原理

 升序排列:将一个无序的区间相邻进行比较,较大的放在后面,循环比较,一次循环可以把最大的放在数组最后,下一次
 循环可以将较大者放到次后位置,循环N次就得到了一个升序数组.

2.代码实现

    public static  void bubbleSort(int[] arr) 
        //循环 i 次
        for(int i = 0 ; i < arr.length ;i++) 
            //每循环一次会确定一个较大值
            //注意数组下标越界bound + 1 < arr.length - i
            for(int bound = 0 ;bound + 1 < arr.length - i ;bound++)
                if(arr[bound + 1] < arr[bound])
                    int tmp = arr[bound];
                    arr[bound] = arr[bound + 1];
                    arr[bound + 1 ] = tmp;
                
            
        
    

时间复杂度:O(N^2) ;空间复杂度:O(1);
稳定性 : 稳定排序

六、快速排序

1.原理

 升序排列:1.在待排数组中选取一个数作为基准值(一般选最左侧或最右侧作为基准值;
         2.比基准值大的放在基准值的右边,比基准值小的放在基准值的左边
         3.在递归排序基准值的左边,递归基准值的右边

2.代码实现

递归版本

    public static void quickSort(int[] arr) 
        //借助helper方法进行递归
        //为了代码简单设置成前闭后闭区间[left,right]
        quickSortHelper(arr ,0 ,arr.length - 1);

    

    private static void quickSortHelper(int[] arr, int left, int right) 
        //判断数组元素有几个,如果有0个或者1个就无需排序,直接return;
        if(left >= right)
            return ;
        
        //通过partition对数组进行分区左侧为小于基准值,右侧为大于基准值
        //index 为整理后left和right重合的位置
        int index = partition(arr ,left ,right);
        quickSortHelper(arr ,left , index - 1);
        quickSortHelper(arr , index + 1,right);
    

    private static int partition(int[] arr, int left, int right) 
        int i = left ;
        int j = right ;
        int base = arr[right];  //将数组最后一个元素设为基准值
        //left < right 说明数组还没判断完
        while( i < j)
            while ( i < j && arr[i] <= base)
                i++ ;
                //循环结束后,要么i和j重回,要么i下标是一个比base值大的数
            
            while ( i < j && arr[j] >= base)
                j-- ;
                //循环结束要么j和i重合,要么j下标是一个比base小的数
            
            //交换i和j下标的元素
            swap(arr,i ,j);
        
        //循环结束要将i或j(i和j此时在同一位置)位置的元素和right(基准值)元素进行交换
        swap(arr, i , right);
        //返回基准值位置
        return  i;
    
    
    private static void swap(int[] arr, int i, int j) 
        int tmp =  arr[i];
        arr[i] = arr[j];
        arr[j] = tmp ;
    
时间复杂度:O(N*log(N)) ;空间复杂度:O(log(N))主要是因为递归;
稳定性 : 不稳定排序

非递归版本

    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);
            //排序后的右区间[ index + 1 ,right]
            stack.push(right);
            stack.push(index + 1);
            //排序后的左区间[left ,index - 1]
            stack.push(index - 1);
            stack.push(left);
        
    
    
    private static int partition(int[] arr, int left, int right) 
        int i = left ;
        int j = right ;
        int base = arr[right];  //将数组最后一个元素设为基准值
        //left < right 说明数组还没判断完
        while( i < j)
            while ( i < j && arr[i] <= base)
                i++ ;
                //循环结束后,要么i和j重回,要么i下标是一个比base值大的数
            
            while ( i < j && arr[j] >= base)
                j-- ;
                //循环结束要么j和i重合,要么j下标是一个比base小的数
            
            //交换i和j下标的元素
            swap(arr,i ,j);
        
        //循环结束要将i或j(i和j此时在同一位置)位置的元素和right(基准值)元素进行交换
        swap(arr, i , right);
        //返回基准值位置
        return  i;
    

    private static void swap(int[] arr, int i, int j) 
        int tmp =  arr[i];
        arr[i] = arr[j];
        arr[j] = tmp ;
    
时间复杂度:O(N*log(N)) ;空间复杂度:O(log(N))
稳定性 : 不稳定排序

七、归并排序

1.原理

 升序排列:将数组分成若干个子数组,若子数组仅剩一个元素那么他就是有序的,然后将这些已有的子序列合并,得到
 一个有序的数列.而将两个有序表合成一个有序表就是"二路归并".

2.代码实现

递归实现

      public static void mergeSort(int[] arr)
        //创建一个helper方法帮助完成递归
        mergeSortHelper(arr ,0 ,arr.length);
    

    private static void mergeSortHelper(int[] arr, int low, int high) 
        if( high - low <= 1)
            return;
        
        //求出中间值
        int  mid = (low + high) / 2;
        //这个递归执行完 [low,mid)就已经排序好了
        mergeSortHelper(arr,low ,mid);
        //这个递归执行完[mid,high)就已经排序好了
        mergeSortHelper(arr,mid , high);
        //对[low, high)进行排序
        merge(arr ,low ,mid ,high);
    

    private static void merge(int[] arr, int low, int mid, int high) 
        int[] output = new int[high - low];
        int cur1 = low;
        int cur2 = mid;
        //记录output数组存放了多少元素
        int outputIndex = 0 ;
        while (cur1 < mid && cur2 < high)
            //这里写成 > 才能保证稳定性
            if(arr[cur1] > arr[cur2])
                output[outputIndex] = arr[cur2];
                outputIndex++;
                cur2 ++;
            else 
                output[outputIndex] = arr[cur1];
                outputIndex ++;
                cur1 ++;
            
        
        //上面循环结束不是cur1到mid就是cur2到high
        //再写两个循环将剩余的元素写入output数组中
        while (cur1 < mid)
            output[outputIndex] = arr[cur1];
            outputIndex ++;
            cur1 ++;
        
        while (cur2 < high)
            output[outputIndex] = arr[cur2];
            outputIndex ++;
            cur2 ++;
        
        //将output数组中的元素放回arr数组
        for(int i = 0 ;i < high - low ;i ++)
            arr[low + i ] = output[ i];
        
    

非递归实现

    public static void mergeSortByLoop(int[] arr) 
       //定义一个gap变量进行分组
        for (int gap = 1 ; gap < arr.length;gap *= 2)
            for(int i = 0 ;i < arr.length ;i = i + 2 * gap)
                int low = i ;
                int mid = i + gap;
                int high = i  + 2* gap;
                if(mid > arr.length)
                    mid  = arr.length;
                
                if(high > arr.length)
                    high = arr.length;
                
                merge(arr , low , mid ,high);
            
        
    

    private static void merge(int[] arr, int low, int mid, int high) 
        int[] output = new int[high - low];
        int cur1 = low;
        int cur2 = mid;
        //记录output数组存放了多少元素
        int outputIndex = 0 ;
        while (cur1 < mid && cur2 < high)
            //这里写成 > 才能保证稳定性
            if(arr[cur1] > arr[cur2])
                output[outputIndex] = arr[cur2];
                outputIndex++;
                cur2 ++;
            else 
                output[outputIndex] = arr[cur1];
                outputIndex ++;
                cur1 ++;
            
        
        //上面循环结束不是cur1到mid就是cur2到high
        //再写两个循环将剩余的元素写入output数组中
        while (cur1 < mid)
            output[outputIndex] = arr[cur1];
            outputIndex ++;
            cur1 ++;
        
        while (cur2 < high)
            output[outputIndex] = arr[cur2];
            outputIndex ++;
            cur2 ++;
        
        //将output数组中的元素放回arr数组
        for(int i = 0 ;i < high - low ;i ++)
            arr[low 以上是关于六千字快速复习七种常用排序的主要内容,如果未能解决你的问题,请参考以下文章

2021-10-21java:六千字快速复习七种常用排序

常用排序方法之快速排序

iOS:常用排序算法

快速排序

Java中常见的排序方式-快速排序(升序)

经典排序算法--快速排序