• [Swift]八大排序算法(一):冒泡排序


    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
    ➤微信公众号:山青咏芝(shanqingyongzhi)
    ➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/ 
    ➤GitHub地址:https://github.com/strengthen/LeetCode
    ➤原文地址:https://www.cnblogs.com/strengthen/p/9866220.html 
    ➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
    ➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

    排序分为内部排序和外部排序。

    内部排序:是指待排序列完全存放在内存中所进行的排序过程,适合不太大的元素序列。

    外部排序:指的是大文件的排序,即待排序的记录存储在外存储器上,待排序的文件无法一次装入内存,需要在内存和外部存储器之间进行多次数据交换,以达到排序整个文件的目的。

    当N小于20的时候,插入排序具有最好的性能。

    当N大于20时,快速排序具有最好的性能,尽管归并排序(merge sort)和堆排序(heap sort)复杂度都为nlog2(n)。


    冒泡排序算法

    1、算法原理:

    (1)、比较相邻的元素。如果第一个比第二个大,就交换他们两个。

    (2)、对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。

    (3)、针对所有的元素重复以上的步骤,除了最后一个。

    (4)、持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较

    2、算法分析:时间复杂度

    (1)、若文件的初始状态是正序的,一趟扫描即可完成排序。

    所需的关键字比较次数和记录移动次数均达到最小值:

    所以,冒泡排序最好的时间复杂度为  

    (2)、若初始文件是反序的,需要进行

    趟排序。每趟排序要进行(1≤i≤n-1)次关键字的比较,且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值:

     

     

    冒泡排序的最坏时间复杂度为 

    综上,因此冒泡排序总的平均时间复杂度为 

    3、算法稳定性

    冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,是不会再交换的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。


     ViewController.swift文件:运行时间(29.0735s)

      1 import UIKit
      2 //对数组类型进行扩展
      3 extension Array
      4 {
      5     //扩展方法:用来交换数组中的两个位置的元素
      6     fileprivate mutating func swap(i:Int,j:Int)
      7     {
      8         //通过一个临时变量,交换数组中的两个不同位置的元素
      9         let temp = self[i]
     10         self[i] = self[j]
     11         self[j] = temp
     12     }
     13 }
     14 
     15 //对具有可比较性的数组进行扩展
     16 //以实现冒泡排序功能
     17 extension Array where Element:Comparable
     18 {
     19     //添加一个方法,用来实现具体的排序功能
     20     //使用mutating关键字修饰方法,
     21     //是为了能在方法内部修改自身变量的值
     22     mutating func bubbleSort()
     23     {
     24         //对数组自身进行从头至倒数第二的遍历
     25         for i in 0..<self.count-1
     26         {
     27             //从数组的尾部开始
     28             //向上一个循环语句遍历到的元素进行遍历
     29             for j in (i+1...self.count-1).reversed()
     30             {
     31                 //判断两个相邻元素的大小
     32                 if self[j] < self[j-1]
     33                 {
     34                     //以交换值的方式,调整两个元素的顺序
     35                     swap(i: j, j: j-1)
     36                 }
     37             }
     38         }
     39     }
     40 }
     41 
     42 class ViewController: UIViewController {
     43     //上面是冒泡排序算法的编写。
     44     //现在通过可视化的方式,使用冒泡排序算法
     45     
     46     //属性1:用来存储需要排序的数组
     47     var result : Array<Int> = Array<Int>()
     48     //属性2:统计排序花费的时间
     49     var date : Date!
     50     
     51     override func viewDidLoad() {
     52         super.viewDidLoad()
     53         // Do any additional setup after loading the view, typically from a nib.
     54         //初始化一个整形数组
     55         var array : Array<Int> = Array<Int>()
     56         //将1至100的100个整数,存入到该数组中
     57         for i in 1...100
     58         {
     59             array.append(i)
     60         }
     61         //添加一个循环语句,
     62         //用来生成一个由100个随机整数组成的数组
     63         for _ in 1...100
     64         {
     65             //首先根据数组的长度,
     66             //获得一个1至100的随机整数
     67             let temp = Int(arc4random() % UInt32(array.count))+1
     68             //根据随机值从数组中获得指定位置的整数,
     69             //并存储在用来排序的数组中
     70             let num = array[temp-1]
     71             result.append(num)
     72             //从原数组中移该随机数,以避免获得重复的数字
     73             array.remove(at: temp-1)
     74         }
     75         //添加一个循环语句,
     76         //用来生成100个自定义视图对象
     77         for i in 1...100
     78         {
     79             //初始化自定义视图对象
     80             let num = result[i-1]
     81             //并设置它的显示区域。
     82             //其中视图的高度,是当前数组中的数字的两倍大小
     83             let view = SortView(frame: CGRect(x:10+i*3,y:200,2,height:num*2))
     84             view.backgroundColor = .black
     85             //设置视图的标识值
     86             view.tag = i
     87             //并将视图添加到当前视图控制器的根视图
     88             self.view.addSubview(view)
     89         }
     90         //然后添加一个按钮
     91         //当用户点击该按钮时对数组进行排序
     92         let bt = UIButton(frame: CGRect(x: 10, y: 340,  300, height: 40))
     93         //设置背景按钮的背景颜色为橙色
     94         bt.backgroundColor = .orange
     95         //设置按钮在正常状态下的标题文字
     96         bt.setTitle("Sort", for: .normal)
     97         //给按钮对象绑定点击事件,
     98         bt.addTarget(self, action: #selector(reOrderView), for: .touchUpInside)
     99         //将按钮添加到当前视图控制器的根视图
    100         self.view.addSubview(bt)
    101     }
    102     
    103     //添加一个方法,用来响应按钮的点击事件
    104     @objc func reOrderView()
    105     {
    106         //获得当前的日期和时间
    107         date = Date()
    108         //在一个全局队列中,以异步的方式对数组进行排序
    109         //并实时调整和数组中的数值相对应的视图的位置
    110         DispatchQueue.global().async
    111         {
    112             //下面的代码,是对上方的冒泡排序代码的拷贝:
    113             //首先添加一个循环语句
    114             //对数组自身进行从头至尾的遍历
    115             for i in 0..<self.result.count-1
    116             {
    117                 //从数组尾部开始
    118                 //向上一个循环语句遍历到的元素进行遍历
    119                 for j in (i+1...self.result.count-1).reversed()
    120                 {
    121                     //判断两个相邻元素的大小,
    122                     //并以交换值的方式,调整两个元素的顺序
    123                     if self.result[j] < self.result[j-1]
    124                     {
    125                         //由于需要对界面元素进行调整,
    126                         //所以需要切换至主线程
    127                         weak var weak_self = self
    128                         DispatchQueue.main.async
    129                         {
    130                             //根据标识值,
    131                             //获得和需要交换顺序的数组元素相对应的视图对象
    132                             let view1 = weak_self?.view.viewWithTag(j+1)
    133                             let view2 = weak_self?.view.viewWithTag(j)
    134                             //获得两个视图对象的水平坐标X的值
    135                             let posX1 = view1?.frame.origin.x
    136                             let posX2 = view2?.frame.origin.x
    137                             //然后交换两个视图对象的水平坐标的值
    138                             //从而实现两个视图对象的位置的交换
    139                             view1?.frame.origin.x = posX2!
    140                             view2?.frame.origin.x = posX1!
    141                             //记得更换两个视图对象的标识值
    142                             view1?.tag = j
    143                             view2?.tag = j+1
    144                             //交换数组中两个元素的位置,
    145                             //从而实现了数据和界面的同步更新
    146                             self.result.swap(i: j, j: j-1)
    147                         }
    148                         //使线程休眠0.01秒,
    149                         //以方便观察排序的视觉效果
    150                         Thread.sleep(forTimeInterval: 0.01)
    151                     }
    152                 }
    153             }
    154             //获得排序后的系统时间,
    155             //并在控制台输出两个时间的差值,
    156             //从而获得排序所花费的大致时间。
    157             //考虑线程休眠的影响,此数据仅做参考
    158             let endDate = Date()
    159             print(endDate.timeIntervalSince(self.date))
    160         }
    161     }
    162     
    163     override func didReceiveMemoryWarning() {
    164         super.didReceiveMemoryWarning()
    165         // Dispose of any resources that can be recreated.
    166     }
    167 }

    SortView.swift文件

     1 import UIKit
     2 
     3 class SortView: UIView {
     4     //首先重写父类的初始化方法
     5     override init(frame: CGRect)
     6     {
     7         //设置自定义视图对象的显示区域
     8         super.init(frame: frame)
     9         self.frame = frame
    10     }
    11 
    12     //添加一个必须实现的初始化方法
    13     required init?(coder aDecoder: NSCoder) {
    14         fatalError("init(coder:) has not been implemented")
    15     }
    16     
    17     //重写父类的重新布局子视图方法
    18     //将在此视图中对视图进行外观设置
    19     override func layoutSubviews()
    20     {
    21         //首先获得自定义视图在界面中对Y轴坐标
    22         let y: CGFloat = 300 - frame.height
    23         //然后重新设置自定义视图的位置
    24         self.frame = frame
    25         self.frame.origin.y = y
    26         //根据自定义视图的高度,计算一个权重数值
    27         //用于生成不同的背景颜色
    28         let weight = frame.height / 200
    29         //生成不同y色相的颜色对象,从而给自定义视图设置不同的背景颜色
    30         //然后打开ViewController.swift文件
    31         let color = UIColor(hue: weight, saturation: 1, brightness: 1, alpha: 1)
    32         self.backgroundColor = color
    33     }
    34     /*
    35     // Only override draw() if you perform custom drawing.
    36     // An empty implementation adversely affects performance during animation.
    37     override func draw(_ rect: CGRect) {
    38         // Drawing code
    39     }
    40     */
    41 }
  • 相关阅读:
    H5页面富文本展示图片之间存在空隙
    如何关闭eslint语法校验
    K8S service详解
    vim添加或删除多行注释
    K8S 弹性伸缩
    Load高问题排查
    Dockerfile CMD和ENTRYPOINT
    nginx配置
    sed命令
    Pod排错指南
  • 原文地址:https://www.cnblogs.com/strengthen/p/9866220.html
Copyright © 2020-2023  润新知