Swift排序算法


/*
 冒泡排序:标准
 */
func bubbleSort(_ nums: inout [Int]) {
    if nums.count < 2 { return }
    for i in 0..<nums.count { // 总共需要对比的次数
        for j in 0..<nums.count - i - 1 { // 每一次最后一个数必定已经排序为最大
            if nums[j] > nums[j + 1] {
                // 使用元祖交换值
                nums.swapAt(j, j + 1)
            }
        }
    }
}

/*
 冒泡排序优化:在某次排序后如果已经都排序好了,则退出后续的循环
 */
func bubbleSort2(_ nums: inout [Int]) {
    if nums.count < 2 { return }
    var sorted = true
    for i in 0..<nums.count {
        sorted = true
        for j in 0..<nums.count - i - 1 {
            if nums[j] > nums[j + 1] {
                nums.swapAt(j, j + 1)
                sorted = false
            }
        }
        if sorted { break }
    }
}

/*
 冒泡排序优化:记录后半部分排序好的位置,避免重复排序已经排序的部分
 */
func bubbleSort3(_ nums: inout [Int]) {
    if nums.count < 2 { return }
    var sorted = true
    var index = nums.count - 1
    for _ in 0..<nums.count {
        sorted = true
        for j in 0..<index {
            if nums[j] > nums[j + 1] {
                nums.swapAt(j, j + 1)
                sorted = false
                index = j
            }
        }
        if sorted { break }
    }
}

/*
 冒泡排序优化:缩小两边的边界,并记录是否已完成排序
 */
func bubbleSort4(_ nums: inout [Int]) {
    if nums.count < 2 { return }
    var sorted = true
    var left = 0
    var right = nums.count - 1
    // 因为从两端双向排序,左边每次都会是最小,右边每次都是最大,排完的次数刚好到中间位置,
    // 不需要nums.count的次数那么多,写nums.count也没问题,因为会提前退出
    for _ in 0..<nums.count / 2 {
        sorted = true
        for j in left..<right {
            if nums[j] > nums[j + 1] {
                nums.swapAt(j, j + 1)
                sorted = false
                right = j
            }
        }
        if sorted { break }
        
        sorted = true
        
        for j in (left + 1...right).reversed() {
            if nums[j] < nums[j - 1] {
                nums.swapAt(j, j - 1)
                sorted = false
                left = j
            }
        }
        if sorted { break }
    }
}

/*
 插入排序:O(n^2)
 */
func insertSort(_ array: inout [Int]) {
    // 从1开始遍历,默认不清楚数组是否部分有序
    for i in 1..<array.count {
        // 取出第i位元素 赋给临时变量 做后续比较
        let tmp = array[i]
        var j = i - 1
        // 当比到最左边或临时变量tmp小于比较的元素时
        while j>=0 && tmp < array[j] {
            // 比较的元素array[j],向右移动一位
            array[j + 1] = array[j]
            // j-1,并继续和左边元素比较
            j -= 1
        }
        // 临时变量tmp放到已排序好的数组的下一位
        array[j + 1] = tmp
    }
}

/*
 选择排序:O(n^2),交换次数少于冒泡
 */
func selectSort(_ nums: inout [Int]) {
    for i in 0..<nums.count {
        var k = i
        for j in (i + 1)..<nums.count {
            if nums[j] < nums[k] {
                k = j
            }
        }
        
        if i != k {
            nums.swapAt(i, k)
        }
    }
}

/*
 堆排序:O(nlogn)
 */
func heapSort(_ array: inout [Int]) {
    
    //构建大顶堆 从最后一个非叶子结点倒序遍历
    for i in (0...(array.count / 2 - 1)).reversed() {
        //从第一个非叶子结点从下至上,从右至左调整结构
        adjustHeap(&array, i, array.count)
    }
    //上面已将输入数组调整成堆结构
    for j in (1...(array.count - 1)).reversed() {
        //堆顶元素与末尾元素进行交换
        array.swapAt(0, j)
        adjustHeap(&array, 0, j)
    }
}

/*
 调整堆结构
 */
func adjustHeap(_ array: inout [Int],_ i: Int,_ length: Int) {
    var j = i
    //取出当前元素i
    let tmp = array[j]
    var k = 2 * i + 1
    while k < length {
        //左子节点小于右子节点
        if(k + 1 < length && array[k] < array[k + 1]) {
            //取到右子节点下标
            k += 1
        }
        if(array[k] > tmp){
            //如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
            array[j] = array[k]
            j = k
        } else {
            break
        }
        k = k * 2 + 1
    }
    //将tmp值放到最终的位置
    array[j] = tmp
}

/** 标准的快排 */
func quickSort(_ array: inout [Int], _ l: Int,_ r: Int) {
    if l >= r { return }
    
    var left = l
    var right = r
    let key = array[left]
    while left < right {
        while left < right && array[right] > key {
            right -= 1
        }
        array[left] = array[right]
        while left < right && array[left] < key {
            left += 1
        }
        array[right] = array[left]
    }
    array[left] = key
    quickSort(&array, l, left - 1)
    quickSort(&array, left + 1, r)
}

/** 快排: 利用二分查找思路进行快速排序,需要额外空间得到左右两边数据 */
func quickSort2(_ array: [Int]) -> [Int] {
    guard array.count > 1 else {
        return array
    }
    let num = array[array.count / 2]
    let left = array.filter { $0 < num }
    let mid = array.filter { $0 == num }
    let right = array.filter { $0 > num }
    return quickSort2(left) + mid + quickSort2(right)
}

/** 归并排序 */
func mergeSort(_ array: inout [Int]) {
    var helper = [Int].init(repeating: 0, count: array.count)
    slipSort(&array, 0, array.count - 1, &helper)
}

func slipSort(_ array: inout [Int], _ l: Int,_ r: Int,_ helper: inout [Int]) {
    if l >= r { return }
    
    let mid = (r - l) / 2 + l
    slipSort(&array, l, mid, &helper)
    slipSort(&array, mid + 1, r, &helper)
    mergeSliped(&array, l, mid, r, &helper)
}

func mergeSliped(_ array: inout [Int], _ l: Int,_ mid: Int,_ r: Int, _ helper: inout [Int]) {
    var l = l
    var m = mid
    var index = 0
    while l < m && m <= r {
        if array[l] < array[mid] {
            helper[index] = array[l]
            l += 1
        } else {
            helper[index] = array[m]
            m += 1
        }
        index += 1
    }
    
    while l < m {
        
    }
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容