经典七大排序算法

首先排序分为四种:

  交换排序: 包括冒泡排序,快速排序。

  选择排序: 包括直接选择排序,堆排序。

  插入排序: 包括直接插入排序,希尔排序。

  归并排序: 归并排序。

(一) 冒泡排序

冒泡排序的基本思想是,对相邻的元素进行两两比较,顺序相反则进行交换,这样,每一趟会将最小或最大的元素“浮”到顶端,最终达到完全有序。时间复杂度为==O(n^2)==。

 /**
     * 冒泡排序
     *
     * @param arr
     */
    public static void bubbleSort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            boolean flag = true;//设定一个标记,若为true,则表示此次循环没有进行交换,也就是待排序列已经有序,排序已然完成。
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    swap(arr,j,j+1);
                    flag = false;
                }
            }
            if (flag) {
                break;
            }
        }
    }

(二)插入排序

想想扑克牌就很好理解了。时间复杂度为==O(n^2)==

Java代码实现

public static void insertSort(int[] A){

        for(int right = 1;right < A.length;right++){
            int temp = A[right];
            int left = right-1;
            while(left >= 0 && A[left]>temp){
                A[left+1] = A[left]; 
                left--;
            }
            A[left+1] = temp;
        }
    }

复杂度分析

①插入排序的时间复杂度 就是判断比较次数有多少,而比较次数与 待排数组的初始顺序有关,当待排数组有序时,没有移动操作(第8行for不成立),此时复杂度为O(N),当待排数组是逆序时,比较次数达到最大–对于下标 i 处的元素,需要比较 i-1 次。总的比较次数:1+2+…+N-1 ,故时间复杂度为==O(n^2)==
①可以看出,算法中只用到了一个临时变量(第6行),故空间复杂度为O(1)

(三)归并排序

思想
分解:分解待排序的n个元素的序列成n/2个元素的两个子序列
解决:使用归并排序递归地排序两个子序列
合并:合并两个已经排序好地子序列为一个序列 产生答案

     public static int[] mergeSort(int[] A ,int left,int right){
            if(left < right){
                int mid = left + (right - left)/2;

                //分
                mergeSort(A,left,mid);
                mergeSort(A,mid+1,right);

                //合并
                mergeGetArray(A,left,mid,right);
            }
            return A;
        }

     public static void mergeGetArray(int[] A,int left,int mid,int right){
            int[] TempRes = new int[right-left+1];
            int i = left,j = mid +1;
            int k = 0;

            while(i <= mid && j <= right){
                if(A[i]<A[j]){
                    TempRes[k++] = A[i++];

                }else{
                    TempRes[k++] = A[j++];
                }
            }    

            while(i <= mid){
                TempRes[k++] = A[i++];
            }

            while(j <= right){
                TempRes[k++] = A[j++];
            }

            for(i = 0;i < TempRes.length;i++){
                A[left+i] = TempRes[i];
            }
     }

(四)堆排序

 堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为==O(nlogn)==,它也是不稳定排序。

思想:
将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了

代码实现
维护堆的性质的函数

//维护堆的性质的函数,根据大小来调整某个结点以及它的孩子结点的位置
MAX_HEAPIFY(A,i){
 left = 2i+1;  //左孩子
 right = 2i+2 ; //右孩子

 //以下为判断结点以及它的孩子结点哪个最大,孩子结点比父节点大则调整二者位置
 if( A[left] <= A.heap-size and A[Left]>A[i])
      largest = Left;
else largest = i;

 if( A[right] <= A.heap-size and A[right]>A[largest])
      largest = r;

if( largets != i)
{
    exchage A[i] with A[largest]
    MAX_HEAPIFY(A,largest)
}
}

构建堆的函数

//构建堆的函数
BUID-HEAP(A){
    A.heap-size = A.length;
    for(int i = A.length/2-1;i>=0;i++){
            MAX-HEAPIFY(A,i);//从最后一个非叶子结点开始调整,直到根节点的index为0
    }
}

有了前面的铺垫,我们可以很容易写出堆排序

堆排序:
HEAP-SORT(A){
    BUID-HEAP(A)  //构建堆
    for(int i = A.length-1;A>=0;A--){
        exchange A[0] with A[i]  //每次将堆的顶端也就是最大值放在数组最后边
        A.heap-size = A.heap-size -1
        MAX-HEAPIFY(A,1)   //维护堆
    }
}
 ```
### (五)快速排序
在平均状况下,排序 n 个项目要==Ο(n log n)== 次比较。在最坏状况下则需要Ο(n^2)次比较,但这种状况并不常见。
快速排序使用分治法(Divide and conquer)策略(归并排序也是分治法)来把一个串行(list)分为两个子串行(sub-lists)。是冒泡排序的改进型.

**算法步骤:**
1.  首先在数组中选择一个基准点(该基准点的选取可能影响快速排序的效率,后面讲解选取的方法)

2.  重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。

``` java
    public static void QuickSort(int[] arr,int low,int high){

        while(low < high){
            int mid = Division(arr,low,high);
            QuickSort(arr,low,mid-1);
            QuickSort(arr,mid+1,high);
        }

    }



    private static int Division(int[] arr,int low,int high) {

        //选择一个基准数,一次循环将其放到属于它的位置
        int temp = arr[low];

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

        return low;
    }




<div class="se-preview-section-delimiter"></div>

注意:快速排序在序列中元素很少时,效率将比较低,不然插入排序,因此一般在序列中元素很少时使用插入排序,这样可以提高整体效率。

(六)直接选择排序

直接选择排序最类似于人的本能思想,比如把大小不一的玩具让三岁小毛孩对大小排个序,那小孩首先会在这么多玩具中找到最小的放在第一位,然后找到次小的放在第二位,以此类推。。。。。。

public static void SelectSort(int[] arr){

        for(int i = 0;i<arr.length-1;i++){

            int Index = i;

            for(int j = i+1;j<arr.length;j++){

                if(arr[Index]>arr[j])
                    Index = j;
            }
            //swap arr[i] with arr[Index]
            int temp = arr[i];
            arr[i] = arr[Index];
            arr[Index] = temp;
        }
    }




<div class="se-preview-section-delimiter"></div>

(七)希尔排序

希尔是插入排序的改进版。 如果当数据是”5, 4, 3, 2, 1“的时候,此时我们将“无序块”中的记录插入到“有序块”时,估计俺们要崩盘,
shell根据这个弱点进行了算法改进,融入了一种叫做“==缩小增量排序法==”的思想。

首先要明确一下增量的取法:

  第一次增量的取法为: d=count/2;

  第二次增量的取法为:  d=(count/2)/2;

  最后一直到: d=1;
public static void shellSort(int[] arr){
        int j = 0;
        int temp = 0;

        for(int incre = arr.length/2 ; incre>0 ;incre /= 2){

            for(int i = incre; i < arr.length;i++){
                temp = arr[i];          
                for(j = i-incre; j >= 0 ; j -= incre){

                    if(temp < arr[j]){
                        arr[j + incre] = arr[j];
                    }else{
                        break;
                    }
                }
                arr[j + incre] = temp;
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/github_38687585/article/details/79920420