def quickSort(left: Int, right: Int, arr: Array[Int]): Unit = {
// 递归出口条件
if (left >= right) return
val basePositon: Int = getPosition(left, right, arr)
// 以基数为界,分而治之
quickSort(left, basePositon - 1, arr)
quickSort(basePositon + 1, right, arr)
}
/** *
* 挖坑填数,该方法执行完已经将传入的arr修改成: 左边数据|基数|右边数据
* 并且左边数据都比基数小 右边数据都比基数大
*/
def getPosition(left: Int, right: Int, arr: Array[Int]): Int = {
// 基准数默认指定为数组的第一个元素
val base = arr(left)
var l = left;
var r = right;
while (l < r) {
// 找出比基准数小的放在这个基准数的左边,所以要从右往左找
while (l < r && arr(r) >= base) {
r -= 1
}
// 如果跳出循环说明找到了比基数小的值,将这个值填充在基数所在的下标位置,同时l下标+1
if (l < r) {
arr(l) = arr(r)
l += 1
}
// 第二个循环找出比基准数大的放在这个基准数的右边,所以要从坐往右找
while (l < r && arr(l) <= base) {
l += 1
}
// 如果跳出循环说明找到了比基数大的值,将这个值填充在基数所在的下标位置,同时l小标+1
if (l < r) {
arr(r) = arr(l)
r -= 1
}
}
// 如果走到这里说明left=right,此时基数应该所在的位置就是当前left或者right的位置
arr(l) = base
// 返回基数应该所在的下标位置
l
}
def main(args: Array[String]): Unit = {
val array: Array[Int] = Array(16,13,15,29,32,17,11)
quickSort(0,array.length-1,array)
for (elem <- array) {
print(elem + "\t")
}
System.exit(0)
}
第二种简单写法
def quickSort(left: Int, right: Int, arr: Array[Int]): Unit = {
var l: Int = left
var r: Int = right
// 取一个中间值作为参考值
var pivot = arr((left + right) / 2)
var temp = 0
import util.control.Breaks._
// 总的思想每轮循环找到比中间值大的和比中间值小的,然后交换数据,直到left下标和right下标重合就跳出循环
// 然后以重合的下标为界将数据分成左右两部分,利用递归的思想递归调用即可
breakable {
while (l < r) {
//从左点向右遍历,直到找到比中间值大的
while (arr(l) < pivot) {
l += 1
}
//从右点向左遍历,直到找到比中间值小的
while (arr(r) > pivot) {
r -= 1
}
//如果l==r表示已经到达中间值,此时中间值左边的数据都比中间值小,右边的值都比中间值大
// 就没有必要在交换数据了,而且也需要跳出循环
if (l == r) {
break()
}
//交换数据
temp = arr(l)
arr(l) = arr(r)
arr(r) = temp
}
}
// 递归排序中间值左边部分的数据,到达中间值时l==r,如果此时l-1还大于起始下标0,说明左边还有大于1个元素
// 因为左边的元素不一定有序,还需要继续递归排序,所以这里的判断条件left < l - 1就很有必要了,而且最重
// 要的是如果不加这个条件就会是递归循环调用,最后栈溢出
if (left < l - 1) {
quickSort(left, l - 1, arr)
}
// 递归排序中间值右边边部分的数据,这里用r,l都一样,因为他们相等
if (right > r + 1) {
quickSort(r + 1, right, arr)
}
}