数组
数组是由类型相同的数据额元素组成的有序集合,每个元素称为数组元素。
优点:
按照索引查询元素速度快
按照索引遍历数组方便
缺点:
数组的大小固定后就无法扩容了
数组只能存储一种类型的数据
添加、删除的操作慢,因为要移动其他的元素
适用:
频繁查询,对存储空间要求不大,增加和删除次数少的情况
栈
内存中的堆栈可以理解成真实存在的物理内存区域
堆栈:逻辑 入栈、出栈
栈:是一种受限制的限制表,后进先出
例如:JavaScript的调用栈(执行栈): 全局执行上下文、函数执行上下文、eval
调用帧
尾调用:一个函数的最后一步是调用另一个函数
尾递归:尾调用自身,尾递归。
递归非常耗费内存,因为它需要同时保存很多个调用帧,尾递归只存在一个调用帧,所以它不会发生栈溢出错误。
队列
队列是一种受限的线性表,先进先出
队列值允许在表的前端进行删除,在标的后端插入
例如:JS的异步队列。
JS语言特点是单线程,单线程意味着所有的任务需要排队执行,前一个任务结束,才会去执行后一个任务。
执行顺序:
1、所有额同步任务:主线程上执行,执行栈
2、主线程之外,任务队列。
3、一旦执行栈所有的同步任务执行完毕之后,系统就会去读取任务队列。
4、主线程其实就是不断地重复上面的三个步骤。
js中异步:定时器,ajax,事件
事件循环:
1、同步代码,执行完毕后,立即出栈,让出主线程
2、主线程是空闲状态,去读取任务队列
3、任务队列(微任务——>宏任务)
链表
线性表的链式存储结构特点是:
用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。
数据元素的逻辑顺序是通过链表的指针地址实现,每个元素包括两个结点,一个是存储元素的数据域(内存空间),一个是指向下一个结点地址的指针域。根据指针的指向,链表能形成不同的结构,例如单链表,双链表,循环链表等。
优点:
链表不需要初始化容量,可以任意加减元素。
添加或者删除元素时只需要改变前后两个元素结点的指针域指向地址即可,所以添加删除很快。
(线性表查找复杂度为O(1),添加删除元素复杂度为O(n),而链表查找复杂度为O(n),添加删除元素时空复杂度为O(1))
缺点:
因为含有大量的指针域,占用空间较大。
查找元素需要遍历链表,非常耗时。
适用:
数据量较小,需要频繁增加删除操作的场景。
哈希
1、哈希:就是把任意长度的输入通过散列算法变换成固定长度的输出。
不可逆
2、插入删除链表的性能好,查询用数组性能好的,下标去查询,按内容,能够让我们的字符串变成我们的数组的索引。
3、哈希表也算是数组,key-value形式存储的数据结构,不同点在于哈希表的key是经过一个哈希函数计算出来的。
4、对于索引下标的改变,改变方式称之为哈希函数。
通过一个哈希函数,把要存储的值能够映射到一个位置,这个位置就是它的下标或者索引。
传一个字符串——数组的下标。
5、冲突问题(索引相同):后添加的会覆盖其那面的。叫做哈希覆盖。
6、解决冲突:
链地址法:数组存储的不是实际的值,存储一个链表用来存储实际数据。
(来一个相同的数据,就将它插入到单元对应的链表中)
开放地址发:1、线性探索法,线性探索法存在的问题:聚集。
树
1、树是n个结点的有限集合,n=0时,为空树。
2、任意非空树,有且仅有一个特定的称为root的结点。
树形结构是一种具有递归特征的数据结构(任何一个子树又满足数的概念)
3、树的存储结构
顺序存储或者是链式存储,树的结构不能直接存储,需要转换顺序存储或者链式存储。
双亲表示法:顺序存储各个结点的同时,给各个结点添加一个变量,记录其父节点的位置。
孩子表示法:建立多个指针域,指向它所有子节点的地址,任何一个结点,都会掌握它所有子节点的信息。
孩子兄弟表示法:从树的根节点开始,依次采用链表去存储各个结点的孩子结点和兄弟节点,可以把一棵普通的树,转换成二叉树。
二叉树
树的每个节点只有一或两个子节点,叫做二叉树,二叉树可以为空。
特点:
1、每个结点最多有两棵子树,所有二叉树不存在度大于2的结点。
2、一棵树中,最大的结点的度称为树的度,结点的度:结点所拥有的子树的个数。
3、左子树和右子树是有顺序的,次序不能任意的颠倒。
4、即使数某个结点只有一颗子树,也要区分左右
二叉搜索树
就是在普通二叉树上加了限制。
性质:
左子树键值小于根结点。
右子树键值大于根节点。
左右子树本身也是二叉搜索树
特点:小的在左,大的在右
遍历:先序遍历:根左右
中序遍历:左根右
后序遍历:左右根
优点:可以快速找到给定的关键字的数据项,快速插入和删除数据。
缺陷:时间性能上有局限性。
红黑树
红黑树是一种平衡的二叉搜索树,
特性:
1、结点最开始同意为红色
2、根节点是黑色
3、每个叶子节点都是黑色的空节点。
4、每个红色节点的两个子节点都是黑色。
5、从任意结点到每个叶子节点的所有路径包含相同数量的黑色结点
从根节点到叶子节点的最长路径不大于最短路径的二倍
当插入和删除结点时,就会导致红黑树的平衡被破坏,这个时候需要对红黑树调整(变色、旋转)。
哈夫曼树
图
1、集合:同属于一个集合,
线性结构:一对一;
树形结构:一对多;
图形结构:多对一
2、图形结构:顶点、边
3、图的分类:
无向图:边没有方向的图,边与边之间仅仅是连接。
有向图:边具有方向性。
带权图:边带着权重
4、邻接矩阵:1表示两者连接,0表示无连接。
算法复杂度
算法的时间复杂度:一个算法的执行时间根据数据规模增长的一个趋势。
T(n)=O(f(n))
常见的时间复杂度
哈希表的插入时间复杂度平均O(1),最好O(1),最差O(n)。
排序链表的插入时间复杂度平均O(n),最好O(1),最差O(n)。
数组的查询时间复杂度平均O(n),最好O(1),最差O(n)。
二叉树的查询时间复杂度平均O(logn),最好O(logn),最差O(n)。
二叉查找树的时间复杂度平均O(logn),最好O(logn),最差O(logn)。
二叉平衡树的时间复杂度平均O(logn),最好O(logn),最差O(logn)。
红黑树的时间复杂度平均O(logn),最好O(logn),最差O(logn)。
冒泡排序的时间复杂度平均O(n2),最好O(n),最差O(n2)。
插入排序的时间复杂度平均O(n2),最好O(n),最差O(n2)。
选择排序的时间复杂度平均O(n2),最好O(n2),最差O(n2)。
归并排序的时间复杂度平均O(nlogn),最好O(nlogn),最差O(n*logn)。
希尔排序的时间复杂度最好O(n),最差O(n2)。快排的时间复杂度平均O(nlogn),最好O(nlogn),最差O(n2)。
冒泡排序
本质:升序排列,大的放后面,小的放前面。(左右交换)
过程:让数组的当前项和后一项比较,如果当前项比后一项大,就换位置,往后继续。
时间复杂度
最差:每一个都要轮一遍即(n-1)+(n-2)+(n-3)+...+1=n*(n-1)/2 =O(n²)
选择排序
本质:第一轮会选出最小值,第二轮选出第二小的。从前往后选择交换。
过程:选第一个,和后面依次比,找到比他小的,就换,换完再比,直到第一个是最小的。找完最小的,找第二小的。
插入排序(打牌)
本质:效率最高,从后向前遍历。
过程:在已经排好的后面插入,新元素小于后面这个元素,就放前面,依次前推,找到已经元素小于或者等于这个新元素,就停止前推。
希尔排序
本质:插入排序,对数组进行了等间隔的分组处理,每一组中插入排序。
第一次排序的时候,每一组的较小的元素都移动到了相对靠前的位置。
过程:按一定的间隔对数组进行分组,在每一个分组中做插入排序;随后逐次缩小间隔,再
在每一个分组中进行插入排序,知道间隔等于1.做一次插入排序结束。
归并排序
本质:拆分和归并、分治
过程:将数组分成前后两部分,分别排序,再合并在一起
快速排序
本质:
过程:选择一个元素作为基准,对基准的左边和右边的两个子集,不断重复第一步和第二步知道所有元素只剩一个。
计数排序
本质:堆
过程:提供一个足够大(包括提供数据的范围),都是0的数组。遍历提供数组,找到顺序对应的索引,对值++,没找到就0。