关于经典排序算法的学习

496 阅读2分钟

为什么要学习这几种经典算法?因为我自己在力扣的时候,遇见瓶颈了,弄不出来了。因此来学习经典算法,和接下来的数据结构。

在找资料的时候,发现这张图片很好的描述了算法时间度等 算法时间度.webp

一、冒泡排序算法

func Bobble(_ arr:inout [Int]) -> [Int] {
    for element in 0 ..< arr.count{
        for sortElement in 0 ..< arr.count-element-1 {
            if arr[sortElement] > arr[sortElement+1] {
                //元祖
                (arr[sortElement],arr[sortElement+1]) = (arr[sortElement+1],arr[sortElement])
                //替换
//                let temp = arr[sortElement]
//                arr[sortElement] = arr[sortElement + 1]
//                arr[sortElement + 1] = temp
                //数组方法
//                arr.swapAt(sortElement, sortElement+1)
            }
            }
    }
    return arr
}

var a = [8,3,1,2,4,0]
print(Bobble(&a))

总结:

  1. 通过交换实现的稳定经典排序算法
  2. 难点在于:如何知道为什么要去arr.count-element-1?,其实很好理解,在n次排序中n-1次就完成了排序。

二、二分法算法

func binarySearch1(_ arr:[Int], _ locationKey:Int) -> Int {
    
    var left = 0
    var right = arr.count
    while left < right {
        let middle = left + (right-left)>>1
        if arr[middle] < locationKey {
            left = middle+1
        }else if arr[middle] > locationKey{
            right = middle-1
        }else {
            return middle
        }
    
    }
    return left
}
//关于github上swift写的二分法
func binarySearch2(_ arr:[Int], _ locationKey:Int) -> Int {
    
    var lowIndex = 0
    var highIndex = arr.count
    
    while lowIndex<highIndex {
        let middle = lowIndex + (highIndex - lowIndex)>>1
        if arr[middle] == locationKey {
            return middle
        }else if arr[middle] < locationKey{
            lowIndex = middle + 1
        }else{
            highIndex = middle
        }
    }
    return lowIndex
}

var a = [1,2,4,5,6,7,9]
print(binarySearch1(a, 5))

总结

  1. 此算法必须在排序之后使用
  2. 无任何难点(当中间值大于目标值时,右边-1;反之左边-1)

三、插入排序

func insertionSort(_ Array:[Int]) -> [Int] {
    var sortArr = Array
    
    for index in 1..<sortArr.count {
        var currentIndex = index
        while currentIndex > 0 && sortArr[currentIndex]<sortArr[currentIndex-1] {
            sortArr.swapAt(currentIndex, currentIndex-1)
            currentIndex-=1 //通过此条件来退出while循环或者再次排序,直到sortArr[currentIndex]>sortArr[currentIndex-1]
        }
    }
   return sortArr
}
let list = [ 10, -1, 3, 9, 2, 27, 8, 5, 1, 3, 0, 26 ]
print(insertionSort(list))

总结

  1. 此算法将数组从低到高(或从高到低)排序
  2. 原理:
    • 把数字放在一堆。这堆是未分类的。
    • 从堆中挑选一个数字。你选择哪一个并不重要,但从最上面选择最容易。
    • 将此数字插入到新数组中。
    • 从未排序的堆中选择下一个数字,并将其插入到新数组中。它要么在您选择的第一个数字之前或之后,因此现在这两个数字已排序。
    • 再次,从堆中挑选下一个数字并将其插入到正确排序位置的数组中。
    • 继续这样做,直到堆上没有更多数字。您最终会得到一个空堆和一个已排序的数组。
  3. 其实也不难理解,无非就是后者大于前者时(后者小于前者),两者交换,直到排序完成。

四、归并排序

//合并
func mergeSort(_ array: [Int]) -> [Int] {
  guard array.count > 1 else { return array }   
  let middleIndex = array.count / 2              
  
  let leftArray = mergeSort(Array(array[0..<middleIndex]))  
  let rightArray = mergeSort(Array(array[middleIndex..<array.count]))
  
  return merge(leftArray, rightArray)       
}
//合并算法--->有序排序
func merge(_ leftPile:[Int], _ rightPile:[Int]) -> [Int] {
    var leftIndex = 0
    var rightIndex = 0
    var sortArr = [Int]()
    sortArr.reserveCapacity(leftPile.count + rightPile.count)
    
    while leftIndex<leftPile.count && rightIndex<rightPile.count {
        if leftPile[leftIndex]<rightPile[rightIndex] {
            sortArr.append(leftPile[leftIndex])
            leftIndex += 1
        }else if leftPile[leftIndex]>rightPile[rightIndex]{
            sortArr.append(rightPile[rightIndex])
            rightIndex += 1
        }else{
            sortArr.append(leftPile[leftIndex])
            leftIndex += 1
            sortArr.append(rightPile[rightIndex])
            rightIndex += 1
        }
    }
    
    while leftIndex<leftPile.count {//左边未满,右边已满(左边小于,右边大于)
        sortArr.append(leftPile[leftIndex])
        leftIndex += 1
    }
    while rightIndex<rightPile.count {//右边未满,左边已满(左边大于,右边小于)
        sortArr.append(rightPile[rightIndex])
        rightIndex += 1
    }
    return sortArr
}
let list = [ 10, -1, 3, 9, 2]
print(mergeSort(list))

总结

  1. 在看这个算法的时候,一直在纠结递归是什么时候结束。重复认真看了几遍之后,发现自己进入了一个死胡同,一直在想既然递归结束了,为什么还要返回元素? 最后我认为在分裂成一个元素的时候,递归就结束了,返回的元素,其实是在调用合并排序的这一个方法,然后在合并算法里面返回最终的有序数组
  2. 这个算法里面的合并算法不是很复杂,我认为难点是在递归那里。

五、选择排序

func selectionSort(_ arr:[Int]) -> [Int] {
    var sortArr = arr
    let count = sortArr.count
    for index in 0..<count {
        var minIndex = index // 拿到最小索引
        for currentIndex in minIndex+1..<count {//在[最小索引+1,count)中找到最小值索引
            if sortArr[minIndex]>sortArr[currentIndex] {
                minIndex = currentIndex//交换索引
            }
        }
        
        sortArr.swapAt(index, minIndex)
    }
    
    return sortArr
}

let arr = [10,-9,8,2,4,3]
print(selectionSort(arr))

总结

  1. 需要注意的是,要在[最小索引+1,数组元素总数)之间

参考文章

swift算法->github算法地址
10分钟看懂10大经典算法(Swift代码实现)