Sorter 特质
package com.shockang.study.algorithm.scala.archive.sort
trait Sorter {
def sort(a: Array[Int])
protected def swap(a: Array[Int], i: Int, j: Int): Unit = {
val tmp = a(i)
a(i) = a(j)
a(j) = tmp
}
}
3 种 O(n^2)的排序算法
冒泡排序
package com.shockang.study.algorithm.scala.archive.sort.bubble
import com.shockang.study.algorithm.scala.archive.sort.Sorter
/**
* 冒泡排序
*
* @author Shockang
*/
class BubbleSorter extends Sorter {
override def sort(a: Array[Int]): Unit = {
if (a == null || a.length < 2) return
// i 从左到右遍历每一个数组元素, j 从右到左进行冒泡
for (i <- a.indices; j <- i - 1 to 0 by -1) {
if (a(j) > a(j + 1)) swap(a, j, j + 1)
}
}
}
插入排序
package com.shockang.study.algorithm.scala.archive.sort.insert
import com.shockang.study.algorithm.scala.archive.sort.Sorter
/**
* 插入排序
*
* @author Shockang
*/
class InsertSorter extends Sorter {
override def sort(a: Array[Int]): Unit = {
if (a == null || a.length < 2) return
val n = a.length
// i 从左到右遍历每个数组元素,跳过首个元素
for (i <- 1 until n) {
val num = a(i)
var j = i
// j 从右到左进行插入操作
while (j > 0 && a(j - 1) > num) {
// 往右挪,给插入腾出位置
a(j) = a(j - 1)
j -= 1
}
// 插入
a(j) = num
}
}
}
选择排序
package com.shockang.study.algorithm.scala.archive.sort.select
import com.shockang.study.algorithm.scala.archive.sort.Sorter
/**
* 选择排序
*
* @author Shockang
*/
class SelectSorter extends Sorter {
override def sort(a: Array[Int]): Unit = {
if (a == null || a.length < 2) return
val n = a.length
// i 从左到右遍历每个数组元素
for (i <- 0 until n) {
var min = a(i)
var index = i
// j 从左到右选择最小的值
for (j <- i + 1 until n) {
if (a(j) < min) {
min = a(j)
index = j
}
}
swap(a, i, index)
}
}
}
3 种 O(nlogn)的排序算法
归并排序
1
package com.shockang.study.algorithm.scala.archive.sort.merge
import com.shockang.study.algorithm.scala.archive.sort.Sorter
/**
* 归并排序
*
* @author Shockang
*/
class MergeSorter extends Sorter {
override def sort(a: Array[Int]): Unit = {
if (a == null || a.length < 2) return
mergeSort(a, 0, a.length - 1)
}
/**
* 归并排序
*
* @param a 待排序数组
* @param low 左边界
* @param high 右边界
*/
def mergeSort(a: Array[Int], low: Int, high: Int): Unit = {
if (low < high) {
// 取中间元素的下标
val mid = low + ((high - low) >> 1)
mergeSort(a, low, mid)
mergeSort(a, mid + 1, high)
merge(a, low, mid, high)
}
}
/**
* 合并
*
* @param a 待排序数组
* @param low 左边界
* @param mid 中间元素的下标
* @param high 右边界
*/
def merge(a: Array[Int], low: Int, mid: Int, high: Int) = {
// a 中 low ~ mid 的元素挪到一个新数组中,新数组最后一个元素放置一个哨兵
val a1 = new Array[Int](mid - low + 2)
for (i <- 0 to a1.length - 2) {
a1(i) = a(low + i)
}
a1(a1.length - 1) = Int.MaxValue
// a 中 mid+1 ~ high 的元素挪到一个新数组中,新数组最后一个元素放置一个哨兵
val a2 = new Array[Int](high - mid + 1)
for (i <- 0 to a2.length - 2) {
a2(i) = a(mid + 1 + i)
}
a2(a2.length - 1) = Int.MaxValue
// 两个新数组的元素比较并放入原数组,因为哨兵的存在,减少了比较
var i, j = 0
for (k <- low to high) {
if (a1(i) <= a2(j)) {
a(k) = a1(i)
i += 1
} else {
a(k) = a2(j)
j += 1
}
}
}
}
2
package com.shockang.study.algorithm.scala.archive.sort.merge
import com.shockang.study.algorithm.scala.archive.sort.Sorter
class MergeSorter2 extends Sorter {
var aux: Array[Int] = _
override def sort(a: Array[Int]): Unit = {
if (a == null || a.length < 2) return
aux = new Array[Int](a.length)
mergeSort(a, 0, a.length - 1)
}
def mergeSort(nums: Array[Int], lo: Int, hi: Int): Unit = {
if (lo < hi) {
val mid = (lo + hi) / 2
mergeSort(nums, lo, mid)
mergeSort(nums, mid + 1, hi)
merge(nums, lo, mid, hi)
}
}
private def merge(nums: Array[Int], lo: Int, mid: Int, hi: Int): Unit = {
var i = lo
var j = mid + 1
for (k <- lo to hi) aux(k) = nums(k)
var index = lo
while (i <= mid || j <= hi) {
if (i > mid) {
nums(index) = aux(j)
index += 1
j += 1
} else if (j > hi || aux(i) <= aux(j)) {
nums(index) = aux(i)
index += 1
i += 1
} else {
nums(index) = aux(j)
index += 1
j += 1
}
}
}
}
3
package com.shockang.study.algorithm.scala.archive.sort.merge;
import com.shockang.study.algorithm.scala.archive.sort.Sorter;
import com.shockang.study.algorithm.scala.archive.sort.Sorter;
public class MergeSorter3 implements Sorter {
private int[] aux;
@Override
public void sort(int[] a) {
if (a == null || a.length < 2) return;
aux = new int[a.length];
sort(a, 0, a.length - 1);
}
public void sort(int[] nums, int lo, int hi) {
if (hi <= lo) return;
int mid = (lo + hi) / 2;
sort(nums, lo, mid);
sort(nums, mid + 1, hi);
merge(nums, lo, mid, hi);
}
private void merge(int[] nums, int lo, int mid, int hi) {
int i = lo, j = mid + 1;
for (int k = lo; k <= hi; k++)
aux[k] = nums[k];
int index = lo;
while (i <= mid || j <= hi) {
if (i > mid) nums[index++] = aux[j++];
else if (j > hi || aux[i] <= aux[j]) nums[index++] = aux[i++];
else nums[index++] = aux[j++];
}
}
}
快速排序
package com.shockang.study.algorithm.scala.archive.sort.quick
import com.shockang.study.algorithm.scala.archive.sort.Sorter
/**
* 快速排序
*
* @author Shockang
*/
class QuickSorter extends Sorter {
override def sort(a: Array[Int]): Unit = {
if (a == null || a.length < 2) return
quickSort(a, 0, a.length - 1)
}
/**
* 快速排序
*
* @param a 待排序数组
* @param low 左边界
* @param high 右边界
*/
def quickSort(a: Array[Int], low: Int, high: Int): Unit = {
if (low < high) {
val curPoint = getCutPoint(a, low, high)
quickSort(a, low, curPoint)
quickSort(a, curPoint + 1, high)
}
}
/**
* 获取切分点,切分点后面的都比它大,切分点前面的都比它小
*
* @param a 待排序数组
* @param low 左边界
* @param high 右边界
* @return
*/
def getCutPoint(a: Array[Int], low: Int, high: Int): Int = {
val m = a(low)
var l = low
var r = high
while (l < r) {
// 从右往左找第一个比切分点小的元素下标
while (l < r && a(r) >= m) r -= 1
// 从左往右找第一个比切分点大的元素下标
while (l < r && a(l) <= m) l += 1
if (l < r) swap(a, l, r)
}
swap(a, low, l)
l
}
}
堆排序
package com.shockang.study.algorithm.scala.archive.sort.heap
import com.shockang.study.algorithm.scala.archive.sort.Sorter
import scala.util.control.Breaks._
/**
* 堆排序
*
* @author Shockang
*/
class HeapSorter extends Sorter {
override def sort(a: Array[Int]): Unit = {
if (a == null || a.length < 2) return
//从第一个非叶子结点从下至上,从右至左调整结构
for (i <- (a.length - 1) / 2 to 0 by -1) {
adjustHeap(a, i, a.length)
}
//调整堆结构+交换堆顶元素与末尾元素
for (i <- a.length - 1 until 0 by -1) {
//将堆顶元素与末尾元素进行交换
swap(a, 0, i)
//重新对堆进行调整
adjustHeap(a, 0, i)
}
}
/**
* 调整堆
*
* @param a 待排序列
* @param parent 父节点
* @param length 待排序列尾元素索引
*/
private def adjustHeap(a: Array[Int], parent: Int, length: Int): Unit = {
//将temp作为父节点
val temp = a(parent)
//左孩子
var lChild = 2 * parent + 1
var p = parent
breakable(while (lChild < length) {
//右孩子
val rChild = lChild + 1
// 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点
if (rChild < length && a(lChild) < a(rChild)) lChild += 1
// 如果父结点的值已经大于孩子结点的值,则直接结束
if (temp >= a(lChild)) break
// 把孩子结点的值赋给父结点
a(p) = a(lChild)
//选取孩子结点的左孩子结点,继续向下筛选
p = lChild
lChild = 2 * lChild + 1
})
a(p) = temp
}
}
单测
为什么我敢说我的排序算法绝对正确
一点问题没有呢,原因就在于我写的单元测试用例
package com.shockang.study.algorithm.scala.archive.sort.main
import com.shockang.study.algorithm.scala.archive.sort.Sorter
import com.shockang.study.algorithm.scala.archive.sort.bubble.BubbleSorter
import com.shockang.study.algorithm.scala.archive.sort.heap.HeapSorter
import com.shockang.study.algorithm.scala.archive.sort.insert.InsertSorter
import com.shockang.study.algorithm.scala.archive.sort.merge.{MergeSorter, MergeSorter2, MergeSorter3}
import com.shockang.study.algorithm.scala.archive.sort.quick.QuickSorter
import com.shockang.study.algorithm.scala.archive.sort.select.SelectSorter
import com.shockang.study.algorithm.scala.util.StringUtil.format
import scala.util.Random
object SorterMain extends App {
assertSorter(new BubbleSorter)
assertSorter(new InsertSorter)
assertSorter(new SelectSorter)
assertSorter(new MergeSorter)
assertSorter(new MergeSorter2)
assertSorter(new MergeSorter3)
assertSorter(new QuickSorter)
assertSorter(new HeapSorter)
private def assertSorter(sorter: Sorter): Unit = {
println(format(s"Start to assert:${sorter.getClass.getSimpleName}"))
assertNull(sorter)
for (_ <- Range(0, 100)) assertArray(sorter, generateRandomArray())
println(format(s"Succeed to assert:${sorter.getClass.getSimpleName}"))
}
private def generateRandomArray(): Array[Int] = {
val n = Random.nextInt(10000)
val a = new Array[Int](n)
for (i <- a.indices) {
a(i) = Random.nextInt(10000)
}
a
}
private def assertNull(sorter: Sorter): Unit = {
assertArray(sorter, null)
assertArray(sorter, new Array[Int](0))
}
private def assertArray(sorter: Sorter, a: Array[Int]): Unit = {
if (a == null) return
val original = a.clone()
sorter.sort(a)
assert(checkArray(original, a))
}
private def checkArray(original: Array[Int], sorted: Array[Int]): Boolean = {
sorted.mkString(",").equals(original.sorted.mkString(","))
}
}
控制台输出
----------Start to assert:BubbleSorter----------
----------Succeed to assert:BubbleSorter----------
----------Start to assert:InsertSorter----------
----------Succeed to assert:InsertSorter----------
----------Start to assert:SelectSorter----------
----------Succeed to assert:SelectSorter----------
----------Start to assert:MergeSorter----------
----------Succeed to assert:MergeSorter----------
----------Start to assert:MergeSorter2----------
----------Succeed to assert:MergeSorter2----------
----------Start to assert:MergeSorter3----------
----------Succeed to assert:MergeSorter3----------
----------Start to assert:QuickSorter----------
----------Succeed to assert:QuickSorter----------
----------Start to assert:HeapSorter----------
----------Succeed to assert:HeapSorter----------
可以看出,连续测试一百次,每次都是支持最高 10000 个整数的排序,这种情况下的排序算法逻辑毫无疑问绝对是正确的。