排序之解

286 阅读2分钟

排序

image.png

冒泡排序

​  冒泡排序属于一种典型的交换排序。

  交换排序顾名思义就是通过元素的两两比较,判断是否符合要求,如过不符合就交换位置来达到排序的目的。冒泡排序名字的由来就是因为在交换过程中,类似水冒泡,小(大)的元素经过不断的交换由水底慢慢的浮到水的顶端。

​ 冒泡排序的思想就是利用的比较交换,利用循环将第 i 小或者大的元素归位,归位操作利用的是对 n 个元素中相邻的两个进行比较,如果顺序正确就不交换,如果顺序错误就进行位置的交换。通过重复的循环访问数组,直到没有可以交换的元素,那么整个排序就已经完成

解析:

  1. 最外层描述的是趟数

  2. 内层比较的是两两之间的值

    public static void sortData(int[] array){
        if(array == null || array.length == 0){
            return;
        }
        
        int temp;
        for(int i=0;i<array.length -1;i++){
            for(int j=0;j<array.length-1-i;j++){
                if(array[j+1] > array[j]){
                    temp = array[j+1];
                    array[j+1] = array[j];
                    array[j]=temp;
                }
            }
        }
        
        for(int k:array){
            System.out.println(k);
        }
    }
    

快速排序

快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。

快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。快速排序又是一种分而治之思想在排序算法上的典型应用。本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。

快速排序的名字起的是简单粗暴,因为一听到这个名字你就知道它存在的意义,就是快,而且效率高!它是处理大数据最快的排序算法之一了。虽然 Worst Case 的时间复杂度达到了 O(n²),但是人家就是优秀,在大多数情况下都比平均时间复杂度为 O(n logn) 的排序算法表现要更好。

public static int[] quickSort(int[] arr,int left,int right){
    if(left < right){
        int partition = partition(arr,left,right);
        partition(arr,left,partition -1);
        partition(arr,partition+1,right);
    }
}

public static int partition(int[] array,int left,int right){
    int pivot = left;
    int index = pivot + 1;
    for(int i=index;i<=right;i++){
        if(array[i] < array[pivot]){
            swap(array,i,index);
            index++;
        }
    }
    swap(array,pivot,index -1);
    return index -1;
}

private static void swap(int[] arr,int i,int j){
    int temp  = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

堆排序

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:

大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;

小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;

堆排序的平均时间复杂度为 Ο(nlogn)。

\1. 算法步骤

创建一个堆 H[0……n-1];

把堆首(最大值)和堆尾互换;

把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置;

重复步骤 2,直到堆的尺寸为 1。

private static void swap(int[] arr,int i,int j){
    int temp  = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

private void heapify(int[] arr, int i,int len){
    int left = 2*i +1;
    int right = 2*i+ 2;
    int largest = i;
    if(left <len && arr[left] > arr[largest]){
        largest = left;
    }
    
    if(right < len && arr[right] > arr[largest]){
        largest = right;
    }
    
    if(largest != i){
        swap(arr,i,largest );
        heapify(arr,largest,len);
    }
}

private void buildMaxHeap(int[] arr,int len){
    for(int i=(int)Math.floor(len/2);i>=0;i--){
        heapify(arr,i,len);
    }
}

public int[] heapSort(int[] sorce){
    int[] arr = Arrays.copyOf(sorce,sorce.length);
    int len = arr.length;
    buildMaxHeap(arr,len);
    for(int i = len -1;i>0;i--){
        swap(arr,0,i);
        len--;
        heapify(arr,0,len);
    }
    return arr;
}