ios开发——常用经典算法OC篇&冒泡/快速

冒泡排序与快速排序

1、序言

ios开发中涉及到算法的地方还真不多,除非你的应用程序真的非常大,或者你想你的应用程序性能非常好才会去想到关于算法方面的性能优化,而在ios开发中真的能用得到的也就是关于排序的,当然如果你是做游戏的话那么你可能会涉及到不少的算法或者优化问题,但是这不是本篇文章讨论的范围。

后面的文章中,我将会给大家详细介绍八大算法。

2、冒泡排序

2.1 引出

前面的两篇博客里讲的插入排序是基于“逐个记录插入”,选择排序是基于“选择”,那么冒泡排序其实是基于“交换”。每次从第一个记录开始,一、二两个记录比较,大的往后放,二三两个记录比较...依次类推,这就是一趟冒泡排序。每一趟冒泡排序后,无序序列中值最大的记录冒到序列末尾,所以称之为冒泡排序。

2.2 代码

 1 //冒泡排序
 2 void bubbleSort(int *a,int n)
 3 {
 4     int i,j;
 5     for(i=1;i<n;i++)
 6         for(j=1;j<n-i+1;j++){
 7             if(a[j+1]<a[j]){
 8                 a[j]=a[j]+a[j+1];
 9                 a[j+1]=a[j]-a[j+1];
10                 a[j]=a[j]-a[j+1];
11             }
12         }
13 }

冒泡排序算法:

 1 冒泡排序代码
 2
 3  static void Main(string[] args)
 4         {
 5             ////五次比较
 6              for (int i = 1; i <= 5; i++)
 7             {
 8                 List<int> list = new List<int>();
 9                 //插入2k个随机数到数组中
10                 for (int j = 0; j < 2000; j++)
11                 {
12                     Thread.Sleep(1);
13                     list.Add(new Random((int)DateTime.Now.Ticks).Next(0, 100000));
14                 }
15                 Console.WriteLine("\n第" + i + "次比较:");
16                 Stopwatch watch = new Stopwatch();
17                 watch.Start();
18                 var result = list.OrderBy(single => single).ToList();
19                 watch.Stop();
20                 Console.WriteLine("\n快速排序耗费时间:" + watch.ElapsedMilliseconds);
21                 Console.WriteLine("输出前是十个数:" + string.Join(",", result.Take(10).ToList()));
22                 watch.Start();
23                 result = BubbleSort(list);
24                 watch.Stop();
25                 Console.WriteLine("\n冒泡排序耗费时间:" + watch.ElapsedMilliseconds);
26                 Console.WriteLine("输出前是十个数:" + string.Join(",", result.Take(10).ToList()));
27                 Console.ReadKey();
28             }
29
30       }
31
32  //冒泡排序算法
33         private static List<int> BubbleSort(List<int> list)
34         {
35             int temp;
36             //第一层循环: 表明要比较的次数,比如list.count个数,肯定要比较count-1次
37             for (int i = 0; i < list.Count - 1;i++ )
38             {
39                 //list.count-1:取数据最后一个数下标,47
40                 //j>i: 从后往前的的下标一定大于从前往后的下标,否则就超越了。
41                 for (var j = list.Count-1; j > i;j-- )
42                 {
43                     //如果前面一个数大于后面一个数则交换
44                     if (list[j - 1] > list[j])
45                     {
46                         temp = list[j - 1];
47                         list[j - 1] = list[j];
48                         list[j] = temp;
49                     }
50                 }
51
52             }
53             return list;
54         }

2.3 效率分析

相对于简单选择排序,冒泡排序交换次数明显更多。它是通过不断地交换把最大的数冒出来。冒泡排序平均时间和最坏情况下(逆序)时间为o(n^2)。最佳情况下虽然不用交换,但比较的次数没有减少,时间复杂度仍为o(n^2)。此外冒泡排序是稳定的。

3、快速排序

3.1 引出

快速排序是冒泡排序的一种改进,冒泡排序排完一趟是最大值冒出来了,那么可不可以先选定一个值,然后扫描待排序序列,把小于该值的记录和大于该值的记录分成两个单独的序列,然后分别对这两个序列进行上述操作。这就是快速排序,我们把选定的那个值称为枢纽值,如果枢纽值为序列中的最大值,那么一趟快速排序就变成了一趟冒泡排序。

3.2 代码

两种版本,第一种是参考《数据结构》,在网上这种写法很流行。第二种是参考《算法导论》,实现起来较复杂。

 1 //快速排序(两端交替着向中间扫描)
 2 void quickSort1(int *a,int low,int high)
 3 {
 4     int pivotkey=a[low];//以a[low]为枢纽值
 5     int i=low,j=high;
 6     if(low>=high)
 7         return;
 8     //一趟快速排序
 9     while(i<j){//双向扫描
10         while(i < j && a[j] >= pivotkey)
11             j--;
12         a[i]=a[j];
13         while(i < j && a[i] <= pivotkey)
14             i++;
15         a[j]=a[i];
16     }
17     a[i]=pivotkey;//放置枢纽值
18     //分别对左边、右边排序
19     quickSort1(a,low,i-1);
20     quickSort1(a,i+1,high);
21 }
22
23 //快速排序(以最后一个记录的值为枢纽值,单向扫描数组)
24 void quickSort2(int *a,int low,int high)
25 {
26     int pivotkey=a[high];//以a[high]为枢纽值
27     int i=low-1,temp,j;
28     if(low>=high)
29         return;
30     //一趟快速排序
31     for(j=low;j<high;j++){
32         if(a[j]<=pivotkey){
33             i++;
34             temp=a[i];
35             a[i]=a[j];
36             a[j]=temp;
37         }
38     }
39     i++;
40     //放置枢纽值
41     temp=a[i];
42     a[i]=pivotkey;
43     a[high]=temp;
44     //分别对左边、右边排序
45     quickSort2(a,low,i-1);
46     quickSort2(a,i+1,high);
47 }

快速排序算法:

 1 快速排序法
 2
 3  static void Main(string[] args)
 4         {
 5
 6             //5次比较
 7             for (int i = 1; i <= 5; i++)
 8             {
 9                 List<int> list = new List<int>();
10                 //插入200个随机数到数组中
11                 for (int j = 0; j < 200; j++)
12                 {
13                     Thread.Sleep(1);
14                     list.Add(new Random((int)DateTime.Now.Ticks).Next(0, 10000));
15                 }
16                 Console.WriteLine("\n第" + i + "次比较:");
17                 Stopwatch watch = new Stopwatch();
18                 watch.Start();
19                 var result = list.OrderBy(single => single).ToList();
20                 watch.Stop();
21                 Console.WriteLine("\n系统定义的快速排序耗费时间:" + watch.ElapsedMilliseconds);
22                 Console.WriteLine("输出前是十个数:" + string.Join(",", result.Take(10).ToList()));
23                 watch.Start();
24                 new QuickSortClass().QuickSort(list, 0, list.Count - 1);
25                 watch.Stop();
26                 Console.WriteLine("\n俺自己写的快速排序耗费时间:" + watch.ElapsedMilliseconds);
27                 Console.WriteLine("输出前是十个数:" + string.Join(",", list.Take(10).ToList()));
28                 Console.ReadKey();
29             }
30         }
31
32  public class QuickSortClass
33     {
34
35         ///<summary>
36         ////// 分割函数
37         ///</summary>
38         //////<param name="list">待排序的数组</param>
39         ///<param name="left">数组的左下标</param>
40         //////<param name="right"></param>
41         ///<returns></returns>
42          public int Division(List<int> list, int left, int right)
43          {
44              //首先挑选一个基准元素
45              int baseNum = list[left];
46              while (left < right)
47              {
48                  //从数组的右端开始向前找,一直找到比base小的数字为止(包括base同等数)
49                  while (left < right && list[right] >= baseNum)
50                      right = right - 1;
51                  //最终找到了比baseNum小的元素,要做的事情就是此元素放到base的位置
52                  list[left] = list[right];
53                  //从数组的左端开始向后找,一直找到比base大的数字为止(包括base同等数)
54                  while (left < right && list[left] <= baseNum)
55                      left = left + 1;
56                  //最终找到了比baseNum大的元素,要做的事情就是将此元素放到最后的位置
57                  list[right] = list[left];
58              }
59              //最后就是把baseNum放到该left的位置
60              list[left] = baseNum;
61              //最终,我们发现left位置的左侧数值部分比left小,left位置右侧数值比left大
62              //至此,我们完成了第一篇排序
63              return left;
64          }
65         public void QuickSort(List<int> list, int left, int right)
66         {
67             //左下标一定小于右下标,否则就超越了
68             if (left < right)
69             {
70                 //对数组进行分割,取出下次分割的基准标号
71                 int i = Division(list, left, right);
72                 //对“基准标号“左侧的一组数值进行递归的切割,以至于将这些数值完整的排序
73                 QuickSort(list, left, i - 1);
74                 //对“基准标号“右侧的一组数值进行递归的切割,以至于将这些数值完整的排序
75                 QuickSort(list, i + 1, right);
76             }
77         }
78     }

3.3 效率分析

快速排序时间与划分是否对称有关。快速排序的平均时间复杂度为o(n*logn),至于为什么是o(n*logn),请参考《算法导论》第7章,书中用递归树的方法阐述了快速排序平均时间。且常数因子很小,所以就平均时间而言,快速排序是很好的内部排序方法。最佳情况下(每次划分都对称)时间复杂度o(n*logn)。最坏情况下(每次划分都不对称,如输入的序列有序或者逆序时)时间复杂度为o(n^2),所以在待排序序列有序或逆序时不宜选用快速排序。此外,快速排序是不稳定的。

最佳情况下,每次划分都是对称的,由于枢纽值不再考虑,所以得到的两个子问题的大小不可能大于n/2,同时一趟快速排序时间为o(n),所以运行时间递归表达式:

T(n)<=2T(n/2)+o(n)。这个递归式的解法请参考下一篇博客中归并排序效率分析。其解为T(n)=o(n*logn)。

最坏情况下,每次划分都很不对称,T(n)=T(n-1)+o(n),可以用递归树来解,第i层的代价为n-i+1.总共有n层。把每一层代价加起来有n-1个n相加。所以这个递归式的解为T(n)=o(n^2),此时就是冒泡排序。

时间: 2024-10-22 01:58:36

ios开发——常用经典算法OC篇&冒泡/快速的相关文章

iOS开发——完整项目实战OC篇&amp;百思不得姐第四天

iOS开发——完整项目实战OC篇&百思不得姐第四天 上午 一:自定义按钮使用九宫格布局 二:控件不能点击 三:获取用户点击了那个按钮 四:调整按钮内部控件的位置:主流->上下 五:不能直接使用self.navigationController中或者View中获取导航控制器 方法一: 方法二: 六:布局取整 1 // 总行数 2 3 // NSUInteger rows = sqaures.count / maxCols; 4 5 // if (sqaures.count % maxCols)

iOS开发——高级技术精选OC篇&amp;Runtime之字典转模型实战

Runtime之字典转模型实战 如果您还不知道什么是runtime,那么请先看看这几篇文章: http://www.cnblogs.com/iCocos/p/4734687.html http://www.cnblogs.com/iCocos/p/4676679.html http://www.cnblogs.com/iCocos/p/4725527.html 关于runtime的详细介绍及其相关的小实例 好了,这里就不多废话了,直接开干! 先来看看怎么使用Runtime给模型类赋值 iOS开发

iOS开发——网络使用技术OC篇&amp;网络爬虫-使用正则表达式抓取网络数据

网络爬虫-使用正则表达式抓取网络数据 关于网络数据抓取不仅仅在iOS开发中有,其他开发中也有,也叫网络爬虫,大致分为两种方式实现 1:正则表达 2:利用其他语言的工具包:java/Python 先来看看网络爬虫的基本原理: 一个通用的网络爬虫的框架如图所示: 网络爬虫的基本工作流程如下: 1.首先选取一部分精心挑选的种子URL: 2.将这些URL放入待抓取URL队列: 3.从待抓取URL队列中取出待抓取在URL,解析DNS,并且得到主机的ip,并将URL对应的网页下载下来,存储进已下载网页库中.

iOS开发——完整项目实战OC篇&amp;百思不得姐第十一天

百思不得姐第十一天 一:模型中没有ID这个属性 为模型增加一个属性ID,设置名字替换 /** id */ @property (nonatomic, copy) NSString *ID; 替换: + (NSDictionary *)replacedKeyFromPropertyName {     return @{@"ID" : @"id"}; } 二:错误的将数组当作字典来用(其实就是没有数据,比如刷新数据已经没有了,或者直接就是0) 通过堆栈定位错误 最后一

iOS开发——项目实战技术OC篇&amp;XMPP简单总结

XMPP简单总结 最近面试被问到了一个问题,笔者当时就懵了:什么XMPP,平时怎么使用,使用过程中遇到什么问题?. 但是还是通过记忆,简单的说了一下自己所知道了,不过那并没有撒卵用,所以你懂的 XMPPFramework是一个OS X/iOS平台的开源项目,使用Objective-C实现了XMPP协议(RFC-3920),同时还提供了用于读写XML的工具,大大简化了基于XMPP的通信应用的开发. 1.关于连接的 1 //此方法在stream开始连接服务器的时候调用 2 - (void)xmppS

iOS开发——完整项目实战OC篇&amp;百思不得姐第一天

百思不得姐第一天 做好准备,我们要开干了...... 先声明,我不过给出过多的代码实现,除非是一些重要的(开发中常用的),或者是比较难理解的. 主要介绍一些思路和简单功能的总结,还有一些遇到的错误及处理! 上午 一:修改项目名称(之前是Buble DisplayName) 二:删除(没有launchXIB的时候会显示界面错误),再iOS8以后屏幕的显示跟启动图片有关 需要删除对应,并且设置launchImages 或者我们可以自己在images.xcasesets中新建我们的launchImag

iOS开发——完整项目实战OC篇&amp;项目总结之九宫格布局双语实现

项目总结之九宫格布局双语实现 九宫格布局创建子控件 Objective-C版的实现 1 2 // 按钮 3 // 数据 4 NSArray *images = @[@"publish-video", @"publish-picture", @"publish-text", @"publish-audio", @"publish-review", @"publish-offline"];

iOS开发——高级UI之OC篇&amp;UIdatePicker&amp;UIPickerView简单使用

UIdatePicker&UIPickerView简单使用 /***********************************************************************************/ 一:UIdatePicker:(日期控件) 1.UIDatePicker什么时候用? 当用户选择日期的时候,一般弹出一个UIDatePicker给用户选择. 2.UIDatePickerios6和ios7/8的区别 下面看看使用封装的代码怎么去实现它: 因为这个比较简

iOS开发——完整项目实战OC篇&amp;百思不得姐第八天

百思不得姐第八天 上午 一:监听ScrollView停止两种方法 代码实现滚动的时候:必须要有动画 拖拽实现滚动的时候 二:ScrollView中,对应的X/Y宽高都相等的时候frmae就等一bounds 三:判断View是否在对应的View上面 1:判断父控件 2:看Window是否有值 3:是否创建加载 四:autormaticllyAdjustScrollViewInsets 五:内边距设置 1:tableView尺寸还是屏幕的尺寸(高度) 2:不被导航栏河tabBar挡住(用户能看齐所有