排序算法一之快排、归并、堆排(swift 实现)

1.快排

  1. 思想
    快排选取一个作为基准,把小的数放到基准数的左边,把大的数放到基准数的右边。再以基准数左边、右边分别进行快排。
    快排更像树的前序遍历

  2. 源码

func quick(arr: inout [Int]) {
    quickSortArray(array: &arr, left: 0, right: arr.count-1)
}

func quickSortArray(array:inout [Int],left:Int,right:Int) {
        if left >= right {
            return
        }
        
        var l = left,r = right
        let key = array[left]
        while l < r {
            while l < r && key<=array[r] {
                r -= 1
            }
            if l < r {
                array[l] = array[r]
            }
            
            while l<r && key>=array[l] {
                l += 1
            }
            if l < r {
                array[r] = array[l]
            }
        }
        array[l] = key
        
        quickSortArray(array: &array, left: left, right: l-1)
        quickSortArray(array: &array, left: l+1, right: right)
    }
  1. 时间复杂度
    快排在最糟糕得情况下时间复杂度是O(n²),平均的复杂度是O(nlogn)
    空间复杂度为o(1)

  2. 示例
    72,6,57,88,60,42,83,73,48,85
    第一趟:选取72为基数
    从右查找比72小的数,是48,下标是8。结果:48,6,57,88,60,42,83,73,48,85
    从左查找比72大的数,是88,下标是3。结果:48,6,57,88,60,42,83,73,88,85
    从7开始查找比72小的数,是42,下标是5。结果:48,6,57,42,60,42,83,73,88,85
    从3开始查找比72大的数,没有了。用72填充到下标是5的数:48,6,57,42,60,72,83,73,88,85

2.归并

  1. 思想
    归并是先把数拆成单个再进行合并,有点像树的后序遍历。

  2. 源码

func merge(arr: inout [Int]) {
        var temp = Array.init(repeating: 0, count: arr.count)
        mergeSort(arr: &arr, left: 0, right: arr.count-1,temp:&temp)
        print("排序结果:\(arr)")
    }
    
    func mergeSort(arr:inout [Int],left:Int,right:Int,temp:inout [Int]) {
        if left>=right{
            return
        }
        let middle = (right+left)/2
        mergeSort(arr: &arr, left: left, right: middle,temp: &temp)
        mergeSort(arr: &arr, left: middle+1, right: right,temp: &temp)
        mergeTwoArr(arr: &arr, left: left, middle: middle, right: right,temp: &temp)
    }

func mergeTwoArr(arr:inout [Int],left:Int,middle:Int,right:Int,temp:inout [Int]) {
        var i = left
        var j = middle+1
        var t = 0
        while i<=middle && j<=right {
            if arr[i]<=arr[j] {
                temp[t] = arr[i]
                i+=1
            }else{
                temp[t] = arr[j]
                j+=1
            }
            t+=1
        }
        while i<=middle {
            temp[t] = arr[i]
            t+=1;i+=1
        }
        while j<=right {
            temp[t] = arr[j]
            t+=1;j+=1
        }
        
        t = 0
        for j in left...right {
            arr[j] = temp[t]
            t+=1
        }
        
    }
  1. 时间复杂度
    在最坏、最佳、平均情况下归并排序时间复杂度均为o(nlogn)
    归并的空间复杂度为o(n),需要借助额外的空间

3.堆排

  1. 思想:二叉树的应用
    关键在于堆的调整,升序需要大顶堆,把小的数往下沉。
    先构建大顶堆,再倒叙遍历数组,交换第0个与第i个位置,不断调整大顶堆

  2. 源码

func heap(arr: inout [Int]) {
        if arr.count == 0 {
            return
        }
        //构建大顶堆
        for i in (0...arr.count/2).reversed() {
            heapAdjust(array: &arr, parent: i, length: arr.count)
        }
        print("构建堆:\(arr)")

        for j in (1..<arr.count).reversed() {
            ArrayUtil.swap(arr: &arr, i: 0, j: j)
            heapAdjust(array: &arr, parent: 0, length: j)
        }
        print("\(arr)")
    }
    
func heapAdjust(array:inout [Int], parent:Int,length:Int) {
        var parentIndex = parent
        let temp = array[parentIndex]
        var child = 2*parentIndex+1//2n+1:左孩子,2n+2:右孩子
        //把最小的数据放在大于孩子节点的位置
        while child<length {
            //取左右孩子节点的最大节点
            if child+1<length && array[child]<array[child+1]{
                child += 1
            }
            if temp>array[child]{//父节点大于左右孩子节点
                break
            }
            array[parentIndex] = array[child]
            parentIndex = child
            
            child = 2*child+1
        }
        array[parentIndex] = temp
    }
  1. 时间复杂度
    时间复杂度是O(nlogn)

总结:

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