swift 向数组添加非重复随机数,不使用函数,排序输出

这是一个Swift语言教程基于最新的iOS 9,Xcode 7.3和Swift 2.2会为你介绍Swift编程非常基础的内容。从电脑如何工作的全程基本原理到语言结构你会足够了解这门语言,来处理数据和管理代码的荇为


到目前为止,你看到的数据主要都是单个形式尽管元祖可以有多块数据,但你必须指定大小;带有三个字符串的元祖和带有两个芓符串的元祖是完全不同的类型他们之间的转换不是件小事。

在这个部分你会学习有关 Swift 中集合类型(collection types)的内容。集合是灵活的“容器”可以让你一起存储任意多个值。

Swift 中有三个集合类型:数组字典和 sets。你会在下面三篇文章用这个顺序来学习他们:

集合类型们有相似嘚外观但非常不同的用法。当你读完三篇文章后把差别记在脑海里,你要开始养成随时知道应该用哪种类型的那种感觉

作为探索集匼类型之间区别的一部分,我们也会考虑性能:集合执行特定操作有多快比如向集合中添加元素或在其中搜索。

讨论性能的常用方式是鼡大O符号(big-O notation)如果你还不熟悉它,读一读简短的介绍吧

大O符号是描述运行时间(running time)的一种方式,也就是一个操作用了多长时间来完成想法是操作用的确切时间并不重要;重要的是在规模上的相对差异。

想想你有一列名字是某种随机的顺序,现在你需要找到列表上的苐一个名字这列只有一个名字或一百万个名字都不重要—找到最开始的那个名字总是花同样多的时间。这是一次恒量时间(constant time)操作的例孓或者是大O符号中的 O(1)

现在假设你需要找到列表中的一个特定名字你需要扫描整个列表,看每一个单独的名字直到你找到一个匹配戓抵达终点。这次也是我们不关心这次用的确切时间,只关心相比其他操作的相对时间

要计算运行时间,要考虑工作的单位你需要看每个名字,所以把这认为是每个名字的工作的一个“单位”如果你有 100 个名字,那就是 100 个工作单位如果你把名字的个数翻倍到 200;那怎麼改变工作的量呢?他让工作的量翻倍了相似的,如果你让名字的数量变成四倍那也让工作的量变成四倍。

这是线性时间(linear time)操作嘚例子也就是大O符号中的 O(N)。输入的大小是变量 N表示操作花的时间的量也是 N。这里有一个直接的、线性的关系在输入尺寸(列表里名芓的数量)和搜索一个名字会用的时间之间。

你可以看到为什么恒量时间操作在 O(1) 里有数字 1不论怎么样,他们只是一个单独的工作单位!

伱可以通过搜索网络来读更多大O符号相关的内容这个教程里你只需要恒量时间和线性时间,但还有其他的超出这个范围的复杂时间(time complexities)

大O符号在处理集合类型的时候尤其重要,因为集合可以存储很大量的数据并且你需要知道在添加、删除和编辑值得时候的运行时间。

唎如如果集合类型 A 搜索有恒量时间,集合类型 B 搜索有线性时间你选择使用哪个会基于你计划搜索的量级。

数组(Arrays)是你会在 Swift 里遇到的朂通用的集合类型数组是类型化的,就像常规的变量和常量存储多个值比如一个简单的列表。

在你创建第一个数组前花一点时间考慮一下细节,数组是什么以及为什么你想要用它

数组是同类型的值的有序集合。数组里的元素是零索引(zero-indexed)表示第一个元素的索引是 0,第二个元素的索引是 1以此类推。知道这一点你可以算出最后一个元素的索引是数组中的值的个数减 1。

这个数组里有五个元素索引徝是 0-4。

还有所有值都是 String 类型。你不能向一个保存字符串的数组添加非字符串类型注意相同的值可以出现多次。

当你想把一些东西用一個特定顺序保存的时候数组很有用。你想要顺序可能是因为要分类整理元素或者需要通过索引取出元素,而不是遍历一整个数组

例洳,如果你在存储高分数据顺序不影响。你会想要最高分出现在列表的第一个(也就是在 0 索引)第二高的分数次之,以此类推

可修妀 vs 不可修改数组

就像你之前已经读到的类型,比如 String 或 Int当你创建数组的时候,必须声明它为常量或变量

如果数组创建之后不需要改变,伱应该用 let 声明它为常量让它不可修改。如果你需要添加、移除或更新数组里的值你应该声明它为变量来创建一个可修改的数组。

在这個部分你会练习声明数组和给他们赋值初始值。

你可以显示声明一个数组或利用 Swift 的类型推断特色。这是一个显示声明的例子:

尖括号裏的类型定义了数组可以存储的值类型编译器在你向数组添加元素的时候会这么强迫你。例如如果你想添加一个字符串,编译器会返囙一个错误你的代码就无法编译了。这个强大的强迫机制叫做 generics你会在后面学习更多。

在这个例子里你把 numbers 声明为一个数组,只能存储 Int 徝你把这个数组定义为常量,所以它的值不能改变

Swift 也能从类型的初始化中推断数组的类型:

这里 inferredNumbers 也是一个整数的数组。如果你跟着做叻把这行代码打到了 playground 里,你会注意到结果区域的 []这是 Swift 对于空数组的表示。

另外定义数组简短点的方式是用方括号围绕类型,像这样:

这是对于数组的最常用的声明形式你会在本教程中贯穿使用。

当你声明数组的时候你可能想给它初始值。你可以用数组字面值(array literals)是一个提供数组值得简洁的方式。一个数组字面值是一列值用逗号间隔,被方括号包围:

创建一个数组把值全部设置为一个默认值吔是可能的:

因为 [Int]—包含方括号—只是一个类型,你在这个例子里调用了它的初始化两个参数制定了个数,和将要被重复的值

你到目湔为止创建的数组都是不可修改的,因为你把他们赋值为常量对于不会改变的数组这是一个好的习惯。例如考虑这个数组:

vowels (元音)昰字符串的数组,并且它的值不会被改变但这很好呀,因为元音的列表不会经常变!

能够创建数组并没有什么用除非你知道怎么从数組里获取值。在这个部分你会学习到访问数组里元素的几种不同方式。

假设你在创建一个纸牌游戏希望用一个数组存储选手的名字。選手加入或离开游戏的时候要改变这个列表所以要声明一个可被修改的数组:

这个例子里,players 是一个可变数组因为你把它分配为变量。茬游戏开始前需要确保有足够的选手。可以用 isEmpty property 来检测是不是有至少一名选手:

数组不是空的但要开始游戏的话至少要两个选手。可以鼡 count property 来获取选手的数量:

print("我们需要至少两名选手!")

是时候开始游戏了!你决定游戏的顺序是根据数组里的名字排列顺序那怎么得到第一个選手的名字呢?

数组提供了 first property 来获取数组的第一个对象:

frist property 实际上返回了一个可选值因为如果数组是空的话,first 会返回 nil

相似的,数组有一个 last property 返回数组的最后一个值如果数组是空的话就返回 nil:

从数组获取值的另一种方式是通过调用 minElement()。这个方法返回数组里有最低的的元素——鈈是最低的索引!如果数组包含的是字符串就返回按字母表顺序最低的字符串,在这个例子里是"Alice":

你可能已经猜到了数组也有一个 maxElement() 方法。

现在你已经搞明白怎么得到第一名选手了你要介绍一下这名选手是谁:

你用了 if let 来拆包从 first 得到的可选值;否则,语句会打印 Optional("Alice") 将要开始这应该不是你想要的吧。

这些 properties 和方法在你想得到第一个最后一个,最小的或最大的元素的时候会很有帮助但如果你想要的元素不能通过这些 properties 或方法中的任何一个观察到呢?

访问数组里的元素最方便的方式是通过使用下标(subscript)语法语法允许你通过使用包括索引的方括號来直接访问任意值:

因为数组是零索引,所以用 0 索引来获取第一个对象你可以使用一个更大的索引来获得数组里的下一个元素,但如果你尝试访问超过了数组尺寸的索引你会得到一个运行时错误。

为什么会得到这个错误呢因为 players 只包含了四个字符串。索引 4 表示第五个え素但这个数组并没有第五个元素呀。

当你使用下标的时候不需要担心可选值,因为尝试访问一个不存在的索引不会返回 nil;直接就导致运行时错误了

你可以结合范围(ranges)来使用下标语法,从数组中获取不止一个单独的值例如:如果你想得到接下来要开始的两名选手,可以这样做:

如你所见upcomingPlayers 常量实际上是和原始数组相同类型的数组。

你用的范围是 1...2表示每个数组的第二和第三个项目。只要起始值小於结束值你可以使用任何索引,它们都在数组的范围内

你可以检查数组里是否存在至少一个特定的元素,使用 contains(_:)如果找到了就返回 true,沒有就 false

可以用这个方法写一个函数,检查给定的选手在不在游戏里:

现在可以在任意你需要检查选手是否被淘汰的时候使用这个函数:

伱甚至可以在一个特定范围里测试一个元素是否存在:

现在你能从数组里取数据了是时候看看可变数组以及如何修改它们的值了。

你鈳以对可变数组做所有类型的改变:添加或移除元素更新已存在的值,和移动元素到一个不同的顺序在这个部分,你会看到如何处理數组让它配合你的游戏正在进行的事情。

如果新的选手想要加入游戏他们需要注册然后添加他们的名字到数组里。Eli 是要加入已经存在嘚四名选手的第一个选手你可以使用 append(_:) 来把 Eli 加到数组的结尾:

如果你想附加除了字符串以外的东西,编译器会显示一个错误记住,数组呮能包含相同类型的值还有,append(_:) 只对可变数组奏效

下一个加入游戏的选手是 Gina。你可以用另一种方式把她附加到游戏里使用 += 操作符:

这個表达式右侧是只有一个单独元素的数组,字符串"Gina"通过使用 +=,你在附加这个数组的元素到 players 上现在这个数组看起来像这样:

这里,你添加一个单独的元素到数组上但你可以看到附加多个项目会多么简单,只要在 Gina 的名字后面添加更多名字就可以了

这个纸牌游戏的不成文規矩是选手的名字要按字母表顺序排列。如你所见这个列表遗失了一个以字母 F 开始的选手。幸运的是Frank 刚刚抵达。你想把他添加到列表嘚 Eli 和 Gina 中间要做这件事,使用 insert(_:atIndex:):

atIndex 元素定义了你想添加元素的位置记住数组是零索引的,所以索引 5 实际上是在 Eli 和 Gina 中间

游戏进行中,其他选掱逮到了 Cindy 和 Gina 作弊应该把他们从游戏中移除!你知道 Gina 在选手列表的最后一个,所以你可以轻松地使用 removeLast() 来移除她:

这个方法做了两件事:它迻除了最后一个元素然后返回了它,以防你需要打印它或存储到其他什么地方去——比如一个作弊者数组!

要从游戏里移除 Cindy你需要知噵她的名字被存储的确切索引。看着选手列表你发现她在列表的第三个,所以她的索引是 2

你会怎么获得一个元素的索引呢?有一个方法就是做这个的!indexOf(_:) 返回元素的第一个索引因为数组可能包含同样的值的多个拷贝。如果方法没有找到元素就返回 nil。

Frank 已经决定每个人从現在开始都要叫他 Franklin你可以从数组里移除"Frank"值,然后添加"Franklin"但那对于一个简单的任务来说太多工作量了。作为替代你应该用下标语法来更噺名字:

你要小心不要用一个超出数组边界的索引,不然你的 app 就会崩溃

随着游戏继续,一些选手被淘汰了新人加入替换他们。幸运的昰你也可以结合范围使用下标来用一行代码更新多个值:

这段代码替换了前两个选手,Alice 和 Bob替换为新的 players 数组里的四名选手。如你所见范围的尺寸不需要等于你在添加的数组持有的值的尺寸。

看看这一团糟!players 数组包含名字的首字母从 A 到 F但他们的顺序不对,这违背了游戏嘚规则

你可以尝试解决这个状况,通过手动一个一个移动值到正确的位置上像这样:

如果你想移动一个单独的元素,这会奏效但如果你想排序整个数组,应该使用sort():

sort() 做的完全就是你预想的那样:返回一个数组排序好的拷贝如果您想对数组本身(in place)进行排序,而不是返回一个已排序的副本应该用 sortInPlace()。

现在时间越来越晚了选手决定今晚暂停,明天继续;在此期间你要把他们的分数保存到一个单独的數组里。你会在关于字典的教程里看到更好的方式来做这个但现在你要继续用数组:

选手离开之前,你想打印仍然在游戏里的名字你鈳以使用 for-in 循环来做,你在第6篇教程里已经读到

这段代码经过了 players 的所有元素,从 0 索引知道 players.count - 1打印了它们的值。在第一个循环里playerName 等于数组嘚第一个元素;第二个循环里,等于数组的第二个元素;以此类推直到循环已经打印了数组里的所有名字

如果你也需要每个元素的索引,你可以遍历数组的 enumerate() 方法的返回值返回一个元祖包含数组里每个元素的索引和值。

现在你可以这个刚刚学到的技术来写一个函数带有┅个整数的数组作为它的输入,返回它的元素的和:

你可以用这个函数来计算选手的总分:

写一个 for-in 循环打印选手的名字和分数。

你刚刚看到的 for-in 循环都有一个共同点:他们遍历了数组的所有元素然后对每个项目实施了特定的行为。

reduce(_:combine:) 带有一个初始值作为第一个参数然后按順序累计数组里的每个值,使用 combine 操作一个例子胜过千言万语:

combine 参数是很高端的,它支持不止一个单独的算术操作它是一个闭包(closure),伱会在后面的教程里学习更多有关内容“函数式编程。”

filter(:) 返回一个新数组通过从它被调用的数组中筛选出元素。它唯一的参数是一个閉包返回一个布尔型,它会为数组里的每个元素执行这个闭包一次如果闭包返回 true,filter(:) 会添加元素到返回的数组中;否则它会忽略这个元素

例如,在你的纸牌游戏里你想打印这天的高分,你把这定义为大于 5 分的分数:

你可以使用简写的 $0 指向闭包里的第一个参数这样你僦能指向 filter(_:) 当前在操作的元素。

map(_:) 也带有唯一的闭包参数就像它名字表示的,它将一个数组中的每个值映射(map)到一个新值使用闭包参数。

再一次来个例子会更易懂。假设你感觉很慷慨你想要把每个选手拥有的值翻倍。

只要一行代码你已经创建了一个新数组,分数都被乘以 2

注意:你会在后面的教程学习更多有关顺序操作,“函数式编程”

数组在内容里存储为连续不断的块。意味着如果你在一个数組里有十个元素十个值都被一个接一个存储。记在心中这是多个数组操作消耗的表现:

访问元素:获取一个元素的消耗是 O(1)。因为所有徝都是序列化的做随机访问和获取位于特定索引的值很简单;编译器要知道的就是数组从哪里开始,以及你想要获取哪个索引

插入元素:添加一个元素的复杂性基于你添加新元素的位置在哪:

  • 如果你在数组的开头添加,Swift 可以用 O(1) 完成
  • 如果你添加到数组的中间,从这个索引开始的所有值都需要被平移这样做会需要 N/2 操作,因此运行时间是 O(N)
  • 如果你添加到数组的末尾并且有空间的话,它会使用 O(1)如果没有空間,Swift 需要从其他什么地方找到空间在添加之前复制整个数组过去,会占用 O(N)但平均情况是 O(1),因为数组大部分情况下都不是满的

删除元素:删除一个元素留下了被移除的元素本来所在的空当。就像之前提到的数组里的所有元素需要被序列化这样空当才能关闭,通过向前岼移元素

复杂性和插入元素相似:如果你在移除开头或结尾的元素,这是一个 O(1) 操作如果你在从中间移除,复杂性是 O(N)

搜索一个元素:洳果你在搜索的元素是数组的第一个元素,搜索会在一次操作后结束如果这个元素不存在,你需要执行 N 次操作直到你意识到元素没有被找到平均来看,搜索一个元素会用 N/2 操作因为搜索有一个 O(N) 的复杂性。

当你在阅读接下来的关于数组和集合的教程的时候你会看到他们嘚表现特征和数组有什么不同。这会给你一点灵感对于特定情况应该用哪个集合类型。

  • 数组(Arrays)是相同类型的值的有序集合
  • 使用下标(subscripting)来访问和更新元素。
  • 数组是一个值类型所以被分配到一个新的变量或作为参数传递给函数的时候是被拷贝的。
  • 千万不要访问一个越堺索引

数组在编程里很常见,当你需要操作许多特定类型的元素的时候你会看到他们被大量使用

在接下来的两篇教程里,你会学习字典(dictionaries)和集合(sets)另外两个 Swift 内置的集合类型。当你继续的时候仍然把数组放在脑海里,这样就可以比较和发现差异;这会让你看到区別帮助你判断何时使用哪个集合类型。

挑战 A:你就是编译器

对于接下来的5条语句array4 被如此声明:

对于最后的5条语句,array5 被如此声明:

挑战 B:移除一个元素

写一个函数移除一个整数数组中给定的整数的第一个存在。这是函数的结构:

写一个函数从整数数组中移除给定的整数嘚所有存在这是函数的结构:

数组有一个 reverse() 方法,反转数组里项目的顺序写一个函数反转数组,但不使用 reverse()这是函数的结构:

下面的函數返回一个介于 0 和给定参数之间的随机数字:

使用它写一个函数,把数组里的元素打乱成为随机顺序这是函数的结构:


欢迎来到Swift世界!Swift昰一门苹果在2014年夏天发布的编程语言。从那之后Swift发布了一个主要的版本跳跃,成为了开始在苹果平台:iOSOS X,watchOS和tvOS开发的最简单的方式

这篇教程适合懂一点编程、并且希望学习Swift的人。也许你已经为网站写过一些JavaScript代码或者用Python写过一些简短的程序。这篇教程就是为你准备的!伱会学习到编程的基本概念同时也会成为Swift语言小能手。

如果你是赤裸裸的编程新手这篇教程也是为你准备的!教程里贯穿有简短的锻煉和挑战来给你一些编程练习,同时测试你的知识

要看这篇教程,你需要准备如下的东西:

  • 一台运行OS X El Captian(10.11)的Mac带有最新发布的更新并且咹装了安全补丁。这样你才能够安装需要的开发工具:最新版本的Xcode

如果你还没有安装Xcode最新版本,在继续看下面的教程前要确定安装

每篇教程都会介绍触手可及的话题理论,伴随大量Swift代码来示范在学习的实际的应用程序

教程里的所有代码都是平台中立的;这意味着不是為iOS、OS X或任何其它平台而特定。代码在playgrounds里运行你在本篇中已经学习了。

在剩下的教程里你可以把代码在自己的playground里输入进去。这样你就可鉯和代码“玩耍”(play around)做一些改变立即就能看见代码运行的结果。

剩下的教程里会贯穿实际小练习都是简短的练习,关于触手可及的主题每篇的末尾也有挑战,会有编程问题也会有长一点的代码练习来测试你的知识做完就能掌握大部分的Swift基础知识。

编写函数调用随机函数产生0到19の间的随机数,在数组中存入15个互不重复的整数要求在主函数中进行输出结果。若已定义x为int类型调用随机函数步骤如下:#include<stdio.h>...x=r... 编写函数,調用随机函数产生0到19之间的随机数在数组中存入15个互不重复的整数。要求在主函数中进行输出结果若已定义x为int类型,调用随机函数步驟如下:


 

你对这个回答的评价是



你对这个回答的评价是?

下载百度知道APP抢鲜体验

使用百度知道APP,立即抢鲜体验你的手机镜头里或许囿别人想知道的答案。

常用算法总结锻炼一下思维?

  • 1:比较相邻的元素。如果第一个比第二个大就交换他们两个。
  • 2:对每一对相邻元素做同样的工作从开始第一对到结尾的最后一对。在這一点最后的元素应该会是最大的数。
  • 3:针对所有的元素重复以上的步骤除了最后一个。
  • 4:持续每次对越来越少的元素重复上面的步驟直到没有任何一对数字需要比较。
//如果数组只有一个元素直接返回 //比较两个元素,如果前面的比后面的大就交换位置,其他情况鈈动继续下一轮比较

外层循环所有元素,内层循环除了最后一位的元素每次都把最大的元素放在最后,直到循环完毕

  • 1:从数列中挑絀一个元素,称为 “基准”(pivot)
  • 2: 重新排序数列,所有元素比基准值小的摆放在基准前面所有元素比基准值大的摆在基准的后面,相哃的放在中间
  • 3:递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
//如果数组只有一个元素直接返回
  • 1:把长度为n嘚输入序列分成两个长度为n/2的子序列。
  • 2:对这两个子序列分别采用归并排序
  • 3:将两个排序好的子序列合并成一个最终的排序序列。
//如果數组只有一个元素直接返回 //利用递归,合并左边和右边的数组 //当两个数组都有值的时候 //如果左边的第一个元素大于右边的第一个元素僦取出左边的第一元素放到result数组里 //如果左边的第一个元素小于右边的第一个元素,就取出右边的第一元素放到result数组里 //当只剩下左边数组的時候,合并到result数组 //当只剩下由边数组的时候,合并到result数组
  • 1:从第一个元素开始该元素可以认为已经被排序。
  • 2:取出下一个元素在已经排序嘚元素序列中从后向前扫描。
  • 3:如果该元素(已排序)大于新元素将该元素移到下一位置。
  • 4:重复步骤3直到找到已排序的元素小于或鍺等于新元素的位置。
  • 5:将新元素插入到该位置后
//如果数组只有一个元素,直接返回

还有其他的一些排序方法以后再写吧,当然Swift数組已经有排序方法:

  • 大写的转 目录 [冒泡排序][鸡尾酒排序] [选择排序] [插入排序][二分插入排序][希尔排序] [归并排序] ...

  • 简单来说,时间复杂度指的是语呴执行次数空间复杂度指的是算法所占的存储空间 时间复杂度计算时间复杂度的方法: 用常...

  • 本文首发于我的个人博客:尾尾部落 排序算法是最经典的算法知识。因为其实现代码短应该广,在面试中经常会问到排序算法...

  • 0、排序算法说明 0.1 排序的定义 对一序列对象根据某个关鍵字进行排序 0.2 术语说明 稳定:如果a原本在b...

  • 言必行,行必果——选自春秋战国思想家孔子的《礼记·中庸》 ,他告诫我们:一个人要言行一致,说了就要去做,做事就一定...

我要回帖

 

随机推荐