为什么要学习这几种经典算法?因为我自己在力扣的时候,遇见瓶颈了,弄不出来了。因此来学习经典算法,和接下来的数据结构。
在找资料的时候,发现这张图片很好的描述了算法时间度等
一、冒泡排序算法
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))
总结:
- 通过交换实现的稳定经典排序算法
- 难点在于:如何知道为什么要去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;反之左边-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))
总结
- 此算法将数组从低到高(或从高到低)排序
- 原理:
- 把数字放在一堆。这堆是未分类的。
- 从堆中挑选一个数字。你选择哪一个并不重要,但从最上面选择最容易。
- 将此数字插入到新数组中。
- 从未排序的堆中选择下一个数字,并将其插入到新数组中。它要么在您选择的第一个数字之前或之后,因此现在这两个数字已排序。
- 再次,从堆中挑选下一个数字并将其插入到正确排序位置的数组中。
- 继续这样做,直到堆上没有更多数字。您最终会得到一个空堆和一个已排序的数组。
- 其实也不难理解,无非就是后者大于前者时(后者小于前者),两者交换,直到排序完成。
四、归并排序
//合并
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))
总结
- 在看这个算法的时候,一直在纠结递归是什么时候结束。重复认真看了几遍之后,发现自己进入了一个死胡同,一直在想既然递归结束了,为什么还要返回元素? 最后我认为在分裂成一个元素的时候,递归就结束了,返回的元素,其实是在调用合并排序的这一个方法,然后在合并算法里面返回最终的有序数组
- 这个算法里面的合并算法不是很复杂,我认为难点是在递归那里。
五、选择排序
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,数组元素总数)之间
参考文章
swift算法->github算法地址
10分钟看懂10大经典算法(Swift代码实现)