一. 前端基本的数据结构类型
0 js数据类型
基本类型(栈 stack) :
Number、String 、Boolean、Null 和 Undefined, Symbol(es6 新增);
基本数据类型是按值访问 由高向低分配, 栈内存最大是 8MB,(超出报栈溢出), String: 是特殊的栈内存 (向高分配大小不定), 程序员分配
引用类型(堆 heap) :
Object 、Array 、Function 、Data;引用类型数据在栈内存中保存的实际上是对象在堆内存中的引用地址(指针), 向高分配, 系统自动分配
1 堆栈空间分配区别:
栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈;
堆(操作系统): 一般由程序员分配释放,若程序员不释放,程序结束时可能由 OS 回收,分配方式倒是类似于链表。
2 堆栈缓存方式区别:
栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放;
堆是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。
3 堆 、栈数据结构区别:
数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成; 数据结构的基本操作的设置的最重要的准则是, 实现应用程序与存储结构的独立
(数据结构 = 数据的存储 + 算法)
4 数据结构分类
逻辑结构: 反映数据之间的逻辑关系;
存储结构: 数据结构在计算机中的表示;
5 逻辑结构:
集合: 结构中的数据元素除了同属于一种类型外,别无其它关系。(无逻辑关系)
线性结构: 数据元素之间一对一的关系(线性表)
树形结构: 数据元素之间一对多的关系(非线性)
图状结构或网状结构: 结构中的数据元素之间存在多对多的关系(非线性)
6 存储结构:
顺序存储数据结构
链式存储数据结构
索引存储数据结构
散列存储数据结构
二. 前端常用到的具体的数据结构
栈
栈是一种特殊的线性表。它的特点是,只能在表的一端操作。可以操作的端称为栈顶,不可以操作的另一端称为栈底。栈的特性:先进后出。
队列
队列也是一种特殊的线性表,它的特点是,只能在表的一端进行删除操作,而在表的另一点进行插入操作。可以进行删除操作的端称为队首,而可以进行插入操作的端称为队尾。删除一个元素称为出队,插入一个元素称为入队。和栈一样,队列也是一种操作受限制的线性表。队列的特性:先进先出
链表
链表由若干个结点链结成一个链表,称之为链式存储结构。
链表和数组的区别
链表和数组都可以存储多个数据,数组需要一块连续的内存空间来存储数据,对内存的要求比较高。而链表却相反,它并不需要一块连续的内存空间。链表是通过指针将一组零散的内存块串联在一起。
分类: 单向链表 、双向链表、单向循环链表 、双向循环链表
应用:环形链表、回文链表、相交链表(想想怎么判断)
树
树是一种数据结构,它是由 n(n >= 1)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。
分类
无序树:树中任意节点的子结点之间没有顺序关系,这种树称为无序树, 也称为自由树。
有序树:树中任意节点的子结点之间有顺序关系,这种树称为有序树。
二叉树:每个节点最多含有两个子树的树称为二叉树。
满二叉树:叶节点除外的所有节点均含有两个子树的树被称为满二叉树。
完全二叉树:除最后一层外,所有层都是满节点,且最后一层缺右边连续节点的二叉树称为完全二叉树(堆就是一个完全二叉树)。
哈夫曼树(最优二叉树):带权路径最短的二叉树称为哈夫曼树或最优二叉树。
遍历
深度优先遍历
先序遍历 又称先根遍,根 - 左 - 右
中序遍历 又称中根遍历,左 - 根 - 右,仅二叉树有中序遍历
后序遍历 又称后根遍历,左 - 右 - 根
广度优先遍历
层序遍历 一层一层的遍历
图
图结构是一种非线性的数据结构,图在实际生活中有很多例子,比如交通运输网,地铁网络,等等都可以抽象成图结构。图结构比树结构复杂的非线性结构。
图是由若干个节点和边组成
分类
无向图 如果一个图结构中,所有的边都没有方向性,那么这种图便称为无向图。
有向图 一个图结构中,边是有方向性的,那么这种图就称为有向图。
加权图 如果给边加上一个值表示权重,这种图就是加权图。
连通图 如果图中任意两个节点都能找到路径可以将它们进行连接,则称该图为连通图。
表示
图有两种表示方法:邻接矩阵、邻接链表。不同的场景及算法可能需要不同的图表示方式,一般情况下当结点数量非常庞大时,会造成矩阵非常稀疏,空间开销会较大,此时使用邻接链表的表示方式会占用较少的空间。而如果是稠密矩阵或者需要快速判断任意两个结点是否有边相连等情况,可能邻接矩阵更合适。
遍历
深度优先遍历
广度优先遍历
综合概括:栈,队列,树,链表(环形,交叉),字典,集合(交,并,补,差),图(无向图,有向图,加权图 ,连通图。邻接矩阵、邻接链表 ) 以及 权重的引入
三. 补充了解几个相关的概念
- 什么是复杂度分析?
1.数据结构和算法解决是 “如何让计算机更快时间、更省空间的解决问题”。
2.因此需从执行时间和占用空间两个维度来评估数据结构和算法的性能。
3.分别用时间复杂度和空间复杂度两个概念来描述性能问题,二者统称为复杂度。
4.复杂度描述的是算法执行时间(或占用空间)与数据规模的增长关系。
- 为什么要进行复杂度分析 ?
1.和性能测试相比,复杂度分析有不依赖执行环境、成本低、效率高、易操作、指导性强的特点。
2.掌握复杂度分析,将能编写出性能更优的代码,有利于降低系统开发和维护成本。
- 那如何进行复杂度分析呢?
1 大 O 表示法
算法的执行时间与每行代码的执行次数成正比,用 T(n) = O(f(n)) 表示,其中 T(n) 表示算法执行总时间,f(n) 表示每行代码执行总次数,而 n 往往表示数据的规模。这就是大 O 时间复杂度表示法。
2 时间复杂度
定义
算法的时间复杂度,也就是算法的时间量度。
大 O 时间复杂度表示法 实际上并不具体表示代码真正的执行时间,而是表示 代码执行时间随数据规模增长的变化趋势,所以也叫 渐进时间复杂度,简称 时间复杂度(asymptotic time complexity)。
特点
以时间复杂度为例,由于 时间复杂度 描述的是算法执行时间与数据规模的 增长变化趋势,所以 常量、低阶、系数 实际上对这种增长趋势不产生决定性影响,所以在做时间复杂度分析时 忽略 这些项。
- 时间复杂度分析?
只关注循环执行次数最多的一段代码
单段代码看高频:比如循环。
加法法则:总复杂度等于量级最大的那段代码的复杂度
多段代码取最大:比如一段代码中有单循环和多重循环,那么取多重循环的复杂度。
乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积
嵌套代码求乘积:比如递归、多重循环等。
多个规模求加法:比如方法有两个参数控制两个循环的次数,那么这时就取二者复杂度相加
多个规模求乘法:比如方法有两个参数控制两个循环的次数,那么这时就取二者复杂度相乘
- 常用的时间复杂度分析?
多项式阶:随着数据规模的增长,算法的执行时间和空间占用,按照多项式的比例增长。
包括 O(1)(常数阶)、O(logn)(对数阶)、O(n)(线性阶)、O(nlogn)(线性对数阶)、O(n2) (平方阶)、O(n3)(立方阶)。
时间复杂度分类
时间复杂度可以分为:
最好情况时间复杂度(best case time complexity):在最理想的情况下,执行这段代码的时间复杂度。
最坏情况时间复杂度(worst case time complexity):在最糟糕的情况下,执行这段代码的时间复杂度。
平均情况时间复杂度(average case time complexity),用代码在所有情况下执行的次数的加权平均值表示。也叫 加权平均时间复杂度 或者 期望时间复杂度。
均摊时间复杂度(amortized time complexity): 在代码执行的所有复杂度情况中绝大部分是低级别的复杂度,个别情况是高级别复杂度且发生具有时序关系时,可以将个别高级别复杂度均摊到低级别复杂度上。基本上均摊结果就等于低级别复杂度。
- 时间复杂度消耗时间排序
常用的时间复杂度所耗费的时间从小到大依次是:
O(1) < O(logn) < (n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < O(nn)
- 空间复杂度分析
时间复杂度的全称是 渐进时间复杂度,表示 算法的执行时间与数据规模之间的增长关系 。
类比一下,空间复杂度全称就是 渐进空间复杂度(asymptotic space complexity),表示 算法的存储空间与数据规模之间的增长关系 。
定义:算法的空间复杂度通过计算算法所需的存储空间实现,算法的空间复杂度的计算公式记作:S(n) =O(f(n)),其中,n 为问题的规模,f(n) 为语句关于 n 所占存储空间的函数。
- 如何掌握好复杂度分析方法 ?
平时我们在写代码时,是用 空间换时间 还是 时间换空间,可以根据算法的时间复杂度和空间复杂度来衡量。
- 判断一段字符串是否为回文?
回文是指把相同的词汇或句子,在下文中调换位置或颠倒过来,产生首尾回环的情趣,叫做回文,也叫回环。
比如 abba,redder…
1.字符串转数组;2.用reverse()函数颠倒;3.使用join(’’)拼接成字符串
function reverseFn( str ) { return str == str.split(',').reverse().join('') }
- 思考一下给你一个数组,你会怎么去重?
1 利用ES6(Set)的数组去重。
2 双层for循环,然后再用splice进行去重。
3 利用indexOf()或 include进行去重。
4 利用sort()进行排序在遍历进行去重。
5 利用includes过滤进行去重。
6 对象的属性不能相同的特点进行去重。
7 利用filter过滤进行去重。
8 利用递归进行去重,排序以后,再递归,在去重。
9 Map数组结构进行去重。
10 Array.from(new Set(arr))
11 let a = {},[a,a,{}]的情况
然后请思考美种数据结构分别应用了什么数据类型,以及在生活中的场景和实践应用