时间复杂度

算法导论-堆排序

北慕城南 提交于 2019-12-31 02:36:19
堆排序的时间复杂度是 ,具有空间原址性,即任何时候都只需要常数个额外的元素空间存储临时数据。 一、堆 二叉堆是一个数组,可看成一个近似的完全二叉树,树上的每个结点对应数组中的一个元素。除了最底层外,该树是完全充满的,而且是从左到右填充。 二叉堆可以分为两种形式:最大堆和最小堆。在最大堆中除根节点外所有结点i都要满足: ,即某个结点的值至多与其父结点一样大。在最小堆中除根节点外所有 结点i都要满足: 。 说明: 堆排序中,我们使用最大堆,最小堆通常用于构造优先队列。 二、维护堆的性质 函数MAX-HEAPIFY的输入为一个数组A和下标i,假定根节点为LEFT(i)和RIGHT(i)的二叉树都是最大堆,通过让A[i]的值在最大堆中逐级下降,从而使得以下标i为根结点的子树为最大堆。 函数MAX-HEAPIFY的时间代价包括:调整A[i]、A[LEFT[i]]和A[RIGHT[i]]关系的时间代价 ,加上以一颗i的一个孩子为根结点的子树上运行MAX-HEAPIFY的时间代价(假设递归调用会发生)。 下面首先证明每个子树的大小至多为2n/3。 证明: 设堆的高度为h,最后一层结点个数为m,则整个堆的结点总数为: 。 根结点的左子树结点总数为: , 根结点的右子树结点总数为: ,其中 。 当最底层恰好半满的时候, ,则 , 。 解出: , 。 因此,每个子树的大小至多为2n/3

算法分析——时间复杂度

拥有回忆 提交于 2019-12-30 23:36:42
下面就举几个常见的时间复杂度 常数阶O(1) 通俗地来讲,就是没有循环等复杂结构 int i = 0 ; int j = 2 ; i ++ ; j ++ ; int m = i + j ; 对数阶O(log2n) 在while循环里面,每次都将 i 乘以 2,乘完之后,i 距离 n 就越来越近了。假设循环x次之后,i 就大于 2 了,此时这个循环就退出了,也就是说 2 的 x 次方等于 n,那么 x = log2n也就是说当循环 log2n 次以后,这个代码就结束了 int i = 1 ; while ( i < n ) { i = i * 2 ; } 线性阶O(n) int j = 0 ; for ( int i = 0 ; i < n ; i ++ ) { j ++ ; } 线性对数阶O(nlogN) 这可以看成是对数阶和常数阶的嵌套 for ( int m = 0 ; m < n ; m ++ ) { int i = 1 ; while ( i < n ) { i = i * 2 ; } } 来源: CSDN 作者: 田村卡夫卡~~ 链接: https://blog.csdn.net/weixin_43517302/article/details/103772931

[LeetCode]1. 两数之和

感情迁移 提交于 2019-12-30 22:49:30
题目描述: 给定一个整数数组 nums 和一个目标值 target ,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 示例: 给定 nums = [2, 7, 11, 15], target = 9 因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1] 思路: 我们应该首先想用暴力求解的话,怎么做? 我们会遍历数组 a ,然后看除了 a 数组中有没有 target-a 的数,这样就能保证该数组有两个数和等于 target ;但是时间复杂度为 \(O(n^2)\) ; 接下来,想一想如何更快一点呢? 对,我们可以借用哈希(python叫字典),我们遍历元素的时候,且记录元素的下标,当我们找 target-a 时候,只需要在字典找,就可以了,查找字典时间复杂度为 \(O(1)\) 所以, 时间复杂度: \(O(n)\) 空间复杂度: \(O(n)\) 代码: Python版 class Solution: def twoSum(self, nums, target): """ :type nums: List[int] :type target: int :rtype: List[int] """ n = len(nums) lookup = {}

从零开始学算法(一)

生来就可爱ヽ(ⅴ<●) 提交于 2019-12-30 22:39:28
理解时间复杂度: 一个有序数组A,另一个无序数组B,请打印B中的所有不在A中的数,A数 组长度为N,B数组长度为M。 算法1:对于数组B中的每一个数,都在A中通过遍历的方式找一下; 算法2:对于数组B中的每一个数,都在A中通过二分的方式找一下; 算法3:先把数组B排序,然后用类似外排的方式打印所有不在A中出现的数; 时间复杂度分别为: O(M*N), O(M*log(N)),O(M*logM)+O(M+N) (算法3:排序O(M*logM),再加上两个有序数组各遍历一遍O(M+N)) 递归的算法的时间复杂度: 递归算法满足 master公式 :T(N) = aT(N/b)+T(N^d) 其中N是问题的样本量,a是拆分成子问题的数量,N/b是子问题的样本量,N^d是拆分后常规操作的复杂度。 log(b,a) > d ——> 时间复杂度: O(N^log(b,a)) log(b,a) = d ——> 时间复杂度: O(N^d*logN) log(b,a) < d ——> 时间复杂度: O(N^d)) 以归并排序为例,T(N)=2T(N/2)+T(N),a=2,b=2,d=1;log(1,1)=1,时间复杂度O(N*logN) 排序算法: 1.冒泡排序: 时间复杂度O(N^2),空间复杂度O(1) 相邻两个数比较,大的放在后面。每次遍历把最大的数找出放在最后。 for(int end

关于树,各种平衡树查找树的资料合集~~

我怕爱的太早我们不能终老 提交于 2019-12-30 05:40:37
我们知道,对于一般的二叉搜索树(Binary Search Tree) ,其期望高度(即为一棵平衡树时)为log2n,其各操作的时间复杂度(O(log2n))同时也由此而决定。 但是,在某些极端的情况下(如在插入的序列是有序的时) ,二叉搜索树将退化成近似链或链,此时,其操作的时间复杂度将退化成线性的,即O(n) 。我们可以通过 随机化 建立二叉搜索树来尽量的避免这种情况,但是在进行了多次的操作之后,由于在删除时,我们总是选择将待删除节点的后继代替它本身,这样就会造成总是右边的节点数目减少,以至于树向左偏沉。这同时也会造成树的平衡性受到破坏,提高它的操作的 时间复杂度 。 平衡二叉搜索树 (Balanced Binary Tree)具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。常用算法有红黑树、AVL、Treap、伸展树等。在平衡二叉搜索树中,我们可以看到,其高度一般都良好地维持在O(log2n),大大降低了操作的时间复杂度。 BST Binary Search Tree~ 二叉搜索树 ( Binary Search Tree ),或者是一棵空树,或者是具有下列性质的 二叉树 : 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左

算法分析与优化

无人久伴 提交于 2019-12-29 21:32:29
算法分析 同一问题可用不同算法解决,而一个算法的质量优劣将影响到算法乃至程序的效率.算法分析的目的在于选择合适算法和改进算法.一个算法的评价主要从时间复杂度和空间复杂度来考虑. 1、时间复杂度 (1)时间频度 一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度,记为T(n)。 (2)时间复杂度 在刚才提到的时间频度中,n称为问题的规模,当n不断变化时,时间频度T(n)也会不断变化。但有时想知道它变化时呈现什么规律.为此,引入时间复杂度概念. 一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。 在各种不同算法中,若算法中语句执行次数为一个常数,则时间复杂度为O(1),另外,在时间频度不相同时,时间复杂度有可能相同,如T(n)=n2+3n+4与T(n)=4n2+2n

数据结构与算法概论

﹥>﹥吖頭↗ 提交于 2019-12-29 21:26:25
计算机已经成为我们有力的工具。利用计算机处理数据,我们需要考虑到数据的存储表示,以及对数据的处理。 而数据的表示则要用到我们所说的数据结构,对数据的处理需要用到算法。 1 . 数据结构 对数据的存储表示,我们不仅仅需要保存每个独立数据的值,还需要保存数据中数据元素间的关系。 数据 首先我们来看一下我们的主要对象: 数据 数据指的是所有能够输入到计算机并能够被计算机程序识别和处理的 集合 (1)数据的分类:数值型(整数、实数等)+ 非数值型(图像、语音、文本等) (2)数据的组成:数据元素(由数据项构成)一般数据元素是我们考虑数据时的最小单位 数据元素间的关系 数据中数据元素间的逻辑关系我们可以用数据的逻辑结构来表示。这个是针对数据的 逻辑结构 (1)集合:数据元素间都是平等的,比如接幼儿园小孩子回家在门口等候的父母亲 (2)线性结构:数据间一对一的关系,比如列队 (3)树结构:一对多的层次关系。公司部门里面的领导员工 (4)图结构:数据元素间多对多的任意关系。辩论自由辩时的状态 存储结构(物理结构) 数据的存储表示,我们需要考虑到在计算机中用什么结构去存,这个是针对计算机的 (1)顺序存储:用一组连续的单元存储。此时数据元素间的逻辑关系由她们在内存中的位置呈现。比如按次序列队 (2)链接存储:数据在内存中是可以不连续的。排队过程中总是存在着有人插队,这个可以用飞机场接机来表示

redis数据结构-字符串

瘦欲@ 提交于 2019-12-28 17:25:21
数据结构 1.Redis简单动态字符串 Redis Simple Dynamic String 底层结构 Redis 对buf[]中的数据是二进制数据保存的。 计算长度时间复杂度 C语言字符串,计算长度,遍历字符串, 时间复杂度O(n) Redis字符串,直接给出了长度,时间复杂度O(1) 空间分配策略 Redis如果每次修改字符串长度,都进行“重新分配内存空间”操作的话, 那么,连续更改操作,会导致性能受到影响。 故采用了两种策略:空间预分配和惰性空间释放 空间预分配策略 惰性空间释放策略 释放多余的内存空间,不会触发“重新分配内存空间”操作,只计数到free。 来源: CSDN 作者: 像我这么帅的一般都是主角哦 链接: https://blog.csdn.net/qq_32828777/article/details/103743974

数据结构:链表讲解

拈花ヽ惹草 提交于 2019-12-28 15:12:11
数据结构:链表讲解 一、缓存淘汰策略: 缓存的大小有限,当缓存被用满时,哪些数据应该被清理出去?哪些数据应该保留?这就需要缓存淘汰策略来决定。 简单理解: 就是当缓存被用满时清理数据的优先顺序 。 先进先出策略 FIFO(First In, First Out) 最少使用策略 LFU(Least Frequently Used) 最近最少使用策略 LRU(Least Recently Used) 以上策略举个栗子: 假如,你买了很多书,但有一天发现,书太多了,太占书房空间了,打算丢掉一些书籍; 丢到刚买的书:先进先出策略 丢到买完一直都没有读过的书:最少使用策略 丢到最近刚买的书,但是一直都没怎么读过:最近最少使用策略 二、数组与链表的区别: 1.底层存储的结构区别: 我们可以从 底层的存储结构 来看。数组需要一块 连续的内存空间 来存储,对内存的要求比较高。 如果我们申请一个 100MB 大小的数组,当内存中没有连续的、足够大的存储空间时,即便内存的剩余总可用空间大于 100MB,仍然会申请失败。 链表恰恰相反,它并 不需要一块连续的内存空间 ,它通过 指针 将一组零散的内存块串联起来使用,其中,我们把内存块称为链表的 结点 。 为了将所有的结点串起来,每个链表的结点除了存储数据之外,还需要记录链上的 下一个结点的地址 。结点地址的指针叫作 后继指针 next 。

数据结构:Skip List--跳表

孤人 提交于 2019-12-28 06:48:47
本文为转载,原文作者:fanrui 原文链接: 简书 https://www.jianshu.com/p/9d8296562806 跳表是一种神奇的数据结构,因为几乎所有版本的大学本科教材上都没有跳表这种数据结构,而且神书《算法导论》、《算法第四版》这两本书中也没有介绍跳表。但是跳表插入、删除、查找元素的时间复杂度跟红黑树都是一样量级的,时间复杂度都是O(logn),而且跳表有一个特性是红黑树无法匹敌的(具体什么特性后面会提到)。所以在工业中,跳表也会经常被用到。废话不多说了,开始今天的跳表学习。 通过本文,你能 get 到以下知识: 什么是跳表? 跳表的查找、插入、删除元素的流程 跳表查找、插入、删除元素的时间复杂度 跳表插入元素时,如何动态维护索引? 为什么Redis选择使用跳表而不是红黑树来实现有序集合? 工业上其他使用跳表的场景 友情提示:下文在跳表插入数据时,会讲述如何动态维护索引,实现比较简单,逻辑比较绕,不要放弃,加油!!!如果一遍看不懂没关系,可以选择暂时性的跳过,毕竟这块偏向于源码。但是读者必须知道跳表的查找、插入、删除的时间复杂度都是 O(logn),而且可以按照范围区间查找元素,当工作中遇到某些场景时,需要想到可以使用跳表解决问题即可。毕竟平时的工作都是直接使用封装好的跳表,例如:java.util.concurrent 下的