1. 程式人生 > >插入排序,歸併排序,快速排序的實現和速度比較(包含二分法查詢所有匹配元素)

插入排序,歸併排序,快速排序的實現和速度比較(包含二分法查詢所有匹配元素)

最近在學習排序演算法,實現後比較了花費時間情況,現在總結一下

插入排序的時間複雜度是O(n²),是一種很直觀的排序方式。歸併排序為O(nlogn),實現起來也比較簡單。快速排序平均時間複雜度也是O(nlogn),實現起來比歸併複雜一些。經過比較發現快速排序比歸併排序要快一些,大概一倍的時間,資料越大,效果越明顯。我嘗試用5000萬長度的隨機陣列成的陣列進行排序,歸併排序大概用了50s左右,期間出現過oom,比較消耗堆疊的空間,而快速排序則很穩定,實現的時候的不會額外建立陣列,全是在原陣列之上的操作,主要是swap操作,多次測試大概只用了20s左右的時間,也是5000萬長度的資料。然後做了簡單的二分查詢,實現了對排序陣列的指定的相等元素全部查找出來。

這是歸併排序花費的時間:


這是快速排序花費的時間


下面是具體程式碼實現:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class MergeSort {

    private static <T extends Comparable<? super T>> void mergeSort(T [] arr){

       // T [] tempArr= (T []) new Comparable[arr.length];

        mergeSort(arr, 0, arr.length - 1);

    }

    private static <T extends Comparable<? super T>> void mergeSort(T[] arr, int left, int right) {

        if (left < right){
            int mid = (left + right) / 2;
            mergeSort(arr, left, mid);
            mergeSort(arr, mid + 1, right);
            merge(arr, left, mid, right);
        }




    }

    private static <T extends Comparable<? super T>> void merge(T[] arr, int left, int mid, int rightEnd) {

        T [] temp = (T []) new Comparable[rightEnd - left + 1];
      //  System.out.println(temp);

        int leftEnd = mid;
        int right = mid + 1;
        int tempPos = 0;
        int numOfObj = rightEnd - left + 1;

        while(left <= leftEnd && right <= rightEnd){
            if (arr[left].compareTo(arr[right]) <= 0){
                temp[tempPos ++] = arr[left ++];
            }else {
                temp[tempPos ++] = arr[right ++];
            }
        }

        while (left <= leftEnd) {
            temp[tempPos++] = arr[left++];
        }

        while (right <= rightEnd) {
            temp[tempPos++] = arr[right++];
        }
       for (int i = numOfObj - 1; i >= 0;){
            arr[rightEnd--] = temp[i--];
        }
    }


    private static <T extends  Comparable<? super T>> void quickSort(T [] arr){
        quickSort(arr, 0, arr.length - 1);
    }

    private static <T extends  Comparable<? super T>> void quickSort(T[] arr, int start, int end) {
        if (end - start < 8) {
            insertSort(arr, start, end);
        } else {

            T key = prepQuickSort(arr, start, end);
            int leftIndex = start;
            int rightIndex = end - 1;
            for ( ; ;) {
                while (arr[++leftIndex].compareTo(key) < 0) { }
                while (arr[--rightIndex].compareTo(key) > 0) { }

                if (leftIndex > rightIndex) {
                    break;
                } else {
                    swapByReference(arr, leftIndex, rightIndex);
                }
            }
            swapByReference(arr, leftIndex, end - 1);

            quickSort(arr, start, leftIndex - 1);
            quickSort(arr, leftIndex + 1, end);
        }
    }

    private static <T extends  Comparable<? super T>> T prepQuickSort(T[] arr, int left, int right) {

        int mid = (left + right) / 2;
        if (arr[left].compareTo(arr[mid]) > 0)
            swapByReference(arr, left, mid);
        if (arr[left].compareTo(arr[right]) > 0)
            swapByReference(arr, left, right);
        if (arr[mid].compareTo(arr[right]) > 0)
            swapByReference(arr, mid, right);

        swapByReference(arr, mid, right - 1);
        return arr[right -1];
    }

    private static  <T extends  Comparable<? super T>> void insertSort(T[] arr) {
        insertSort(arr, 0, arr.length);
    }

    private static <T extends  Comparable<? super T>> void insertSort(T[] arr, int start, int end) {
        T min;
        int index;
        for (int i = start; i < end -1; i ++){
            min = arr[i];
            index = i;
            for (int j = i + 1; j < end; j++){
                if (min.compareTo(arr[j]) > 0){
                    min = arr[j];
                    index = j;
                }
            }
            swapByReference(arr, i, index);
        }

    }

    private static <T extends  Comparable<? super T>> void swapByReference(T[] arr, int before, int after) {
        if (before == after)
            return;
        else {
            T tmp;
            tmp = arr[before];
            arr[before] = arr[after];
            arr[after] = tmp;
        }

    }

    public static <T extends Comparable<? super T>> List binarySearch(T [] arr, T goal){

        if (arr == null || arr.length < 1 )
            return null;

        int left = 0;
        int right = arr.length -1;
        if (arr[left].compareTo(goal) > 0 || arr[right].compareTo(goal) < 0)
            return null;
        int mid = right / 2;

        while(left < right){
            if (arr[mid].compareTo(goal) == 0){
                List list = new ArrayList<Integer>();

                int eqLeft = getEqualsBound(arr, mid, false);
                int eqRight = getEqualsBound(arr, mid, true);

                for (int index = eqLeft; index <= eqRight; index ++){
                    list.add(index);
                }
                return list;

            } else if (arr[mid].compareTo(goal) > 0)
                right = mid - 1;
            else
                left = mid + 1;
            mid = (left + right) / 2;
        }
        return  null;
    }

    private static <T extends Comparable<? super T>> int getEqualsBound(T[] arr, int location, boolean sequence) {
        int result = location;
        if (sequence){
            while(arr[location].compareTo(arr[++result]) == 0){ }
            return result - 1;
        }else {
            while(arr[location].compareTo(arr[--result]) == 0){ }
            return result + 1;
        }
    }


    public static void main(String[] args) {

        Integer[] arr = {16,2,4,3,1,5,6,0,2,4,3,11,14,16,12,9,8,11,13,15,18,20,19,11,22,23,9,6,3,4,5,1,1,0,7,4,3,4,5,1,14,16};
        Integer[] arr1 = {2,2,2,2,2,2,2,2,2,2};

        List<Integer> list = new ArrayList<Integer>();
        Random random = new Random();
        for (int i= 0; i< 50000000; i++){
            list.add(random.nextInt(10000000));
        }
        Integer [] mkArr = list.toArray(new Integer[0]);

        long startTime = System.currentTimeMillis();
        System.out.println("start time is " + startTime + " ms");

        quickSort(mkArr);
        System.out.println("first node is " + mkArr[0] + " , mid node is " + mkArr[mkArr.length/2] + " , last node is " + mkArr[mkArr.length -1]);
        System.out.println(binarySearch(mkArr, 4000000));
        long stopTime = System.currentTimeMillis();
        System.out.println("end time is " + stopTime + " ms");
        System.out.println("cost time is " + (stopTime - startTime) + " ms");

    }

相關推薦

插入排序歸併排序快速排序實現速度比較包含二分查詢所有匹配元素

最近在學習排序演算法,實現後比較了花費時間情況,現在總結一下插入排序的時間複雜度是O(n²),是一種很直觀的排序方式。歸併排序為O(nlogn),實現起來也比較簡單。快速排序平均時間複雜度也是O(nlogn),實現起來比歸併複雜一些。經過比較發現快速排序比歸併排序要快一些,大

排序演算法整理:氣泡排序、堆排序插入排序歸併操作、快速排序、希爾排序、選擇排序

SortUtils.java package prms.utils.sort; import java.util.Arrays; /** * @ClassName: SortUtils * @Description: &lt;p&gt; 排序演算法 工具類 &l

元素中位數以及快速排序問題分治法問題

IBM最後有道求主元素的題目,一個數組有N個元素,其中有超過N/2的元素相同,請找出這個元素。時間複雜度為O(n) 方法1: 如果一個元素的個數超過N/2則這個元素必然是這N個元素的中位數。則這個題目是找中位數。方法是通過快速排序變化的來的演算法。 程式碼如下: #incl

氣泡排序選擇排序二分查詢圖示以及程式碼實現

氣泡排序 請看下面的這個栗子: 需要排序的陣列arr = {99,88,77,55,66,44}; 具體排序細節各位客官請看圖: 程式碼實現: public class BubbleSort { public static void main(String[] ar

高階排序演算法【2】--快速排序歸併排序、堆排序

4、快速排序 從數列中挑出一個元素,稱為基準;  重新排列數列,所有元素比基準小的擺放在基準前面,所有元素比基準大的擺在基準後面;  在這個分割槽結束之後,該基準就位於數列的中間位置;  遞迴地對基準左右兩邊的數列進行排序。 快速排序程式碼——第一步 def qui

常見的演算法:二分查詢氣泡排序選擇排序

今天主要說一下常見的演算法 ,於是我百度了一下點進那 “ 牛逼 ” 的知乎看了一眼 ,完蛋了 ,這都是些神馬 ??? 我怎麼一個都不會呢 ,我要的可是那種很常見的演算法啊 ,好吧 ,無形中又被深深的傷了一刀 ,好在我迅速調節狀態 。管他呢 ,我就按照自己 low

排序演算法02——插入排序(直接、折半)、快速排序

插入排序:插入排序的思路就是,前面的陣列已經有序(從第二個數看來,第一個數已經有序了,它只要找到自己的插入點插入就行了;然後第三個數看前兩個數都已經有序了....以此類推),下標為i的這個值依次與前面的值比較,找到合適的地方就可以直接插入了。但是,陣列的插入是需要插入位以後的

歸併排序包含逆序數對的個數51Nod1019

歸併排序是效率很好的排序方式,和快排效率一樣高,但在穩定性上優於快排,下面我們來介紹歸併排序。 歸併排序運用遞迴將序列不斷二分(其原理就是分治),就像一棵樹不斷向下分支,最後分到只剩一個元素,這樣這個元素就可當做有序的,因為只有一個元素嘛。然後是合併,怎麼分出來就怎麼合併回去,不過既然是排序,

PHP二分查詢快速排序、氣泡排序

二分法查詢: /* 遞迴呼叫實現二分法查詢 //$search 函式 $array為陣列,$K為要找的值,$low為查詢範圍的最小鍵值,$high為查詢範圍的最大鍵值 //intval返回整數值*/ function search($array,$k,$low=0,$high=0){

python中的冒泡、快速、堆排序二分查詢

    氣泡排序 它重複地走訪過要排序的元素列,依次比較兩個相鄰的元素,如果他們的順序(如從大到小、首字母從A到Z)錯誤就把他們交換過來。走訪元素的工作是重複地進行直到沒有相鄰元素需要交換,也就是說該元素已經排序完成。 第一種 def bubble_sort(

快速排序演算法原理及實現單軸快速排序、三向切分快速排序、雙軸快速排序

歡迎探討,如有錯誤敬請指正 1. 單軸快速排序的基本原理 快速排序的基本思想就是從一個數組中任意挑選一個元素(通常來說會選擇最左邊的元素)作為中軸元素,將剩下的元素以中軸元素作為比較的標準,將小於等於中軸元素的放到中軸元素的左邊,將大於中軸元素的放到中軸元素的右邊,然後以當前中軸元素的位置為界,將左半部分子

雙路快速排序演算法及三路快速排序演算法視覺化

雙路快速排序演算法 工具類 import java.awt.*; import java.awt.geom.Ellipse2D; import java.awt.geom.Rectangle2D; import java.lang.Interrup

五十道程式設計小題目 --- 28 八大排序演算法 java 之 06快速排序

6. 交換排序—快速排序(Quick Sort) 快速排序演算法介紹       快速排序和歸併排序都使用分治法來設計演算法,區別在於歸併排序把陣列分為兩個基本等長的子陣列,分別排好序之後還要進行歸併(Merge)操作,而快速排序拆分子陣列的時候顯得更有藝術,取一

排序演算法c語言描述-快速排序隨機化

今天在做資料結構排序實驗的時候,使用的快速排序。按理,我印象中快排是很高效的,不過,這次400w的資料,排了2659秒,有點意想不到,讓我一度懷疑了演算法是否寫錯了。 不過,認真分析,認真想想後, 也就釋然了。 快排其實就是冒泡的升級版。 每次遞迴,把當前序列分成兩部分,

資料結構 8 基礎排序演算法詳解、快速排序實現、瞭解分治法

## 快速排序 快速排序與氣泡排序一樣,同樣是屬於`交換排序` 叫做快速排序也是有原因的。因為它採用了**分治法的概念** ![image.png](https://file.chaobei.xyz/blogs/image_1588862421197.png_imagess) 其中最重要的一個概念就是

Java中陣列的補充方法增強版遍歷、逆序、氣泡排序二分查詢

陣列的補充方法 在《陣列》文章中簡單的介紹了陣列的基本格式和實現案例,此處不做說明,此文主要是補充一些陣列的使用方法。例如:增強版的遍歷、逆序、氣泡排序、二分法查詢。 增強版遍歷: 1.與普通遍歷的區別: 普通的遍歷給人的直觀感覺不是很好,輸出的元素都是排列不好看,所以需

常見排序演算法的基本原理、程式碼實現時間複雜度分析

  排序演算法無論是在實際應用還是在工作面試中,都扮演著十分重要的角色。最近剛好在學習演算法導論,所以在這裡對常見的一些排序演算法的基本原理、程式碼實現和時間複雜度分析做一些總結 ,也算是對自己知識的鞏固。 說明: 1.本文所有的結果均按照非降序排列; 2.本文所有的程式均用c++實現,

Java之陣列排序二分查詢

首先先介紹兩種最基本的陣列排序方法:冒泡法和選擇法。 冒泡法排序:依次比較相鄰的兩個元素,如果第一個比第二個大,則交換他們兩個,如此一輪比較下來會產生一個最大的數位於陣列末尾,第二次比較則進行到陣列長度-1個元素,以此類推。 /** *

如何使用雲效看板讓需求持續快速地流動交付

雲效看板支援看板方法標準實踐,幫助團隊更好的協作和管理交付過程。通過雲效看板功能可以幫助團隊: 更好地視覺化端到端價值(需求)流動,確保產品、開發、測試等職能的前後拉通; 支援任務按所屬模組或不同端展開為子列,確保不同模組或不同端任務向所屬的需求對齊;