排序

作者: 周二可 | 来源:发表于2018-04-08 11:27 被阅读2次

交换排序

让每个值都和它后面的值比较,如果打则交换,这样第一位置的值在一次循环后就是最小值,然后第二次循环找出第二小的值,以此类推。


交换排序
func switchSort(_ array: inout [Int]) -> [Int] {
    
    guard array.count > 1 else { return array }
    
    for i in 0 ..< array.count {
        
        for j in i + 1 ..< array.count {
          
            if array[i] > array[j] {
                array.swapAt(i, j) 
                print("\(array)")
            }
        }
    }
    
    return array 
}

冒泡排序

两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。
O(n2)


冒泡排序
func bubbleSort(_ array: inout [Int]) -> [Int] {
    
    guard array.count > 1 else { return array }    
    
    for i in 0 ..< array.count - 1 {

        for j in 0 ..< array.count - 1 - i {
            
            if array[j] > array[j+1] {
                array.swapAt(j, j+1) //keeping index of j is the smaller one
                print("after swap: \(array)")
                
            }
        }
    }
    return array
}
// 优化冒泡
func bubbleSortAdvanced(_ array: inout [Int]) -> [Int] {
    
    guard array.count > 1 else { return array }
    
    for i in 0 ..< array.count - 1 {
        
        //bool switch
        var swapped = false
      
        for j in 0 ..< array.count - i - 1 {
            
            if array[j] > array [j+1] {
                array.swapAt(j, j+1) 
                swapped = true;
            }
        }
        
        //if there is no swapping in inner loop, it means the the part looped is already sorted,
        //so it's time to break
        if (swapped == false){ break }
    }
    
    return array
    
}

选择排序

O(n2)
两层循环,外面循环开始时用变量min记录最小值对应的下标,初始化为i,然后每次内层循环来得到最小值对应下标。如果最小值下标变化了说明找到了比i对应的值更小的值,这时候替换i与min对应的值。否则说明i对应的就是这次外层循环对应的最小值,不用替换。

func selectionSort(_ array: inout [Int]) -> [Int] {
    
    guard array.count > 1 else { return array }

    for i in 0 ..< array.count - 1{
        
        var min = i
        
        for j in i + 1 ..< array.count {
            
            if array[j] < array[min] {
                min = j 
            }
        }
        
        //if min has changed, it means there is value smaller than array[min]
        //if min has not changed, it means there is no value smallter than array[min]
        if i != min {
            array.swapAt(i, min) 
        }
    }
    return array
}

插入排序

从数组中拿出一个元素(通常就是第一个元素)以后,再从数组中按顺序拿出其他元素。如果拿出来的这个元素比这个元素小,就放在这个元素左侧;反之,则放在右侧。

func insertionSort(_ array: inout [Int]) -> [Int] {
    
    guard array.count > 1 else { return array }
    
    for i in 1..<array.count {
        
        var j = i
        while j > 0 && array[j] < array[j - 1] {
             array.swapAt(j - 1, j)
            j -= 1
        }
    }
    return array
}

归并排序

归并排序示意图

递归实现

func mergeSort(array: [Int]) -> [Int] {
    var helper = Array(repeating: 0, count: array.count)
    var array = array
    mergeSort(array: &array, helper: &helper, start: 0, end: array.count - 1)
    return array
}

func mergeSort(array: inout [Int], helper: inout [Int], start: Int, end: Int) {
    // 递归基础,当start大于等于end的时候说明已经分为最小单位
    if start >= end {
        return
    }
    let m = (start + end) / 2
    // 排序start到m
    mergeSort(array: &array, helper: &helper, start: start, end: m)
    // 排序m+1到end
    mergeSort(array: &array, helper: &helper, start: m + 1, end: end)
    // 归并start到m的数组与m+1到end的数组
    merge(array: &array, helper: &helper, start: start, middle: m, end: end)
}

func merge(array: inout [Int], helper: inout [Int], start: Int, middle: Int, end: Int) {
    // copy both halves into a helper array
    for i in start ... end {
        helper[i] = array[i]
    }

    // 标记左侧start~middle中要取出元素的位置
    var helperLeft = start
    // 标记右侧middle+1~end中要取出元素的位置
    var helperRight = middle + 1
    // 标记当前排序的位置
    var current = start
    
    // 取出左右两侧中较小的元素放到当前排序的位置,排好以后排下一个位置
    while helperLeft <= middle && helperRight <= end {
        if helper[helperLeft] <= helper[helperRight] {
            array[current] = helper[helperLeft]
            helperLeft += 1
        } else {
            array[current] = helper[helperRight]
            helperRight += 1
        }
        current += 1
    }
    
    // 归并剩下的元素放到排好序的元素后面
    if helperLeft <= middle {
        for i in 0...(middle - helperLeft) {
            array[current + i] = helper[helperLeft + i]
        }
    }
    if helperRight <= end {
        for i in 0...(end - helperRight) {
            array[current + i] = helper[helperRight + i]
        }
    }
}

merge函数示意图
其中 k = current, i = helperLeft, j = helperRight, m = niddle, n = end





非递归实现
//todo

快速排序

func _QSort(array: inout [Int]) {
    qSort(array: &array, low: 0, high: array.count - 1)
}

func qSort(array: inout [Int], low: Int, high: Int) {
    if low >= high {
        return
    }
    
    // 查找枢轴点,并把数组以其分为两部分,左侧全部小于枢轴,右侧全部大于枢轴
    let pivot = partition(array: &array, low: low, high: high)
    
    // 对枢轴左侧进行排序
    qSort(array: &array, low: low, high: pivot - 1)
    // 对枢轴右侧进行排序
    qSort(array: &array, low: pivot + 1, high: high)
}

// 查找枢轴记录
func partition(array: inout [Int], low: Int, high: Int) -> Int {
    var low = low
    var high = high
    
    // 使用第一个元素作为枢轴记录
    let pivotValue = array[low]
    // 从低到高遍历
    while low < high {
        // 从高开始查找,找到第一个比枢轴小的点跳出循环
        while low < high && array[high] >= pivotValue {
            high -= 1
        }
        // low现在代表的是枢轴所在的位置,这时高点指向的值比枢轴小,
        // 因此交换枢与高点的位置,交换之后高点high表示枢轴的位置
        array.swapAt(low, high)
        // 从低点开始查找,找到第一个比枢轴大的点后跳出循环
        while low < high && array[low] <= pivotValue {
            low += 1
        }
        // 交换低点与枢轴的位置,交换以后低点low表示枢轴的位置
        array.swapAt(high, low)
    }
    // 跳出上面的循环说明高点低点重合了,这时就表明比枢轴小的都处于左侧,比其大的都处于右侧
    return low
}

partition 函数示意


相关文章

  • 【恋上数据结构与算法二】(一)排序(Sorting)

    排序方法 冒泡排序 选择排序 堆排序 插入排序 归并排序 快速排序 希尔排序 计数排序 基数排序 桶排序 初识排序...

  • 排序-冒泡排序

    排序系列传递门 排序—选择排序排序—快速排序排序—插入排序排序-希尔排序(待完善)排序—归并排序(待完善)排序—基...

  • 排序

    冒泡排序: 冒泡排序 选择排序: 插入排序: 希尔排序: 归并排序: 快速排序: 堆排序: 计数排序: 桶排序: ...

  • Java | 10种排序算法

    冒泡排序 选择排序 插入排序 希尔排序 计数排序 基数排序 堆排序 归并排序 快速排序 桶排序

  • 常见的排序

    冒泡排序: 选择排序: 插入排序: 快速排序: 希尔排序: 归并排序: 堆排序: 计数排序: 桶排序: 基数排序:

  • 002--20200409刷题

    冒泡排序 选择排序 插入排序 希尔排序 归并排序 快速排序 堆排序 计数排序 桶排序 基数排序

  • 排序

    排序 符号:Θ 插入排序 选择排序 堆排序 归并排序 冒泡排序 快速排序 桶排序 基数排序 计数排序 插入排序 插...

  • 排序 -- 选择/插入

    聊聊排序吧 冒泡排序 选择排序 插入排序 快速排序 归并排序 计数排序 桶排序 堆排序 本篇 选择排序与插入排序 ...

  • 前端基础整理 | 算法基础

    排序算法 冒泡排序 选择排序 插入排序 希尔排序 归并排序 堆排序 快速排序

  • Java 常见的 8 种排序算法(内排序)

    排序分类 内部排序 插入排序:直接插入排序、希尔排序 交换排序:冒泡排序、快速排序 选择排序:直接选择排序、堆排序...

网友评论

    本文标题:排序

    本文链接:https://www.haomeiwen.com/subject/ykkxhftx.html