文章目录


动画网址:http://www.webhek.com/post/comparison-sort.html

冒泡排序

本质


相邻的元素进行比较, 然后小的在前, 大的再后. 一轮下能成功排序 1 个 ,如果有 n 个元素, 则需要排序 n-1 轮


package com.zyd

object PaoSort {
def main(args: Array[String]): Unit = {

val arr = Array(1, 23, 45, 65, 21, 3, 56)

BubbleSort(arr)
print(arr.toList)

}

def BubbleSort(arr: Array[Int]): Unit = {
for (i <- 0 until arr.length - 1) {

for (j <- 0 until arr.length - 1 - i) {
if (arr(j) > arr(j + 1)) {
swap(arr, j, j + 1)
}
}


}
}

def swap(arr: Array[Int], i: Int, i1: Int): Unit = {
val tmp: Int = arr(i)
arr(i) = arr(i + 1)
arr(i + 1) = tmp
}

}

选择排序

本质


选择第一个数为最小数,然后让这个数和后面所有的数进行比较,一轮下来最小的数放在第一个位置
依次选择第二个数和后面的进行比较


代码

package com.zyd


object SelectSort {

def main(args: Array[String]): Unit = {
val arr = Array(1, 23, 45, 65, 21, 3, 56)

SelectSortDef(arr)
print(arr.toList)
}

def SelectSortDef(array: Array[Int]): Unit = {
for (i <- 0 until array.length - 1){ //一共有n个元素,只要找到len -1 个就可以了,最后一个位置自动确认
// 选中第i个元素为第 i 小 ,只记录索引即可,成功之后交换一次元素
var minIndex: Int = i
for(j <- i+1 until array.length) {
//让第i个元素,逐渐与第i+1个元素进行比较
if (array(j) < array(minIndex)) minIndex = j //如果比minIndex小,更新索引
//将i的位置和minIndex的位置元素进行交换
}
if (i != minIndex) {
swap(array, i, minIndex)
}
def swap(arr: Array[Int], k: Int, j: Int): Unit = {
var tmp: Int = arr(k)
arr(k) = arr(j)
arr(j) = tmp
}
}
}
}

插入排序

本质


1.类似于玩扑克,手里的牌总是有序的,每取一张牌只需要从后向前比较即可,一旦遇到比新牌小,新牌插入到这张牌后面即可
2.第一个元素是有序的,第二个元素以前与前面的进行比较,碰到大的交互,小的停下来,然后钱两个元素排序完成
3. n个元素,需要完成n-1次排序


package com.zyd

object InsertSort {
def main(args: Array[String]): Unit = {
val arr = Array(1, 23, 45, 65, 21, 3, 56)
inserSortDef(arr)
print(arr.toList)
}

def inserSortDef(arr: Array[Int]): Unit = {
for (i <- 0 until arr.length - 1) {
for (j <- i + 1 until(0,-1)){
if (arr(j)< arr(j-1)){
swap(arr,j,j-1)
}
}
}
}
def swap(arr: Array[Int], i: Int, i1: Int): Unit = {
val tmp: Int = arr(i)
arr(i) = arr(i1)
arr(i1) = tmp
}

}

快速排序

快速排序典型的使用的分治思想.假设有数组 A, 长度为 len, 则元素为: A[0, …, m,… len-1],1.分解:

把数组A分成 2 个子数组, 使得左边数组的元素都小于一个参考值A[m], 右边的子数组的元素都大于参考值A[m]

2.解决:

通过递归解决数组A[0,…m-1]和数组A[m+1, …, len]

3.合并:

因为子数组都是原址排序的, 所以不需要合并, 原数组已经有序

scala 实现排序算法_插入排序

package com.zyd

object QuickSort {
def main(args: Array[String]): Unit = {
val arr = Array(1, 23, 45, 65, 21, 3, 56)
quickSortDef(arr, 0, arr.length -1)
print(arr.toList)
}

/**
* 需要排序的数组
*
* @param array
* @param left
* @param right
*/
def quickSortDef(array: Array[Int], left: Int, right: Int): Unit = {
//如果左指针超过右指针,排序完成
if (left > right) return
//将数据分区,保证左边的都小于等于某一个参数值,右边的都大于某一个参数值
//返回参考值所在位置,作为划分数组的边界
val m = quickPartition(array, left, right)
//再递归左右数组
quickSortDef(array, left, m - 1)
quickSortDef(array, m + 1, right)
}

def quickPartition(array: Array[Int], left: Int, right: Int): Int = {
// 左扫描指针向右扫, 右扫描指针向左扫. 需要更改指针位置
var l = left
var r = right
//参考值,保证左边数据都小于p,右边都大于等于p
val p = array(l)
// 如果左扫描指针在左边就一直扫描
while (l < r) {
// 左指针找到一个大于 p 的, 右指针找到一个小于等于p的, 然后交换
while (l < right && array(l) <= p) {
l += 1
}
while (r > left && array(r) > p) {
r -= 1
}
// 小于等于p 的去左边, 大于 p 的去右边
if (l <= r) {
swap(array, l, r)
}
}
//让参考元素到正确位置,右指针已经到了小于 p 的区域, 所以可以和右指针的元素进行交互
swap(array, left, r)
// 现在右指针就是分割位置
r
}

def swap(arr: Array[Int], i: Int, i1: Int): Unit = {
val tmp: Int = arr(i)
arr(i) = arr(i1)
arr(i1) = tmp
}
}

归并排序

归并排序算法也完全遵循分治模式.

1.分解

待排序的数组分成2个子数组: A[0, …. len/2] 和 A[len/2 + 1, len - 1]

2.解决

使用归并排序递归的地排序两个子序列

3.合并

合并两个已排序的子序列,当待排序的序列长度为 1 时, 递归”开始回升”, 在这种情况下不需要做任何操作, 因为长度为1的序列都已经排好序了

scala 实现排序算法_插入排序_02

package com.zyd


object MergeSort {

def mergedSort[T](less: (T, T) => Boolean)(list: List[T]): List[T] = {

def merged(xList: List[T], yList: List[T]): List[T] = {
(xList, yList) match {
case (Nil, _) => yList
case (_, Nil) => xList
case (x :: xTail, y :: yTail) => {
if (less(x, y)) x :: merged(xTail, yList)
else
y :: merged(xList, yTail)
}
}
}
val n = list.length / 2
if (n == 0) list
else {
val (x, y) = list splitAt n
merged(mergedSort(less)(x), mergedSort(less)(y))
}
}

def main(args: Array[String]) {
val list = List(3, 12, 43, 23, 7, 1, 2, 0)
println(mergedSort((x: Int, y: Int) => x < y)(list))
}
}

希尔排序

希尔排序(Shellsort),也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。希尔排序因DL.Shell于1959年提出而得名

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

1.在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率

2.但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位

原理: 希尔排序是将待排序的数组元素 按下标的一定增量分组 ,分成多个子序列,然后对各个子序列进行直接插入排序算法排序;然后依次缩减增量再进行排序,直到增量为1时,进行最后一次直接插入排序,排序结束


假设数组: [ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ] 如果我们以步长为5开始进行排序
分5组(5列):
13 14 94 33 82
25 59 94 65 23
45 27 73 25 39
10
然后对每列进行排序(每列内进行排序)
10 14 73 25 23
13 27 94 33 39
25 59 94 65 82
45
分3组:
10 14 73
25 23 13
27 94 33
39 25 59
94 65 82
45
然后每组进行排序:
10 14 13
25 23 33
27 25 59
39 65 73
45 94 82
94
最后步长1进行排序, 就退化成了插入排序


希尔排序具体实现

package com.zyd

object XrSort {
def main(args: Array[String]): Unit = {
val arr = Array(1, 23, 45, 65, 21, 3, 56)
print(xrSort(arr).toList)
}

def xrSort(arr: Array[Int]): Array[Int] = {
var step = arr.length / 2

while (step > 0) {
//分成的子数组个数为step
for (i <- 0 until step) {
//某个子数组采用插入排序算法进行排序
for (j <- i + step to(arr.size - 1, step)) {
//直接插入排序
if (arr(j) < arr(j - step)) {
var k = j - step
while (k > 0 && arr(k + step) < arr(k)) {
swap(arr, k, k + step)
k -= step
}
}
}
}
step /= 2
}
arr
}

def swap(arr: Array[Int], i: Int, i1: Int): Unit = {
val tmp: Int = arr(i)
arr(i) = arr(i1)
arr(i1) = tmp
}
}