Sorting Algorithms swift :( e) merge sort

Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/lin1109221208/article/details/90694062

1 Overview

Merge sort merge operation is based on an effective sort of development, the algorithm is used mainly ideological divide and conquer (divide and conquer) a.

In merge sort, sort the array needs to be split, which is small enough to split, when the array is split in only one element, then it is effective to split the array, then these ordered array twenty-two merge, and compare the process of the merger, the combined generation of new array is still in order, then merge again ordered array merge, repeat this process until the entire array is ordered so far.

2, algorithm principle

Idea: divide and rule, is about a large problem into smaller problems and solve them, can be divided into first split and the merger, that the merger Split +

step:

1) The number of stack on unsorted

2) the stack into two parts, i.e. two digital stack unsorted

3) continue to divide two numbers unsorted heap, know not to split up, and finally, you will have the n heap, each heap is a digital

4) by sequentially pairing the heap begin to merge, during each merger, the content being arranged in sorted order

 

3, for example

Of [2, 1, 5, 4, 9] Sort

1) The array element split into five separate arrays, each array element contains a

2) The split twenty-two merge array, and sorting, up until the entire array is ordered

 

4, algorithm

1) top-down recursive implementation

Split + merge

func mergeSort(_ array: [Int])->[Int]{
        //1、如果数组为空或包含单个元素,则无法将其拆分为更小的部分,返回数组就行
        guard array.count > 1 else{
            return array
        }
        //2、找到中间索引
        let middleIndex = array.count/2
        
        //3、使用上一步中的中间索引,递归的分割数组的左侧
        let leftArray = mergeSort(Array(array[0..<middleIndex]))
        
        //4、递归的分割数组的右侧
        let rightArray = mergeSort(Array(array[middleIndex..<array.count]))
        
        //5、将所有值合并在一起,确保它始终排序
        return merge(leftArray, rightArray)
    }
    //合并算法
    private func merge(_ leftPile : [Int], _ rightPile : [Int])->[Int]{
        //1、合并时需要两个索引来跟踪两个数组的进度
        var leftIndex = 0
        var rightIndex = 0
        
        //2、合并后的数组,目前时空的,需要在下面的操作中添加其他数组中的元素构建
        var orderedPile = [Int]()
        
        //3、while循环将比较左侧和右侧的元素,并添加到orderpile。同时确保结果保持有序
        while leftIndex<leftPile.count && rightIndex<rightPile.count {
            if leftPile[leftIndex] < rightPile[rightIndex]{
                orderedPile.append(leftPile[leftIndex])
                leftIndex += 1
            }else if leftPile[leftIndex]>rightPile[rightIndex]{
                orderedPile.append(rightPile[rightIndex])
                rightIndex += 1
            }else{
                orderedPile.append(leftPile[leftIndex])
                leftIndex += 1
                orderedPile.append(rightPile[rightIndex])
                rightIndex += 1
            }
        }
        
        //4、如果前一个while循环完成,意味着left/right中的一个内容已经完全合并到orderpile中,不需要再比较,只需要依次添加剩下的数组的剩余元素
        while leftIndex < leftPile.count {
            orderedPile.append(leftPile[leftIndex])
            leftIndex += 1
        }
        
        while rightIndex < rightPile.count {
            orderedPile.append(rightPile[rightIndex])
            rightIndex += 1
        }
        
        return orderedPile
    }

2) top-down non-recursive

   func mergeSort1(_ array: [Int])->[Int]{
        //1、如果数组为空或包含单个元素,则无法将其拆分为更小的部分,返回数组就行
        guard array.count > 1 else{
            return array
        }
        
        //2、将数组中的每一个元素放入一个数组中
        var tampArr : [[Int]] = []
        for item in array {
            var subArr : [Int] = []
            subArr.append(item)
            tampArr.append(subArr)
        }
        
        //3、对数组中的数组进行合并,直到合并完成为止
        while tampArr.count != 1 {
            print(tampArr)
            var i = 0
            while i < tampArr.count-1 {
                tampArr[i] = merge(tampArr[i], tampArr[i+1])
                tampArr.remove(at: i+1)
                i += 1
            }
        }
        return tampArr.first!
    }

3) bottom-iterative implementation

When the array is sorted, and skips the resolution step begins each array element immediately combined

func mergeSortBottomUp<T>(_ array : [T], _ isOrderedBefore:(T, T)->Bool)->[T]{
        let n = array.count
        
        //1、归并排序需要一个临时工作数组,因为不能再原数组合并同时又覆盖原有内容---使用两个数组,将使用d的值在他们之前切换,它是0/1,数组 z[d] 用于读,数组 z[1-d] 用于写,称为双缓冲
        var z = [array, array]
        var d = 0
        
        //2、自下而上与x自上而下工作方式相同,都是先合并每个元素的小堆,在合并每个堆两个元素---堆的大小由 width 给出,width初始是1,但在每次迭代结束时,width *2,所以外循环确定合并的堆的大小
        var width = 1
        while width < n {
            var i = 0
            //3、内循环穿过堆并将每对堆合并成一个较大堆,结果写入z[1-d]给出的数组中
            while i < n{
                var j = i
                var left = i
                var right = i+width
                
                let lmax = min(left+width, n)
                let rmax = min(right+width, n)
                
                //4、与自下而上逻辑相同,区别在于自上而下使用双缓冲,从z[d]读 并写入 z[1-d],还是用isOrderedBefore函数来比较元素,是通用的
                while left < lmax && right < rmax{
                    if isOrderedBefore(z[d][left], z[d][right]) {
                        z[1-d][j] = z[d][left]
                        left += 1
                    }else{
                        z[1-d][j] = z[d][right]
                        right += 1
                    }
                    j += 1
                }
                while left<lmax {
                    z[1-d][j] = z[d][left]
                    j += 1
                    left += 1
                }
                while right < rmax {
                    z[1-d][j] = z[d][right]
                    j += 1
                    right += 1
                }
                i += width*2
            }
            width *= 2
            
            //5、z[d]的大小width 的堆已经合并为数组z[1-d]中更大的大小width*2,这里 交换活动数组,方便在下一步中我们从刚刚创建的新堆中读取
            d = 1-d
        }
        return z[d]
    }

4) call

        var array5 = [2, 1, 5, 4, 9]
        //自上而下-递归
        //array5 = mergeSort(array5)
        //自上而下-非递归
        array5 = SortSummary.mergeSort1(array5)
        //自下而上-迭代
        print(array5)
        array5 = mergeSortBottomUp(array5, <)


运行结果:

[1, 2, 4, 5, 9]
[1, 2, 4, 5, 9] 

5, the time complexity

The best, worst and average case time complexity will always be O (nlogn).

 

github Code

Note: The sort of specific implementation code in  SortSummary.swift  calling file is in ViewController.swift

Guess you like

Origin blog.csdn.net/lin1109221208/article/details/90694062