时间复杂度

双向链表为何时间复杂度为O(1)?

北慕城南 提交于 2019-11-28 15:52:11
双向链表相比于单向链表,所谓的O(1)是指删除、插入操作。 单向链表要删除某一节点时,必须要先通过遍历的方式找到前驱节点(通过待删除节点序号或按值查找)。若仅仅知道待删除节点,是不能知道前驱节点的,故单链表的增删操作复杂度为O(n)。 双链表(双向链表)知道要删除某一节点p时,获取其前驱节点q的方式为 q = p->prior,不必再进行遍历。故时间复杂度为O(1)。而若只知道待删除节点的序号,则依然要按序查找,时间复杂度仍为O(n)。 单、双链表的插入操作,若给定前驱节点,则时间复杂度均为O(1)。否则只能按序或按值查找前驱节点,时间复杂度为O(n)。至于查找,二者的时间复杂度均为O(n)。 对于最基本的CRUD操作,双链表优势在于删除给定节点。但其劣势在于浪费存储空间(若从工程角度考量,则其维护性和可读性都更低)。 双链表本身的结构优势在于,可以O(1)地找到前驱节点,若算法需要对待操作节点的前驱节点做处理,则双链表相比单链表有更加便捷的优势。 来源: https://www.cnblogs.com/RambleIvy/p/11414116.html

数据结构和算法 (二)

不想你离开。 提交于 2019-11-28 13:48:24
数据结构(swift实现)一 1. 常用数据结构 1. 1 数组 1. 2 字典 1. 3 链表 1. 4 堆栈 1.4.1 堆 1.4.2 栈 1.5 队列 1.5.1 优先队列 1.5.2 循环队列 1.6 树 1.6.1 二叉树 1.6.2 二叉搜索树 1.6.3 平衡二叉树 1.7 图 2. 常用算法 2.1 查找算法 2.1.1 二分查找 2.1.2 广度优先搜索算法 2.1.3 深度优先搜索算法 2.2 排序算法 2.2.1 排序算法简介 2.2.2 排序算法比较 2.2.2.1 稳定性比较 2.2.2.2 时间复杂度比较 2.2.2.3 辅助空间比较 2.2.2.4 其他比较 2.2.3 排序算法实现 2.2.3.1 插入排序 2.2.3.2 选择排序 2.2.3.3 冒泡排序 2.2.3.4 快速排序 2.2.3.5 堆排序 2.2.3.6 归并排序 2.2.3.7 希尔排序 2.2.3.8 二叉树排序 2.2.3.9 计数排序 2.2.3.10 桶排序 2.2.3.11 基数排序 2.2.3.12 1. 常用数据结构 1. 1 数组 1. 2 字典 1. 3 链表 1. 4 堆栈 1.4.1 堆 1.4.2 栈 1.5 队列 1.5.1 优先队列 1.5.2 循环队列 1.6 树 1.6.1 二叉树 1.6.2 二叉搜索树 1.6.3 平衡二叉树 1.7 图 2.

什么是算法

空扰寡人 提交于 2019-11-28 13:20:45
目录 算法的官方定义 例1:选择排序算法的伪码描述 什么是好的算法 空间复杂度S(n) 时间复杂度T(n) 0101-例2-空间复杂度 0101-例3-时间复杂度 方法1 方法2 算法复杂度的渐进表示 算法复杂度分析小窍门 算法的官方定义 算法(Algorithm) 一个有限指令集 接受一些输入(有些情况下不需要输入) 产生输出 一定在有限步骤之后终止 每一条指令必须 有充分明确的目标,不可以有歧义 计算机能处理的范围之内 描述应不依赖于任何一种计算机语言以及具体的实现手段 例1:选择排序算法的伪码描述 /* 伪代码描述 */ void SelectionSort (int List[], int N) { 将N个整数List[0]...List[N-1]进行非递减排序; 从List[i]到List[N-1]中找最小元,并将其位置赋给MinPosition; 将未排序部分的最小元换到有序部分的最后位置; } } /* c语言实现 */ void SelectionSort (int List[], int N) { /* 将N个整数List[0]...List[N-1]进行非递减排序 */ for (i=0; i<N; i++){ MinPosition = ScanForMin(List, i, N-1); /* 从List[i]到List[N-1]中找最小元

链表

妖精的绣舞 提交于 2019-11-28 13:02:27
开篇问题 问题:如何用链表来实现 LRU 缓存淘汰策略呢? 链表的作用 链表一个经典的应用场景就是 LRU 缓存淘汰算法; 缓存是一种提高数据读取性能的技术,在开发中有着非常广泛的应用,由于缓存的大小有限,当缓存被占满时,哪些数据应该被清理,哪些数据应该被保留?这就需要淘汰策略来决定,常见的淘汰策略有三种:先进先出策略FIFO(First In, First Out)、最少使用策略LFU(Least Frequently Used)、最近最少使用策略LRU(Least Recently Used)。 打个比方:假如说你买了很多书籍,但有一天发现书太多了,太占空间,你要做个大扫除。那么这个时候你会选择扔掉哪些书籍?对应一下,其实就是我们上边说的三种策略; 什么是链表? 为了理解起来更容易,我们拿数组来做对比; 相比数组,链表是一种稍微复杂一点的数据结构。从底层的存储结构上来看:数组需要一块儿连续的内存空间,堆内存的要求比较高,如果我们申请一个100MB大小的数组,当内存中没有连续的、足够大的空间的时候,即便内存的剩余总可用空间大于100MB,仍然会申请失败;而链表恰恰相反,它并不需要一块儿连续的内存空间,它通过“指针”将一组零散的内存块串联起来,所以如果我们申请100MB大小的链表,如果没有100MB连续的内存空间,且内存的剩余总可用空间大于100MB,根本不会有问题;

【数据结构与算法】时间复杂度和空间复杂度

柔情痞子 提交于 2019-11-28 12:18:37
一、阶数比较 时间复杂度判断理论:O(1) <= O(log2(n)) <= O(n) <= O(n*log2(n)) <= O(n^2) <=...<=O(n^k) <= O(2^n) 二、计算方法 用常数1代替运行时间中的所有加法常数 修改后的运行次数中只保留最高阶项 去除最高阶项的系数 三、常见的求时间复杂度例子 1、常数阶 int a=1; int b=a+2; 这种只执行常数规模的情况时间复杂度是O(1) 2、对数阶(O(log2n)) 1 int n=100; 2 int i=1; 3 while(i<=n){ 4 i=i*1; 5 } 在while循环里每次都将i乘以2,i距离n越来越近,如果循环x次之后i大于n此时这个循环退出也就是说2的x次方等于n那么x=log2n也就是说当循环log2n次以后,这个代码就结束了,此时这个短发的时间复杂度是O(log2n),o(LOG2n)的这个n是随着代码变化的,如果里面不是2倍递增则将发生相应变化eg:i=i*3 则时间复杂度为O(log3n) 3、线性阶 1 int j=0; 2 for(int i=1;i<=n;i++){ 3 j++; 4 } 这个代码,for循环里面的代码会执行n编,因此它消耗的时间是随着n的变化而变化O(n) 4、线性对数阶O(nlogN) 1 int j=0; 2 for(int i=1;i<=n

算法的时间复杂度和空间复杂度

坚强是说给别人听的谎言 提交于 2019-11-28 12:17:52
常用的算法的时间复杂度和空间复杂度 排序法 最差时间分析 平均时间复杂度 稳定度 空间复杂度 冒泡排序 O(n 2 ) O(n 2 ) 稳定 O(1) 快速排序 O(n 2 ) O(n*log 2 n) 不稳定 O(log 2 n)~O(n) 选择排序 O(n 2 ) O(n 2 ) 稳定 O(1) 二叉树排序 O(n 2 ) O(n*log 2 n) 不一顶 O(n) 插入排序 O(n 2 ) O(n 2 ) 稳定 O(1) 堆排序 O(n*log 2 n) O(n*log 2 n) 不稳定 O(1) 希尔排序 O O 不稳定 O(1) 1、时间复杂度 (1)时间频度 一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时间多,哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度。记为T(n)。 (2)时间复杂度 在刚才提到的时间频度中,n称为问题的规模,当n不断变化时,时间频度T(n)也会不断变化。但有时我们想知道它变化时呈现什么规律。为此,我们引入时间复杂度概念。 一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n)

算法复杂度:时间复杂度与空间复杂度

我与影子孤独终老i 提交于 2019-11-28 12:16:48
一、算法复杂度   算法复杂度分为:时间复杂度和空间复杂度。作用: 时间复杂度是指执行算法所需要的计算工作量;而空间复杂度是指执行这个算法所需要的内存空间。 二、时间复杂度:   1、定义:用T(n)表示算法中基本操作重复执行的次数,其中的n是问题的规模。若用f(n)表示T(n)的同量级函数,则时间复杂度记为O(f(n))。 注:同量级函数的定义:若有某个函数f(n)、使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数c,则称f(n)是T(n)的同数量级函数,记作T(n)=O(f(n))。   2、计算步骤:     (1)找出算法的基本操作     (2)根据相应的语句确定该 语句的执行次数T(n)     (3)找出 T(n) 的同数量级f(n),则为时间复杂度 O(f(n)   3、常见的T(n)的同数量级f(n)有以下:     1,log2n,n,n log2n ,n^2,n^3,2^n,n!   4、时间复杂度的计算技巧:    (1)看看有几重for循环,只有一重则时间复杂度为O(n),二重则为O(n^2),依此类推;    (2)如果有二分,例如快速幂、二分查找,则为O(log2n);    (3)如果一个for循环套一个二分,那么时间复杂度则为O(nlog2n)。   5、例子: for(i=1; i<=n; ++i) { for(j=1; j<

数据结构与算法

房东的猫 提交于 2019-11-28 12:05:15
/*--> */ /*--> */ 什么是数据结构? 指数据元素之间的关系。这些关系可以分为:   集合   线性结构   树形结构   网状结构。 逻辑结构分为: 线性结构 和 非线性结构。    集合:除了同属一个对象外不存在相互关系。如:汽车上的人除了同辆车彼此间无其他关系。      线性结构:元素间为严格的一对一关系,即一个元素有且只有一个前驱。如:成绩表中一个学生一个成绩    树形结构:元素之间为严格的一对多关系,即一个元素有且只有一个前驱,但可以多个后继。如家谱,行政组织       网状结构:元素之间存在多对多的关系,比较复杂。如:微信朋友圈    如何描述数据结构? 使用二元组来描述数据结构 Data_structure = (D,R) D 是元素的有限集 R 是D上所有元素的关系有限集 下面举一些例子 线性结构可以用二元组表示为: linear = (D,R) D = {A,B,C,D,E,F,G,H} R = {r} r = {<A,B>,<B,C>,<C,D>,<D,E>,<E,F>,<F,G>,<G,H>} 树形结构可以用二元组表示为: tree = (D,R) D = {A,B,C,D,E,F,G,H,I,J} R = {r} r = {<A,B>,<A,C>,<A,D>,<B,E>,<B,F>,<C,G>,<C,H>,<C,I>,<D,G>}

338.比特位计数

天涯浪子 提交于 2019-11-28 11:54:33
给定一个非负整数 num 。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。 示例 1: 输入: 2 输出: [0,1,1] 示例 2: 输入: 5 输出: [0,1,1,2,1,2] 进阶: 给出时间复杂度为 O(n*sizeof(integer)) 的解答非常容易。但你可以在线性时间 O(n) 内用一趟扫描做到吗? 要求算法的空间复杂度为 O(n) 。 你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的 __builtin_popcount )来执行此操作。 class Solution { public: vector<int> countBits(int num) { if (num == 0) return {0}; vector<int> res{0, 1}; int k = 2, i = 2; while (i <= num) { for (i = pow(2, k - 1); i < pow(2, k); ++i) { if (i > num) break; int t = (pow(2, k) - pow(2, k - 1)) / 2; if (i < pow(2, k - 1) + t) res.push_back(res[i - t]); else res.push

Leetcode 338. 比特位计数(Python3)

故事扮演 提交于 2019-11-28 11:51:50
338. 比特位计数 给定一个非负整数 num 。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。 示例 1: 输入: 2 输出: [0,1,1] 示例 2: 输入: 5 输出: [0,1,1,2,1,2] 进阶: 给出时间复杂度为 O(n*sizeof(integer)) 的解答非常容易。但你可以在线性时间 O(n) 内用一趟扫描做到吗? 要求算法的空间复杂度为 O(n) 。 你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的 __builtin_popcount )来执行此操作。 代码: class Solution: def countBits(self, num): """ :type num: int :rtype: List[int] """ res = [] for i in range(num): count = 0 while i: i = i & (i - 1) count += 1 res.append(count) return res 总结: 利用位运算 i = i & (i - 1) 来清除i的二进制中最后位的1 优化时间复杂度: class Solution: def countBits(self, num): """ :type num: int