关于复杂度:常见排序算法及复杂度

1. 常见算法复杂度大O加上()的模式,外面其实包裹的是一个函数f(),O(f()),指明某个算法的 “耗时/耗空间”与“数据增长量”之间的关系。其中的 n代表输出数据的量。 1.1. O(1)1. 解释最低复杂度,常量值。也就是 “耗时/耗空间” 与 “数据增长量” 无关,无论输出数据增大多少倍,“耗时/耗空间” 都不变。 2. 举例哈希算法就是典型的 O(1)工夫复杂度算法,例如 HashMap、布隆过滤器等哈希算法的利用,无论数据规模多大,在计算出 hash key 的值之后,都能够一次性找到指标(不思考哈希抵触的话)。 1.2. O(n)1. 解释数据量增大几倍,耗时也增大几倍。 2. 举例例如:最常见的遍历算法,遍历一次所有值,找出其中的最大值。 1.3. O(n^2)1. 解释对n个数排序,须要扫描 n^2次。 2. 举例例如:冒泡排序法、抉择排序法等。因为该算法都是2层循环,第一层循环遍历 n-1 趟,第二层循环遍历 n-i 趟(i递增)。 1.4. O(logn)1. 解释当数据增大n倍时,耗时增大logn倍。 这里 log 是以2为底。比方:log256=8 2. 举例二分查找法就是 O(logn) 的算法,每找一次就排除个别的可能性,256条数据中只需查找8次就能够。 1.5. O(nlogn)1. 解释当数据增大n倍时,耗时增大 n乘以logn 倍。例如当数据增大256倍,耗时增大 256*8 倍。 这个复杂度高于线性O(n),低于平方O(n^2)。 2. 举例归并排序法、疾速排序法的工夫复杂度就是 O(nlogn)。 2. 排序算法复杂度网上看到这张图: 2.1. 冒泡排序为啥 O(n^2)冒泡排序法遍历的次数: 总层数:n−1每层遍历次数:n−i(i在 1 ~ n 递增)可基于 ∑i 求和,计算出总次数:n(n−1)/2=n^2/2 - n/2既然是 n^2/2 - n/2,为什么说工夫复杂度是 O(n^2) 呢?因为咱们常说的复杂度不是精确的值,而是当数据量收缩时,随之工夫收缩的模型。当 n 趋向于无限大时,n^2/2 - n/2 也就趋向于 n^2。 ...

April 26, 2023 · 2 min · jiezi

关于复杂度:复杂度分析如何分析统计算法的执行效率和资源消耗

作者:京东物流 崔旭 咱们都晓得,数据结构和算法自身解决的是“快”和“省”的问题,即如何让代码运行得更快,如何让代码更省存储空间。所以,执行效率是算法一个十分重要的考量指标。那如何来掂量你编写的算法代码的执行效率呢?这里就要用到咱们明天要讲的内容:工夫、空间复杂度剖析。 1 为什么须要复杂度剖析?你可能会有些纳闷,我把代码跑一遍,通过统计、监控,就能失去算法执行的工夫和占用的内存大小。为什么还要做工夫、空间复杂度剖析呢?这种分析方法能比实实在在跑一遍失去的数据更精确吗? 首先能够必定地说,这种评估算法执行效率的办法是正确的。很多数据结构和算法书籍还给这种办法起了一个名字,叫预先统计法。然而,这种统计办法有十分大的局限性。 1.1 测试后果十分依赖测试环境测试环境中硬件的不同会对测试后果有很大的影响。比方,咱们拿同样一段代码,别离用 Intel Core i9 处理器和 Intel Core i3 处理器来运行,i9 处理器要比 i3 处理器执行的速度快很多。还有,比方本来在这台机器上 a 代码执行的速度比 b 代码要快,等咱们换到另一台机器上时,可能会有截然相同的后果。 1.2 测试后果受数据规模的影响很大对同一个排序算法,待排序数据的有序度不一样,排序的执行工夫就会有很大的差异。极其状况下,如果数据曾经是有序的,那排序算法不须要做任何操作,执行工夫就会十分短。除此之外,如果测试数据规模太小,测试后果可能无奈实在地反馈算法的性能。比方,对于小规模的数据排序,插入排序可能反倒会比疾速排序要快! 所以,咱们须要一个不必具体的测试数据来测试,就能够粗略地预计算法的执行效率的办法,这就是咱们接下来要说的大O复杂度表示法。 2 大O复杂度表示法算法的执行效率,粗略地讲,就是算法代码执行的工夫。然而,如何在不运行代码的状况下,用“肉眼”失去一段代码的执行工夫呢? 这里有段非常简单的代码,求 1,2,3…n 的累加和。当初,一块来估算一下这段代码的执行工夫吧。 从 CPU 的角度来看,这段代码的每一行都执行着相似的操作:读数据-运算-写数据。只管每行代码对应的 CPU 执行的个数、执行的工夫都不一样,然而,咱们这里只是粗略预计,所以能够假如每行代码执行的工夫都一样,为 unit_time。在这个假如的根底之上,这段代码的总执行工夫是多少呢? 第 2、3 行代码别离须要 1 个 unit\_time 的执行工夫,第 4、5 行都运行了 n 遍,所以须要 2n\_unit\_time 的执行工夫,所以这段代码总的执行工夫就是 (2n+2)\_unit_time。能够看进去,所有代码的执行工夫 T(n) 与每行代码的执行次数成正比。 依照这个剖析思路,咱们再来看这段代码。 咱们仍旧假如每个语句的执行工夫是 unit_time。那这段代码的总执行工夫 T(n) 是多少呢? 第 2、3、4 行代码,每行都须要 1 个 unit\_time 的执行工夫,第 5、6 行代码循环执行了 n 遍,须要 2n\_unit\_time 的执行工夫,第 7、8 行代码循环执行了 n²遍,所以须要 2n²\_unit\_time 的执行工夫。所以,整段代码总的执行工夫 T(n) = (2n²+2n+3)*unit\_time。 ...

March 21, 2023 · 2 min · jiezi

理解算法的时间复杂度

翻译:疯狂的技术宅原文:https://www.freecodecamp.org/... 未经允许严禁转载 在计算机科学中,算法分析是非常关键的部分。找到解决问题的最有效算法非常重要。可能会有许多算法能够解决问题,但这里的挑战是选择最有效的算法。现在关键是假如我们有一套不同的算法,应该如何识别最有效的算法呢?在这里算法的空间和时间复杂度的概念出现了。空间和时间复杂度是算法的测量尺度。我们根据它们的空间(内存量)和时间复杂度(操作次数)来对算法进行比较。 算法在执行时使用的计算机内存总量是该算法的空间复杂度(为了使本文更简短一些我们不会讨论空间复杂度)。因此,时间复杂度是算法为完成其任务而执行的操作次数(考虑到每个操作花费相同的时间)。在时间复杂度方面,以较少的操作次数执行任务的算法被认为是有效的算法。但是空间和时间复杂性也受操作系统、硬件等因素的影响,不过现在不考虑它们。 我们将通过解决一个特定问题的例子来帮你理解时间复杂度, 这个问题是搜索。我们必须在数组中查找一个元素(在这个问题中,假设数组已经按升序排序)。为了解决这个问题,我们有两种算法: 线性搜索二分搜索假设数组包含十个元素,要求我们在数组中找到数字 10。 const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];const search_digit = 10;线性搜索算法会将数组的每个元素与 search_digit 进行比较,当它在数组中找到 search_digit 时,会返回 true。现在让我们计算它执行的操作次数。这里的答案是10(因为它比较了数组的每个元素)。因此线性搜索使用十个操作来查找给定元素(这是使用线性搜索算法时对此数组的最大操作数,这也被称为最坏情况。通常线性搜索在最坏的情况下会进行 n 次操作(其中 n 是数组的大小)。 让我们来看看同样情况下的二分搜索算法。 通过此图可以轻松理解二分搜索: 如果要在这个问题上应用此逻辑,那么首先我们将 search_digit 与数组的中间元素进行比较,即 5。现在,因为 5 小于 10,那么我们将开始在大于 5 的数组元素中寻找 search_digit ,不断执行相同的操作直到我们找到所需的元素 10 为止。 现在试着计算使用二分搜索找到所需的元素进行的操作次数:大约需要四次操作。这是二分搜索的最坏情况。这表明,执行的操作数和数组的总大小之间存在对数关系。 操作次数 = log(10) = 4(约) 我们可以将此结果推广到二分搜索:对于大小为 n 的数组,二分搜索执行的操作数为:log(n) Big O表示法在上面的陈述中,我们看到对于大小为 n 的数组,线性搜索将执行 n 次操作来完成查找,而二分搜索执行 log(n) 次操作(两者都是最糟糕的情况)。我们可以将其表示为图形(x轴:元素数量,y轴:操作次数)。 ...

June 13, 2019 · 1 min · jiezi

低复杂度多选框设计与实现

引言还是性能的问题,数据量大的时候,特别得卡。上算法课,也没找到一种性能很优的算法,最终使用Map重新设计了一下,并使用原生的checkbox,性能有极大地提升,用户感觉不出任何卡顿。优化实践原组件性能分析<nz-checkbox-wrapper style=“width: 100%;” (nzOnChange)=“change($event)"> <div nz-row> <div nz-col nzSpan=“4” ngFor=“let host of hostListValues”> <label nz-checkbox [nzValue]=“host.value” [(ngModel)]=“host.checked”>{{host.label}}</label> </div> </div></nz-checkbox-wrapper>this.hostService.getAllHosts().subscribe((hosts) => { this.hostListValues = []; // 获取主机数量 const length = hosts.length; // 使用主机信息构造多选框绑定数据 for (let index = 0; index < length; index++) { this.hostListValues.push({ label: hosts[index].name, value: hosts[index], checked: HostCheckboxComponent.existIn(hosts[index], this._hostList) }); }});根据计算机列表构造符合规范的数组(每次循环都需要判断是否选中)。html中ngFor。每点击一次,就输出一次nzOnChange事件,因为该事件的参数是当前选中的计算机列表,所以应该也进行循环了。使用原生checkbox使用原生的checkbox,我们就不需要再去循环构建符合ng zorro要求格式的数据了,直接就把计算机列表传给页面。<nz-row> <nz-col ngFor=“let host of hosts” [nzSpan]=“4”> <label> <input type=“checkbox”> {{ host.name }} </label> </nz-col></nz-row>默认选中的设计原来的默认选中复杂度太高。假设2000台计算机,100个默认选中的,最终执行次数就是2000 * 100。for 计算机列表 for 默认选中计算机列表怎样降低复杂度呢?最终想到了使用Map,毕竟Map查询的复杂度是要比自己for循环低的多的。设计一个checkedMap,该Map中存储了所有被选中的主机的id。/ * 计算机选中的Map存储 /public checkedMap: Map<number, boolean>;<nz-row> <nz-col ngFor=“let host of hosts” [nzSpan]=“4”> <label> <input type=“checkbox” (change)=“syncHostCheckedMap(host.id)” [checked]=“checkedMap.get(host.id)"> {{ host.name }} </label> </nz-col></nz-row>再分析一下,2000台计算机,100台默认选中的,因为Native Map的高性能,应该能提升部分性能。组件输出@Output()hostCheck = new EventEmitter<Array<Host>>();因为多选框写成了组件,组件其实并不知道用我的页面什么时候要我的数据,所以使用事件输出的,当用户选中的内容有变化时,我就for循环一次所有的计算机,然后把选中的输出出去。现在则是写一个public方法,供外部调用。/ * 获取所有选中的计算机列表 * 供外部调用 /public getAllCheckedHostList(): Array<Host> { // 初始化计算机列表 const hostList: Array<Host> = new Array<Host>(); // 遍历选中的Map this.checkedMap.forEach((value, key) => { // 遍历计算机列表 this.hosts.forEach((host) => { // 如果符号位,添加到列表中 if (host.id === key) { hostList.push(host); } }); }); // 返回 return hostList;}怎么调的呢?以下是示例代码:<app-host-checkbox #hostCheckbox [primaryHostList]=“primaryHostList”></app-host-checkbox>/* * 获取HostCheckboxComponent组件 /@ViewChild(‘hostCheckbox’)private hostCheckbox: HostCheckboxComponent;/* * 计算机组更新方法 * @param hostGroup 计算机组 */public update(hostGroup: HostGroup): void { // 从组件中拿去选中的计算机的列表 hostGroup.hostList = this.hostCheckbox.getAllCheckedHostList(); // 请求后台更新计算机组}ViewChild - Angular.ioAngular官网说ViewChild用于视图查询,我理解就是把用到的组件注进来,和组件的交互不仅限于输入输出,还可以调用组件对外暴露的方法。总结当编码已经不成问题的时候,我们真正可以当语言为工具,通过我们的思考,构造一个又一个实用的设计。 ...

March 15, 2019 · 1 min · jiezi