十大基礎排序算法-scala編寫

1、前言

最近補了一下《數據結構與算法》的相關知識,這裏記錄一下常見的十大排序算法。因爲最近自己在學習scala,所以下面都是使用的scala進行編程,其與java語法有很多類似,保留了java的面向對象編程,同時擁有函數式編程。
(用什麼語言都一樣,算法思路對就行。)

2、排序

2.1、排序分類

根據在排序的過程中待排序的記錄是否全部被放置在內存中,排序分爲:內排序和外排序

其中,內排序是在排序的整個過程中,待排序的所有記錄全部被放置在內存中。外排序是由於排序的次數個數太多,不能同時放置在內存中,整個排序過程需要在內外存之間多次交換數據才能進行。

根據內排序過程中藉助的主要操作,我們把內排序分爲:插入排序、交換排序、選擇排序、歸併排序。

常見的內排序有:

  • 冒泡排序

  • 選擇排序

  • 插入排序

  • 希爾排序

  • 歸併排序

  • 快速排序

  • 堆排序

  • 計數排序

  • 桶排序

  • 基數排序

2.2、影響因素

對於內排序來說,排序算法的性能主要是受3個方面影響:

  1. 時間性能
    排序是數據處理中經常執行的一種操作,往往屬於系統的核心部分,因此排序算法的時間開銷是衡量其好壞的最重要的標誌。在內排序中,主要進行兩種操作:比較和移動。比較是指關鍵字之間的比較,這是要做排序最起碼的操作。移動是指記錄從一個位置移動到另外一個位置,事實上,移動也可以通過改變記錄的存儲方式來予以避免。總之,高效率的內排序算法應該是具有儘可能少的關鍵字比較次數和儘可能少的記錄移動次數。

  2. 輔助空間
    評價排序算法的另外一個主要的標準是執行算法所需要的輔助存儲空間。輔助存儲空間使除了存放待排序所佔有的存儲空間之外,執行算法所需要的其他的存儲空間。

  3. 算法的複雜性
    這裏指的是算法本身的複雜度,而不是指算法的時間複雜度。顯然算法過於複雜也會影響排序的性能。

3、冒泡排序

冒泡排序是一種簡單直觀的排序算法。其是一種交換排序,它的基本思想是:兩兩比較相鄰記錄的關鍵字,如果反序則交換,直到沒有反序的記錄爲止。

  • 冒泡排序算法
import com.zhangyue.impls.IArraySort

import scala.util.Random

/**
  * 冒泡排序:
  * 比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
  * 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。這步做完後,最後的元素會是最大的數。
  * 針對所有的元素重複以上的步驟,除了最後一個。
  * 持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。
  */
class BubbleSort extends IArraySort {
  override def sort(sourceArray: Array[Integer]): Array[Integer] = {
    var flag : Boolean = true //此處的flag主要是優化代碼,防止某次循環發現數組中都已經排好序,而再次進行沒必要的循環
    for (i <- 1 until sourceArray.length if !flag) {
      flag = false
      for (j <- sourceArray.length until i) {  //此處從後往前,也可以從前往後,方式很多
        if (sourceArray(j) < sourceArray(j-1)) {
          val temp : Integer = sourceArray(j)
          sourceArray(j) = sourceArray(j-1)
          sourceArray(j-1) = temp
          flag = true
        }
      }
    }
    sourceArray  //此處等同於return sourceArray
  }
}
object BubbleSort {
  def main(args: Array[String]): Unit = {
    val array = new Array[Integer](10)
    val random = new Random()
    for (i <- 0 to 9) {
      array(i) = random.nextInt(100)
    }
    val bubbleSort = new BubbleSort
    val resultArray : Array[Integer] = bubbleSort.sort(array)
    resultArray.map(println)
  }
}

補充:

  1. 當然,上面這個,也可以設置一個指針,指向數組最後已經排好序的下標,這樣可以省去已經排好序的再重複比較。
  2. 也可以內循環從後往前比較,將小的數字往前放。只要思想對,方式很多種。

4、選擇排序

選擇排序是一種簡單直觀的排序算法,無論什麼數據進去都是O(n2)的時間複雜度。它的基本思想是:通過 n-1 次的關鍵字間的比較,從 n-i+1 個記錄中選出關鍵字最小的記錄,並和第 i 個記錄交換之。

  • 選擇排序
import com.zhangyue.impls.IArraySort

import scala.util.Random

/**
  * 選擇排序:
  * 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
  * 再從剩餘未排序元素中繼續尋找最小(大)元素,然後放到已排序序列的末尾。
  * 重複第二步,直到所有元素均排序完畢。
  */
class SelectionSort extends IArraySort {
   override def sort(sourceArray: Array[Integer]): Array[Integer] = {
    //n-1次循環
    for (i <- 0 until (sourceArray.length - 1 )) {
      //設置最小的數的下標爲min,初始爲i
      var min : Integer = i
      for (j <- i until sourceArray.length ) {
        if (sourceArray(j) < sourceArray(min)) {
          //當下標爲j的數值比min的數值大時候,將min變成j
          min = j
        }
      }
      //此處當min 不等於 i 的時候,說明 最小的數 不是 i,故將 i 與min 對應的數值交換
      if (min != i) {
        val temp : Integer = sourceArray(min)
        sourceArray(min) = sourceArray(i)
        sourceArray(i) = temp
      }
    }
    sourceArray
  }
}
object SelectionSort {
  def main(args: Array[String]): Unit = {
    val array = new Array[Integer](10)
    val random = new Random()
    for (i <- 0 to 9) {
      array(i) = random.nextInt(100)
    }
    val selectionSort = new SelectionSort
    val resultArray : Array[Integer] = selectionSort.sort(array)
    resultArray.map(println)
  }
}

5、插入排序

插入排序是一種最簡單直觀的排序算法,它的工作原理:通過構建有序序列,對於未排序數據,在已經排好序的序列從後往前掃描,找到相應的位置,將此位置與後面位置上面的數值往後移動一位,將此數值插入到序列中。

  • 插入排序
import scala.util.Random

/**
  * 插入排序:
  * 將第一待排序序列第一個元素看做一個有序序列,把第二個元素到最後一個元素當成是未排序序列。
  * 從頭到尾依次掃描未排序序列,將掃描到的每個元素插入有序序列的適當位置。
  * (如果待插入的元素與有序序列中的某個元素相等,則將待插入元素插入到相等元素的後面。)
  */
class InsertionSort extends IArraySort{
  override def sort(sourceArray: Array[Integer]): Array[Integer] = {
    // 從下標爲1的元素開始選擇合適的位置插入,因爲下標爲0的只有一個元素,默認是有序的
    for (i <- 1 until sourceArray.length) {

      //記錄要插入的數據
      var temp : Integer = sourceArray(i)

      //從已經排序的序列最右邊的開始比較,找到比temp小的數
      var j : Integer = i
      while (j>0 && temp<sourceArray(j-1) ) {
        //將比temp小的數都向右移動一位
        sourceArray(j) = sourceArray(j-1)
        j-=1
      }
      //存在比temp小的數,插入
      if (j != i) {
        sourceArray(j) = temp
      }
    }
    sourceArray
  }
}
object InsertionSort {
  def main(args: Array[String]): Unit = {
    val array = new Array[Integer](10)
    val random = new Random()
    for (i <- 0 to 9) {
      array(i) = random.nextInt(100)
    }
    val insertionSort = new InsertionSort
    val resultArray : Array[Integer] = insertionSort.sort(array)
    resultArray.map(println)
  }
}

6、希爾排序

希爾排序,也可以稱爲遞減增量排序算法,是插入排序的一種更高效的改進算法。但希爾排序本身也是非穩定算法。

希爾排序是基於插入排序的一下兩個性質而提出改進方法的:

  • 插入排序在對幾乎已經排好序的數據操作時候,效率非常高,即可以達到線性排序的效果
  • 但插入排序一般來說是低效的,因爲插入排序每次只能講數據移動一位

希爾排序的基本思想:先將整個待排序的記錄序列分割成爲若干子序列分別進行直接插入排序,待整個序列中的記錄"基本有序"時,再對全體記錄進行依次直接插入排序。

  • 希爾排序
import com.zhangyue.impls.IArraySort

import scala.util.Random

/**
  * 希爾排序:
  * 選擇一個增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;
  * 按增量序列個數 k,對序列進行 k 趟排序;
  * 每趟排序,根據對應的增量 ti,將待排序列分割成若干長度爲 m 的子序列,分別對各子表進行直接插入排序。僅增量因子爲 1 時,整個序列作爲一個表來處理,表長度即爲整個序列的長度。
  */
class ShellSort extends IArraySort{
   override def sort(sourceArray: Array[Integer]): Array[Integer] = {
    var gap : Integer = 1	//此處的初始gap可以自己決定,包括gap遞減算法,可以一開始就設置爲序列的長度 + 1
    while (gap < sourceArray.length) {
      gap = gap * 3 + 1
    }
    while (gap > 0) {
      var i : Integer = gap
      while (i < sourceArray.length) {
        val insertValue : Integer = sourceArray(i)
        var j : Integer = i - gap
        while (j >= 0 && insertValue < sourceArray(j)) {
          sourceArray(j+gap) = sourceArray(j)
          j -= gap
        }
        if (j != i-gap) {
          //此處需要加1,因爲在上面的while循環中,最後一次循環出來之前j-gap,但是此位置的j實際上面沒有做數據移動操作
          //故,最後一次移動的位置是沒有-gap的j的位置,也就是j+gap位置上面
          sourceArray(j+gap) = insertValue
        }
        i+=1
      }
      gap = Math.floor(gap/3).toInt
    }
    sourceArray
  }
}
object ShellSort {
  def main(args: Array[String]): Unit = {
    val array = new Array[Integer](10)
    val random = new Random()
    for (i <- 0 to 9) {
      array(i) = random.nextInt(100)
    }
    val shellSort = new ShellSort
    val resultArray : Array[Integer] = shellSort.sort(array)
    println("===========================")
    resultArray.map(println)
  }
}

7、歸併排序

歸併排序是建立在歸併操作上面的一種有效的排序算法。該算法是採用分治法的一個非常典型的應用。此處我們採用遞歸的方式描述歸併排序。
歸併排序的基本思想:假設初始序列有 n 個記錄,則可以看成是 n 個有序的子序列,每個子序列的長度爲 1,之後兩兩合併,得到一系列有2個記錄的有序序列(可能多出一個未配對,也算在內),之後繼續兩兩合併,得到每個有序序列有4個記錄,之後一直合併到只有一個有序序列。

  • 歸併排序
import com.zhangyue.impls.IArraySort

import scala.util.Random

/**
  * 歸併排序:
  * 申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列;
  * 設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置;
  * 比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置;
  * 重複步驟 3 直到某一指針達到序列尾;
  * 將另一序列剩下的所有元素直接複製到合併序列尾。
  */
class MergeSort extends IArraySort{
  override def sort(sourceArray: Array[Integer]): Array[Integer] = {
    if (sourceArray.length < 2) {
      return sourceArray
    }
    var middle : Integer = Math.floor(sourceArray.length / 2).toInt
    import java.util.Arrays
    var left : Array[Integer] = Arrays.copyOfRange(sourceArray,0,middle)
    var right : Array[Integer] = Arrays.copyOfRange(sourceArray,middle,sourceArray.length)
    //此處遞歸調用sort和
    return merge(sort(left),sort(right))
  }

  private def merge(leftArray : Array[Integer],rightArray : Array[Integer]): Array[Integer] = {
    var left : Array[Integer] = leftArray
    var right : Array[Integer] = rightArray
    val result = new Array[Integer](left.length + right.length)

    var i = 0
    while (left.length > 0 && right.length > 0) {
      if (left(0) <= right(0)) {
        result(i) = left(0)
        import java.util.Arrays
        left = Arrays.copyOfRange(left,1,left.length)
        i+=1
      } else {
        result(i) = right(0)
        i+=1
        import java.util.Arrays
        right = Arrays.copyOfRange(right,1,right.length)
      }
    }
    while (left.length > 0) {
      result(i) = left(0)
      i += 1
      import java.util.Arrays
      left = Arrays.copyOfRange(left,1,left.length)
    }
    while (right.length > 0) {
      result(i) = right(0)
      i += 1
      import java.util.Arrays
      right = Arrays.copyOfRange(right,1,right.length)
    }
    result
  }
}
object MergeSort {
  def main(args: Array[String]): Unit = {
    val array = new Array[Integer](10)
    val random = new Random()
    for (i <- 0 to 9) {
      array(i) = random.nextInt(100)
    }
    val mergeSort = new MergeSort
    val resultArray : Array[Integer] = mergeSort.sort(array)
    println("===========================================================================================================")
    resultArray.map(println)
  }
}

8、快速排序

快速排序的基本思想:通過一趟排序將待排序記錄分割成獨立的兩個部分,其中一部分記錄的關鍵字均比另外一部分記錄的關鍵字小,則可分別對這兩部分記錄繼續進行排序,以達到整個序列有序的目的。

  • 快速排序
import com.zhangyue.impls.IArraySort

import scala.util.Random

/**
  * 快速排序:
  * 從數列中挑出一個元素,稱爲 "基準"(pivot);
  * 重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。在這個分區退出之後,該基準就處於數列的中間位置。這個稱爲分區(partition)操作;
  * 遞歸地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序;
  */
class QuickSort extends IArraySort{
override def sort(sourceArray: Array[Integer]): Array[Integer] = {
    return quick(sourceArray,0,sourceArray.length-1)
  }

  private def quick(sourceArray : Array[Integer],left : Integer,right : Integer): Array[Integer] = {
    if (left < right) {
      val partitionIndex : Integer = partition(sourceArray,left,right)
      quick(sourceArray,left,partitionIndex-1)
      quick(sourceArray,partitionIndex+1,right)
    }
    sourceArray
  }

  private def partition(sourceArray : Array[Integer],left : Integer,right : Integer) : Integer = {
    threePivot(sourceArray,left,right)
    val pivot : Integer = left
    var index : Integer = pivot + 1
    var i : Integer = index
    while (i <= right) {
      if (sourceArray(i) < sourceArray(pivot)) {
        swap(sourceArray,i,index)
        index += 1
      }
      i += 1
    }
    //此處需要減1,因爲上面的while循環最後一次進入if中的時候,將index+1,但是此位置實際上面沒有進行任何操作,
    //實際操作的位置在index-1
    swap(sourceArray,pivot,index-1)
    index - 1
  }

  private def threePivot(sourceArray : Array[Integer],left : Integer,right : Integer) : Unit = {
    val middle : Integer = Math.floor(left + (right - left)/2).toInt

    //比較最左邊和最右邊,將兩者比較大的放在right中
    if (sourceArray(left) > sourceArray(right)) {
      swap(sourceArray,left,right)
    }
    //比較中間和最右邊的,將比較大的放在right中,那麼right中的就是三者中間最大的一個
    if (sourceArray(middle) > sourceArray(right)) {
      swap(sourceArray,middle,right)
    }
    //比較最左邊和中間的,將比較大的放在左邊,那麼中間值就放在了最左邊
    if (sourceArray(left) < sourceArray(middle)) {
      swap(sourceArray,left,middle)
    }
  }

  private def swap(sourceArray : Array[Integer],i : Integer,j : Integer): Unit = {
    val temp : Integer = sourceArray(i)
    sourceArray(i) = sourceArray(j)
    sourceArray(j) = temp
  }
}
object QuickSort {
  def main(args: Array[String]): Unit = {
    val array = new Array[Integer](10)
    val random = new Random()
    for (i <- 0 to 9) {
      array(i) = random.nextInt(100)
    }
    val quickSort = new QuickSort()
    val resultArray : Array[Integer] = quickSort.sort(array)
    println("===========================================================================================================")
    resultArray.map(println)
  }
}
  • 上面選取piovt的時候,是採取三點取中間值的方式,這種方式效率比單獨直接指定第一個數字有時候會高一點;
  • 當然也可以選取多些點做比較,取中間點,就更大程度避免取得值比較極限;
  • 上面尋找piovt的對應的位置,此處是通過兩個指針從一端開始來實現的,我們也可以通過兩個指針,一個從低位一個從高位來實現。

9、堆排序

堆排序是指利用堆這種數據結構所設計的一種排序算法。堆積是一種近似完全二叉樹的結果,並同時滿足堆積的性質:即子結點的鍵值或索引總是小於(或者大於)它的父節點。**堆排序可以說是一種利用堆的概念來排序的選擇排序。**分爲兩種方法:

大頂堆:每個節點的值都大於或等於其子節點的值,在堆排序算法中用於升序排列;
小頂堆:每個節點的值都小於或等於其子節點的值,在堆排序算法中用於降序排列;
堆排序的平均時間複雜度爲 Ο(nlogn)。

  • 堆排序
import com.zhangyue.impls.IArraySort

import scala.util.Random

/**
  * 堆排序:
  * 創建一個堆 H[0……n-1];
  * 把堆首(最大值)和堆尾互換;
  * 把堆的尺寸縮小 1,並調用 shift_down(0),目的是把新的數組頂端數據調整到相應位置;
  * 重複步驟 2,直到堆的尺寸爲 1。
  */
class HeapSort extends IArraySort{
  override def sort(sourceArray: Array[Integer]): Array[Integer] = {
    var len : Integer = sourceArray.length
    //構建大根堆
    buildMaxHeap(sourceArray,len)
    var i = len -1
    while (i > 0) {
      swap(sourceArray,0,i)
      len -= 1
      heapify(sourceArray,0,len)
      i -= 1
    }
    sourceArray
  }

  //構造大根堆
  private def buildMaxHeap(sourceArray: Array[Integer], len: Integer): Unit = {
    var i : Integer = Math.floor(len / 2).toInt
    while (i >= 0) {
      heapify(sourceArray,i,len)
      i -= 1
    }
  }

  //將剩餘的數構造成大根堆(通過頂端的數下降)
  private def heapify(sourceArray : Array[Integer],i : Integer,len : Integer): Unit = {
    //此處之所以 left = 2 * i + 1,而不是left = 2 * i ,是因爲開始節點爲數組的0,
    // 因此需要減1,(0 + 1) * 2 - 1 = 1,即(i + 1) * 2 - 1 = left = 2 * i + 1
    var left : Integer = 2 * i + 1
    var right : Integer = 2 * i + 2
    //判斷孩子中比較大的值,先指向其父親
    var largest : Integer = i

    //如果左子節點存在並且左子節點的值大於largest節點的值,那麼就將largest的值改成left節點
    if (left < len && sourceArray(left) > sourceArray(largest)) {
      largest = left
    }
    //如果右子節點存在並且右子節點的值大於largest節點的值,那麼就將largest的值改成right節點
    if (right < len && sourceArray(right) > sourceArray(largest)) {
      largest = right
    }
    //如果largest的值不等於i的值,也就是最大值的數組下標不再是原本i的值,那麼就將i與largest對應的值做調換
    if (largest != i) {
      swap(sourceArray,i,largest)
      //同時,對已經調換了之後的子節點重新計算其左右子節點是否符合規範
      heapify(sourceArray,largest,len)
    }
  }

  private def swap(sourceArray : Array[Integer],i : Integer,j : Integer): Unit = {
    val temp = sourceArray(i)
    sourceArray(i) = sourceArray(j)
    sourceArray(j) = temp
  }
}
object HeapSort {
  def main(args: Array[String]): Unit = {
    val array = new Array[Integer](10)
    val random = new Random()
    for (i <- 0 to 9) {
      array(i) = random.nextInt(100)
    }
    val heapSort = new HeapSort
    val resultArray : Array[Integer] = heapSort.sort(array)
    println("===========================")
    resultArray.map(println)
  }
}

10、計數排序

**計數排序的核心在於將輸入的數據值轉換爲鍵存儲在額外開闢的數組空間中,之後循環將額外開闢空間中的數組的對應值,從小到大寫入到存儲空間中。**作爲一種線性時間複雜度的排序,計數排序要求輸入的數據必須是有確定範圍的整數。

  • 計數排序
import com.zhangyue.impls.IArraySort

import scala.util.Random

/**
  * 計數排序:
  * 找出待排序的數組中最大和最小的元素
  * 統計數組中每個值爲i的元素出現的次數,存入數組C的第i項
  * 對所有的計數累加(從C中的第一個元素開始,每一項和前一項相加)
  * 反向填充目標數組:將每個元素i放在新數組的第C(i)項,每放一個元素就將C(i)減去1
  */
class CountingSort extends IArraySort{
  override def sort(sourceArray: Array[Integer]): Array[Integer] = {
    val maxValue : Integer = getMaxValue(sourceArray)
    return countingSort(sourceArray,maxValue)
  }

  private def countingSort(sourceArray : Array[Integer],maxValue : Integer): Array[Integer] = {
    val bucketLen : Integer = maxValue + 1
    val bucket : Array[Integer] = new Array[Integer](bucketLen)
    //初始化爲0
    for (i <- 0 until bucketLen) {
      bucket(i) = 0
    }

    for (value : Integer <- sourceArray) {
      bucket(value) += 1
    }
    var sortedIndex : Integer = 0
    var j : Integer = 0
    while (j < bucketLen) {
      while (bucket(j) > 0) {
        sourceArray(sortedIndex) = j
        sortedIndex += 1
        bucket(j) -= 1
      }
      j += 1
    }
    sourceArray
  }

  private def getMaxValue(sourceArray : Array[Integer]) : Integer = {
    var maxValue : Integer = sourceArray(0)
    for (value : Integer <- sourceArray) {
      if (maxValue < value) {
        maxValue = value
      }
    }
    maxValue
  }
}
object CountingSort {
  def main(args: Array[String]): Unit = {
    val array = new Array[Integer](10)
    val random = new Random()
    for (i <- 0 to 9) {
      array(i) = random.nextInt(100)
    }
    val countingSort = new CountingSort
    val resultArray : Array[Integer] = countingSort.sort(array)
    println("===========================")
    resultArray.map(println)
  }
}

11、桶排序

桶排序是計數排序的升級版。它利用了函數的映射關係,搞笑與否的關鍵在於這個映射函數的確定。爲了使桶排序更加高效,我們需要做到這兩點:

  • 在額外空間充足的情況下,儘量增大桶的數量
  • 使用的映射函數能夠將輸入的 N 個數據均勻的分配到 K 個桶中

同時,對於桶中元素的排序,選擇何種比較排序算法對於性能的影響至關重要。

  • 桶排序
import com.zhangyue.impls.IArraySort

import scala.util.Random

/**
  * 桶排序
  */
class BucketSort extends IArraySort{
  override def sort(sourceArray: Array[Integer]): Array[Integer] = {
    return bucketSort(sourceArray,8)
  }

  private def bucketSort(sourceArray : Array[Integer],bucketSize : Integer) : Array[Integer] = {
    if (sourceArray.length == 0) {
      return sourceArray
    }
    var minValue: Integer = sourceArray(0)
    var maxValue: Integer = sourceArray(0)

    for (value: Integer <- sourceArray) {
      if (value < minValue) {
        minValue = value
      }
      if (value > maxValue) {
        maxValue = value
      }
    }

    var bucketCount : Integer = Math.floor((maxValue - minValue) / bucketSize).toInt + 1
    val buckets : Array[Array[Integer]]= Array.ofDim[Integer](bucketCount,0)

    //利用映射函數將數據分配到各個桶中
    for (i <- 0 until sourceArray.length) {
      var index : Integer = Math.floor((sourceArray(i) - minValue) / bucketSize).toInt
      buckets(index) = arrayAppend(buckets(index),sourceArray(i))
    }

    var arrayIndex : Integer = 0
    for (bucket : Array[Integer] <- buckets if (bucket.length > 0)) {
      //對每個桶進行排序,這裏使用插入排序
      val insertionSort = new InsertionSort
      val bucketSort = insertionSort.sort(bucket)
      for (value : Integer <- bucketSort) {
        sourceArray(arrayIndex) = value
        arrayIndex += 1
      }
    }
    sourceArray
  }

  /**
    * 自動擴容,並保存數據
    * @param sourceArray  需要擴容的數組
    * @param value  需要添加到數組中去的元素
    * @return
    */
  private def arrayAppend(sourceArray : Array[Integer],value : Integer) : Array[Integer] = {
    import java.util.Arrays
    val appendArray : Array[Integer] = Arrays.copyOf(sourceArray,sourceArray.length+1)
    appendArray(appendArray.length - 1) = value
    appendArray
  }
}
object BucketSort {
  def main(args: Array[String]): Unit = {
    val array = new Array[Integer](40)
    val random = new Random()
    for (i <- 0 until( 40)) {
      array(i) = random.nextInt(100)
    }
    val bucketSort = new BucketSort
    val resultArray : Array[Integer] = bucketSort.sort(array)
    println("===========================")
    resultArray.map(println)
  }
}

12、基數排序

基數排序是一種非比較型整數排序算法,其原理是將整數按位數切割成不同的數字,然後按每個位數分別比較。由於整數也可以表達字符串(比如名字或日期)和特定格式的浮點數,所以基數排序也不是隻能使用於整數。

  • 基數排序

/**
  * 基數排序
  */
class RadixSort extends IArraySort{
  override def sort(sourceArray: Array[Integer]): Array[Integer] = {
    val maxDigit : Integer = getMaxDigit(sourceArray)
    return radixSort(sourceArray,maxDigit)
  }

  private def getMaxDigit(sourceArray : Array[Integer]) : Integer = {
    val maxValue : Integer = getMaxValue(sourceArray)
    return getNumLength(maxValue.longValue())
  }

  private def getMaxValue(sourceArray : Array[Integer]) : Integer = {
    var maxValue = sourceArray(0)
    for (value : Integer <- sourceArray) {
      maxValue = value
    }
    maxValue
  }

  protected def getNumLength(num : Long) : Integer = {
    if (num == 0) {
      return 1
    }
    var length : Integer = 0
    var temp : Long = num
    while (temp != 0) {
      length += 1
      temp /= 10
    }
    length
  }

  private def radixSort(sourceArray : Array[Integer],maxDigit : Integer) : Array[Integer] = {
    var mod : Integer = 10
    var dev : Integer = 1
    for (i <- 0 until maxDigit) {
      //考慮負數的情況,這裏擴展一倍隊列數,其中[0-9]對應負數,[10-19]對應正數(bucket + 10)
      var counter : Array[Array[Integer]] = Array.ofDim[Integer](mod*2,0)

      for (j <- 0 until sourceArray.length) {
        val bucket : Integer = ((sourceArray(j) % mod) /dev) + mod
        counter(bucket) = arrayAppend(counter(bucket),sourceArray(j))
      }
      var pos : Integer = 0
      for (bucketValue : Array[Integer]<- counter) {
        for (value : Integer <- bucketValue) {
          sourceArray(pos) = value
          pos += 1
        }
      }

      dev *= 10
      mod *= 10
    }
    sourceArray
  }

  /**
    * 自動擴容,並保存數據
    * @param sourceArray
    * @param value
    * @return
    */
  private def arrayAppend(sourceArray : Array[Integer],value : Integer) : Array[Integer] = {
    import java.util.Arrays
    val arrayAppend : Array[Integer] = Arrays.copyOf(sourceArray,sourceArray.length + 1)
    arrayAppend(arrayAppend.length - 1) = value
    arrayAppend
  }
}
object RadixSort {
  def main(args: Array[String]): Unit = {
    val array = new Array[Integer](40)
    val random = new Random()
    for (i <- 0 until( 40)) {
      array(i) = random.nextInt(100)
    }
    val radixSort = new RadixSort
    val resultArray : Array[Integer] = radixSort.sort(array)
    println("===========================")
    resultArray.map(println)
  }
}

上面的函數大多數都是從網上java版本改過來的,文字大多數摘自《大話數據結構》以及菜鳥教程的 十大經典排序算法.

可能有些算法有待改進。

發佈了32 篇原創文章 · 獲贊 11 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章