时间和空间复杂度

发布于:2022-12-04 ⋅ 阅读:(587) ⋅ 点赞:(0)

数组 array

读取:1步到位,跳到内存地址 O(1)

查找:线性查找,最多N次

插入:最低效(插入在开头),N+1步,最高效(末尾),1步

删除: 最低效(删除第一项),N步,最高效(末尾),1步

集合 set

不允许元素重复(基于数组)

读取:1步到位,跳到内存地址

查找:线性查找,最多N次

插入:插入前要查找,最低效(插入在开头),2N+1步,最高效(末尾),N+1步

删除: 最低效(删除第一项),N步,最高效(末尾),1步

有序数组 sorted array

线性查找:查找一般快于无序数组

二分查找: 100最多7步,线性100步

O算法复杂度

O(1) < O(logN) < O(N) < O(NlogN) < O(N^2)< O(N^3)<O(2 ^N) < O(n!) < O(n^n)

忽略常数,区分不同算法长期增长率(存在一临界点)

只保留最高阶N

  • 常数时间: O(1) 不局限于1步 读取

  • 线性时间:O(N) 线性查找

  • 对数时间:O(logN) 数据量翻倍,步数+1 二分法

  • 二次时间:O(N^2) 嵌套循环, 冒泡排序,选择排序,插入排序

  • 冒泡排序:比较+交换(相邻交换) O(N^2)

比较次数是 (N-1)+(N-2)+......+1,交换最坏和比较次数相同,总数为N(N-1)

  • 选择排序(最小值 时变量与左侧比较) O((N^2)+N)

移除(N-1)+比较(N-1)+....+1+平移(N-1)+....+1+插入(N-1)= N^2+2N-2

  • 插入排序在不同场景差异很大 最坏N^2 平均(N^2)/2 最好N

找两数组交集(比较+插入) 相互比较,相同值插入result

有break没交集N^2次比较 完全一样N次,不然无论什么情况都是N^2步

散列表 hash table O(1)

计算BAD=2 * 1 * 4=8,返回第8个格子

每次对同一串字符调用该散列函数,返回同一数字串

如果放入格子,冲突,分离链接(格子里放一个数组),若hash table含有array,线性查找,步数最多O(N)

hash table效率(避免冲突,节约空间)

  1. 要存多少数据

  2. 有多少可用格子

  3. 用什么样的散列函数

最理想的负载因子=0.7 (每增加7个元素,增加10个格子)

投票:投票保存(插入末尾)+点票(循环遍历)

array需要O(1)+O(N) hash table需要 O(1)投票时已经在计数(点票)

Stack栈 Queue队列

Stack:处理临时数据

(存储数据方式和Array相同,把元素排成一行, 类似盘子堆叠)

只能末尾(栈顶) 插入数据

只能在 读取/移除 末尾数据

Queue:打字机作业设置,后台任务等

FIFO,先进先出

只能 末尾插入数据

只能 读取/移除 开头数据

递归 recursion

几乎左右循环都可以转换成递归

递归可自然应用于需要重复自身的算法,增加代码可读性

适用于无法预估计算深度的问题

(遍历文件)

快速排序 O(NlogN) 最坏情况O(N^2)

最佳情况:每次分区后,轴都落在子数组中间 严重依赖于分区

分区操作:比较+交换 O(N)

一次分区至少N次比较,交换取决于排列情况,最少1,最多N/2次

随机排列为N/4,+N 是1.25N

一个无序数组,不需要排序,只要找出第10小,或第5大的值,如同找出第25%:

排序+查找—:即使用快速排序,也要O(NlogN)

 

 

快速选择

对数组分区(快排+二分查找结合)不需要把整个数组排序

平均O(N) N个元素,2N步

链表[Linked List]:

结点(node):组成链表不连续的格子,可分布在内存各个地方

每个node除了保留数据,还保留写一个node的内存地址,用来指示下一node内存地址的额外数据成为链Link

每个node需要两个格子,一个数据存储,一个list,最后一个node的list是null,使用LinkList只需要知道第一个node在内存的位置

读取 最坏情况最后一个引索 O( N)

查找 最坏情况最后一个格子 O(N)

插入 插入表头只要1步,但插入前要找到引索(即读取) O(N)

删除 效率和插入相似

亮点:高效的遍历单个列表并删除其中多个元素

每读取一个地址,用正则表达式验证其有效性,如果发现无效,则删除

数组每次删除需要 遍历N步,每次删除需要右移O(N) n个错,需要N+nN

链表每次删除只要1步, 总共N+n步

双向链表

数组作为queue底层:末尾插入O(1),开头删除O(N)

链表作为queue底层:末未插入O(N),开头删除O(1)

双向链表作为queue底层:插入和删除都为O(1),能直接访问前端末端节点

二叉树

子节点个数:0,1,2 两个子节点,大于父节点在右,小于的在左

查找:O(logN) 和数组二分查找一样

插入:O(logN) 查找+插入1步 有序数组是O(N)

只有随意打乱数据才平衡,插入的都是已排序数据,tree失去平衡,低效 完全失衡二叉树查找是O(N)

删除:O(logN) 要删除的节点没有子节点,直接删掉;有一个节点,将子节点填到被删除节点位置上;有两个节点,则替换为后继节点(右子节点中最小的)

实例:书目维护,经常变动,不适合有序数组,使用二叉树。书名搜索和更新,可用二叉树查找、插入和删除 访问数据中所有元素:遍历数组

中序遍历:递归 遍历效率O(N)

强大的基于节点的数据结构,即能维持顺序,又能快速查找、插入和删除

散列表(hash table)

广度优先搜索(使用queue) O(V+E) V个顶点,每个顶点出一次queue,E条边,每条边用两次,访问两端顶点,2E次访问邻接点

关系型数据, M个朋友,需要O(MlogN)次查询,一张user信息表,一张关系表(id代指用11户),id一般有序,二分查找是O(logN).

图数 据库,定位到user,M次即可(遍历连接的边)

Dijkatra算法,确定最短路线(总价最低航线)

本文含有隐藏内容,请 开通VIP 后查看