十大基础排序算法-scala编写

本秂侑毒 提交于 2020-01-01 21:39:45

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版本改过来的,文字大多数摘自《大话数据结构》以及菜鸟教程的 十大经典排序算法.

可能有些算法有待改进。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!