成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

那些年數(shù)組的排序

chanthuang / 1229人閱讀

摘要:交換器兩個(gè)數(shù)組中的元素比較排序過(guò)程中,一定會(huì)有元素的交換操作。如果數(shù)組的長(zhǎng)度小于默認(rèn)值是的話(huà),再判斷,如果數(shù)組長(zhǎng)度小于值為的話(huà),那么就會(huì)用插入排序,否則就會(huì)使用雙軸快速排序?;睾辖Y(jié)束后,最后的元素是整個(gè)數(shù)組最大的數(shù)。

今天來(lái)回顧一下簡(jiǎn)單的排序思想,留作今后的復(fù)習(xí)和備份用。本篇是非常非常基礎(chǔ)的,甚至都不會(huì)講實(shí)際項(xiàng)目真正能用的排序方法,譬如雙軸快速排序 。寫(xiě)的不好請(qǐng)多多諒解。

想要解鎖更多新姿勢(shì)?請(qǐng)?jiān)L問(wèn)http://blog.tengshe789.tech/

準(zhǔn)備階段 相關(guān)功能函數(shù)

為了保持代碼的整潔,先創(chuàng)造好對(duì)數(shù)器和相關(guān)功能性函數(shù)。

交換器

兩個(gè)數(shù)組中的元素比較排序過(guò)程中,一定會(huì)有元素的交換操作。為了保持代碼的整潔,先寫(xiě)出交換操作的函數(shù)。

public static void swap(int[] arr, int i, int j) {
        arr[i] = arr[i] ^ arr[j];
        arr[j] = arr[i] ^ arr[j];
        arr[i] = arr[i] ^ arr[j];
    }
隨機(jī)樣本產(chǎn)生器

自己編數(shù)組太麻煩了,讓他自己生產(chǎn)吧

public static int[] generateRandomArray(int maxSize, int maxValue) {
        int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
        }
        return arr;
    }
對(duì)數(shù)器

對(duì)數(shù)器其實(shí)就是一個(gè)絕對(duì)正確但是復(fù)雜度不好的方法。

public static void comparator(int[] arr) {
        Arrays.sort(arr);
    }

說(shuō)說(shuō)Arrays.sort()的邏輯吧。數(shù)組進(jìn)入方法,先判斷。如果數(shù)組的長(zhǎng)度小于QUICKSORT_THRESHOLD(默認(rèn)值是286)的話(huà),再判斷,如果數(shù)組長(zhǎng)度小于INSERTION_SORT_THRESHOLD(值為47)的話(huà),那么就會(huì)用插入排序 ,否則就會(huì)使用雙軸快速排序。

如果大于286呢,它就會(huì)堅(jiān)持?jǐn)?shù)組的連續(xù)升序和連續(xù)降序性好不好,如果好的話(huà)就用歸并排序,不好的話(huà)就用快速排序。

比較器

比較兩個(gè)數(shù)組一不一樣~

public static boolean isEqual(int[] arr1, int[] arr2) {
        if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
            return false;
        }
        if (arr1 == null && arr2 == null) {
            return true;
        }
        if (arr1.length != arr2.length) {
            return false;
        }
        for (int i = 0; i < arr1.length; i++) {
            if (arr1[i] != arr2[i]) {
                return false;
            }
        }
        return true;
    }
打印器
public static void printArray(int[] arr) {
   if (arr == null) {
      return;
   }
   for (int i = 0; i < arr.length; i++) {
      System.out.print(arr[i] + " ");
   }
   System.out.println();
}
復(fù)制器
public static int[] copyArray(int[] arr) {
        if (arr == null) {
            return null;
        }
        int[] res = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            res[i] = arr[i];
        }
        return res;
    }
主函數(shù)
public static void main(String[] args) {
   int testTime = 500000;
   int maxSize = 100;
   int maxValue = 100;
   boolean succeed = true;
   for (int i = 0; i < testTime; i++) {
      int[] arr1 = generateRandomArray(maxSize, maxValue);
      int[] arr2 = copyArray(arr1);
      bubbleSort(arr1);
      comparator(arr2);
      if (!isEqual(arr1, arr2)) {
         succeed = false;
         break;
      }
   }
   System.out.println(succeed ? "牛逼,算法對(duì)了!" : "?!");

   int[] arr = generateRandomArray(maxSize, maxValue);
   printArray(arr);
   bubbleSort(arr);//測(cè)試的算法
   printArray(arr);
}
腦子

腦闊疼

正篇 基于比較的排序 冒泡排序 原理

冒泡排序算法的原理如下:

比較相鄰的元素。如果第一個(gè)比第二個(gè)大,就交換他們兩個(gè)。此時(shí)這兩個(gè)數(shù),永遠(yuǎn)是后面的數(shù)大。

第一回合將每一對(duì)相鄰元素做同樣的工作?;睾辖Y(jié)束后,最后的元素是整個(gè)數(shù)組最大的數(shù)。

第二回合...第n回合過(guò)程中,對(duì)除了最后一個(gè)元素重復(fù)以上的步驟。

實(shí)現(xiàn)
public static void bubbleSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        for (int end = arr.length - 1; end > 0; end--) {//end最后的數(shù)
            for (int i = 0; i < e; i++) {
                if (arr[i] > arr[i + 1]) {
                    swap(arr, i, i + 1);//交換
                }
            }
        }
    }
復(fù)雜度

時(shí)間復(fù)雜度:O(N2)

額外空間復(fù)雜度:O(1)

選擇排序 原理

1.第一回合,將指針指向第一個(gè)元素,將第一個(gè)元素和剩余的元素比較,最小的元素放到一號(hào)位置。

2.第二回合...第n回合過(guò)程中,指針加一。對(duì)除了第一個(gè)元素重復(fù)以上的步驟。

實(shí)現(xiàn)
public static void selectionSort(int[] arr) {
   if (arr == null || arr.length < 2) {
      return;
   }
   for (int i = 0; i < arr.length - 1; i++) {
      int minIndex = i;
      for (int j = i + 1; j < arr.length; j++) {
         minIndex = arr[j] < arr[minIndex] ? j : minIndex;
      }
      swap(arr, i, minIndex);
   }
}
復(fù)雜度

時(shí)間復(fù)雜度:O(N2)

額外空間復(fù)雜度:O(1)

插入排序的 原理

1.第一回合,比較第一個(gè)元素和第二個(gè)元素大小,大的放在第二個(gè)位置上

2.第二回合,將第三個(gè)元素與第二、第一個(gè)元素比較,大的放在第三個(gè)位置上

3.輪回

實(shí)現(xiàn)
public static void insertionSort(int[] arr) {
   if (arr == null || arr.length < 2) {
      return;
   }
   for (int i = 1; i < arr.length; i++) {
      for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
         swap(arr, j, j + 1);
      }
   }
}
復(fù)雜度

時(shí)間復(fù)雜度:O(N2)

額外空間復(fù)雜度:O(1)

堆排序

堆其實(shí)就是完全二叉樹(shù),看堆要首先知道大頂堆、小頂堆。

每個(gè)結(jié)點(diǎn)的值都大于或等于其左右孩子結(jié)點(diǎn)的值,稱(chēng)為大頂堆;或者每個(gè)結(jié)點(diǎn)的值都小于或等于其左右孩子結(jié)點(diǎn)的值,稱(chēng)為小頂堆。

大頂堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]

小頂堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]

2堆

原理

將待排序序列構(gòu)造成一個(gè)大頂堆(升序采用大頂堆,降序采用小頂堆),此時(shí),整個(gè)序列的最大值就是堆頂?shù)母?jié)點(diǎn)。將其與末尾元素進(jìn)行交換,此時(shí)末尾就為最大值。然后將剩余n-1個(gè)元素重新構(gòu)造成一個(gè)堆,這樣會(huì)得到n個(gè)元素的次小值。如此反復(fù)執(zhí)行,便能得到一個(gè)有序序列了

代碼
public static void heapSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        //0-i之間生成大根堆這種結(jié)構(gòu)
        for (int i = 0; i < arr.length; i++) {
            heapInsert(arr, i);
        }
        int size = arr.length;//定義數(shù)組大小,可以判斷是否越界
        swap(arr, 0, --size);
        while (size > 0) {
            heapify(arr, 0, size);
            swap(arr, 0, --size);
        }
    }
    //生成大根堆這種結(jié)構(gòu)
    public static void heapInsert(int[] arr, int index) {
        while (arr[index] > arr[(index - 1) / 2]) {//如果我這個(gè)節(jié)點(diǎn)比父節(jié)點(diǎn)大
            swap(arr, index, (index - 1) / 2);//交換
            index = (index - 1) / 2;//回到父位置繼續(xù)
        }
    }
    //將數(shù)值小的元素往下沉
    public static void heapify(int[] arr, int index, int size) {
        int left = index * 2 + 1;
        while (left < size) {//左孩子在堆上,沒(méi)越界
            int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;//找出左右孩子中最大的數(shù)
            largest = arr[largest] > arr[index] ? largest : index;//和父比較
            if (largest == index) {
                break;
            }
            swap(arr, largest, index);
            index = largest;//回到較大節(jié)點(diǎn)
            left = index * 2 + 1;
        }
    }
復(fù)雜度

如果只是建立堆的過(guò)程,時(shí)間復(fù)雜度為O(N)

時(shí)間復(fù)雜度O(N*logN)

額外空間復(fù)雜度O(1)

快速排序

快速排序不是一種穩(wěn)定的排序算法,也就是說(shuō),多個(gè)相同的值的相對(duì)位置也許會(huì)在算法結(jié)束時(shí)產(chǎn)生變動(dòng)。

假定在待排序的記錄序列中,存在多個(gè)具有相同的關(guān)鍵字的記錄,若經(jīng)過(guò)排序,這些記錄的相對(duì)次序保持不變,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,則稱(chēng)這種排序算法是穩(wěn)定的;否則稱(chēng)為不穩(wěn)定的。
原理

我先說(shuō)說(shuō)經(jīng)典快排的思路吧。

將數(shù)組分成兩部分,一部分是小于等于某個(gè)數(shù)的,一部分是大于等于某個(gè)數(shù)的。這兩部分初始指針在數(shù)組的左(L)右(R)兩頭,此時(shí)L和R分別是一個(gè)邊界點(diǎn)。

1.先定義less區(qū)域和more區(qū)域,代表比數(shù)組中某一個(gè)數(shù)更小更大的區(qū)域。初始less區(qū)域是L-1以左的部分,more區(qū)域是R以右的區(qū)域

1532425834921

2.第一回合,從數(shù)組左邊開(kāi)始。若L指針指的節(jié)點(diǎn)值小于某個(gè)數(shù)值,less區(qū)域向右移動(dòng)一個(gè)位置 swap(arr,++less,L++);,L節(jié)點(diǎn)位置+1準(zhǔn)備下一個(gè)回合;若它大于這個(gè)數(shù)值,more區(qū)域向左擴(kuò)張一格,然后將這個(gè)節(jié)點(diǎn)放到more區(qū)域swap(arr,--more,L++);,L節(jié)點(diǎn)位置+1準(zhǔn)備下一個(gè)回合;若他等于這個(gè)數(shù)值,什么也不管,只是L節(jié)點(diǎn)位置+1準(zhǔn)備下一個(gè)回合。

3.重復(fù)上述過(guò)程,得到了一個(gè)數(shù)組,他的L指針右邊時(shí)小于某個(gè)數(shù)的,R的右邊時(shí)大于某個(gè)數(shù)的。[L,R]這個(gè)區(qū)間是等于某個(gè)數(shù)的。

4.返回這個(gè)都是相同數(shù)的數(shù)組的左邊界、右邊界

5.不斷遞歸

經(jīng)典快排有一個(gè)弊端。左部分和右部分的規(guī)模不一樣或者有一個(gè)部分規(guī)模特別大,算法效率會(huì)變差。舉個(gè)栗子,如果我有個(gè)數(shù)組[1,1,3,4,7,6,1,2,1,5,1,7],我指定的某個(gè)數(shù)字是7,那么那么排序后就變成了[1,1,1,1,1,2,3,4,5,6,7],經(jīng)典快排結(jié)束后只搞定了一個(gè)一個(gè)區(qū)間(<7的區(qū)間),復(fù)雜度就從理想狀態(tài)下的O(N)變成了O(N2)

然后就有了改進(jìn)后的隨機(jī)快排。

隨機(jī)快排比經(jīng)典快排多了一個(gè)選隨機(jī)數(shù)的過(guò)程 swap(arr, L + (int) (Math.random() * (R - L + 1)), R);。就是隨機(jī)生成某個(gè)數(shù),這樣生成的區(qū)間雖然也會(huì)出現(xiàn)上述經(jīng)典快排的惡劣情況,但是此時(shí)的復(fù)雜度就從原來(lái)的惡劣事件變成了有概率惡劣事件,但總體期望是好的。這就變成了一個(gè)概率問(wèn)題。

代碼

以下為隨機(jī)快排

//隨機(jī)快速排序
    public static void quickSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        quickSort(arr, 0, arr.length - 1);
    }

    public static void quickSort(int[] arr,int L,int R){
        if (L arr[R]){
                swap(arr,--more,L++);
            }else{
                L++;
            }
        }
        swap(arr,more,R);
        return new int[]{less+1,more-1};
    }
復(fù)雜度

科學(xué)家數(shù)學(xué)證明,長(zhǎng)期期望的時(shí)間復(fù)雜度為O(logN*N)

快速排序可以做到穩(wěn)定性問(wèn)題,非常難,要知道的可以谷歌“01 stable sort” ,反正我不會(huì)。

歸并排序 原理

1.和上題一樣,先定義左邊界L右邊界R數(shù)組中,然后定義一個(gè)中間值mid = (r-l)/2

2.遞歸,在邊界內(nèi)部不斷的找中間值mid

實(shí)現(xiàn)
//歸并排序
public static void mergeSort(int[] arr){
    if (arr==null || arr.length <2){
        return;
    }
    mergeSort(arr,0,arr.length-1);
}

private static void mergeSort(int[] arr, int l, int r) {
    if (l == r){
        return;
    }
    int mid = l + ((r - l) >> 1); //(r-l)/2
    mergeSort(arr,l,mid);
    mergeSort(arr,mid+1,r);
    merge(arr, l, mid, r);
}
復(fù)雜度

時(shí)間復(fù)雜度O(N*logN)

額外空間復(fù)雜度O(N),歸并排序的額外空間復(fù)雜度可以變成O(1),但是非常難,我沒(méi)花時(shí)間研究,要知道的可以谷歌“歸并排序 內(nèi)部緩存法”

這里的時(shí)間復(fù)雜度怎么算出來(lái)的呢?有一個(gè)master定理

T(N) = a*T(N/b) + O(N^d)

其中 a >= 1 and b > 1 是常量,其表示的意義是n表示問(wèn)題的規(guī)模,a表示遞歸的次數(shù)也就是生成的子問(wèn)題數(shù),b表示每次遞歸是原來(lái)的1/b之一個(gè)規(guī)模。 如下:

1) log(b,a) > d -> 復(fù)雜度為O(N^log(b,a))

2) log(b,a) = d -> 復(fù)雜度為O(N^d * logN)

3) log(b,a) < d -> 復(fù)雜度為O(N^d)

這里,歸并排序中b=2,a=2.

非基于比較的排序

非基于比較的排序,與被排序的樣本的實(shí)際數(shù)據(jù)狀況很有關(guān)系,所以實(shí)際中并不經(jīng)常使用

桶排序 原理

1.找到一個(gè)數(shù)組中最大數(shù)的值

2.定義(最大數(shù)+1)個(gè)桶

3.將數(shù)組的數(shù)放到對(duì)應(yīng)編號(hào)相同的桶中,每放進(jìn)一個(gè)數(shù),桶里面的數(shù)值加一

4.依次從小輸出這個(gè)桶,桶里的元素出現(xiàn)幾次就輸出幾個(gè)桶的編號(hào)

代碼
// only for 0~200 value
    public static void bucketSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < arr.length; i++) {
            max = Math.max(max, arr[i]);
        }
        int[] bucket = new int[max + 1];
        for (int i = 0; i < arr.length; i++) {
            bucket[arr[i]]++;
        }
        int i = 0;
        for (int j = 0; j < bucket.length; j++) {
            while (bucket[j]-- > 0) {
                arr[i++] = j;
            }
        }
    }
復(fù)雜度

時(shí)間復(fù)雜度O(N)

額外空間復(fù)雜度O(N)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/76472.html

相關(guān)文章

  • 排序算法(Java)——那些面試常見(jiàn)排序算法

    摘要:下面會(huì)介紹的一種排序算法快速排序甚至被譽(yù)為世紀(jì)科學(xué)和工程領(lǐng)域的十大算法之一。我們將討論比較排序算法的理論基礎(chǔ)并中借若干排序算法和優(yōu)先隊(duì)列的應(yīng)用。為了展示初級(jí)排序算法性質(zhì)的價(jià)值,我們來(lái)看一下基于插入排序的快速的排序算法希爾排序。 前言   排序就是將一組對(duì)象按照某種邏輯順序重新排列的過(guò)程。比如信用卡賬單中的交易是按照日期排序的——這種排序很可能使用了某種排序算法。在計(jì)算時(shí)代早期,大家普遍...

    Harpsichord1207 評(píng)論0 收藏0
  • 那些,前端學(xué)習(xí)之路疑難雜癥(三):數(shù)組和Date一些梳理

    摘要:將指定的數(shù)字索引值轉(zhuǎn)換成字符串索引值變成,然后將其作為屬性名來(lái)用。返回一個(gè)由刪除元素組成的數(shù)組。該方法返回的數(shù)組元素是調(diào)用的數(shù)組的一個(gè)子集。使用的函數(shù)有四個(gè)參數(shù)初始值積累值數(shù)組元素元素索引數(shù)組本身。 前言 很多人在學(xué)習(xí)原生JS的過(guò)程中會(huì)遇到一些疑惑,比如在學(xué)習(xí)array時(shí),就很容易搞不清哪些方法會(huì)改變?cè)瓉?lái)數(shù)組,哪些方法不會(huì)改變?cè)瓉?lái)數(shù)組?再比如很多人會(huì)使用new Date()獲取時(shí)間,卻...

    xeblog 評(píng)論0 收藏0
  • Array.prototype.sort()方法到底是如何排序

    摘要:本文除了會(huì)帶大家了解一些方法后面簡(jiǎn)寫(xiě)為方法的基本定義和用法之外,還會(huì)探討一下方法到底是使用的什么排序算法。下面我們來(lái)看看方法到底是如何排序的。 ??本文除了會(huì)帶大家了解一些Array.prototypr.sort()方法(后面簡(jiǎn)寫(xiě)為sort()方法)的基本定義和用法之外,還會(huì)探討一下sort()方法到底是使用的什么排序算法。簡(jiǎn)單度娘了一下,網(wǎng)上的那些sort()方法詳解文章,大多只說(shuō)了...

    youkede 評(píng)論0 收藏0
  • JavaScript專(zhuān)題系列20篇正式完結(jié)!

    摘要:寫(xiě)在前面專(zhuān)題系列是我寫(xiě)的第二個(gè)系列,第一個(gè)系列是深入系列。專(zhuān)題系列自月日發(fā)布第一篇文章,到月日發(fā)布最后一篇,感謝各位朋友的收藏點(diǎn)贊,鼓勵(lì)指正。 寫(xiě)在前面 JavaScript 專(zhuān)題系列是我寫(xiě)的第二個(gè)系列,第一個(gè)系列是 JavaScript 深入系列。 JavaScript 專(zhuān)題系列共計(jì) 20 篇,主要研究日常開(kāi)發(fā)中一些功能點(diǎn)的實(shí)現(xiàn),比如防抖、節(jié)流、去重、類(lèi)型判斷、拷貝、最值、扁平、柯里...

    sixleaves 評(píng)論0 收藏0
  • 7月份前端資源分享

    摘要:更多資源請(qǐng)文章轉(zhuǎn)自月份前端資源分享的作用數(shù)組元素隨機(jī)化排序算法實(shí)現(xiàn)學(xué)習(xí)筆記數(shù)組隨機(jī)排序個(gè)變態(tài)題解析上個(gè)變態(tài)題解析下中的數(shù)字前端開(kāi)發(fā)筆記本過(guò)目不忘正則表達(dá)式聊一聊前端存儲(chǔ)那些事兒一鍵分享到各種寫(xiě)給剛?cè)腴T(mén)的前端工程師的前后端交互指南物聯(lián)網(wǎng)世界的 更多資源請(qǐng)Star:https://github.com/maidishike... 文章轉(zhuǎn)自:https://github.com/jsfr...

    pingan8787 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<