常规数据结构
本文总结自 数据结构与算法-js实现
数据结构:用来组织数据的结构,方法无非是查找、增加、移除;
常见结构
- array:长度固定,使用 index 进行操作
方法:push();pop()-移除索引值最大的元素; - LinkedList:增加删除很方便,连接查找不方便
在计算机科学中, 一个 链表 是数据元素的线性集合。在最简单的形式下,每个节点由数据和到序列中下一个节点的引用(换句话说,链接)组成。
方法:prepend(value);append(value);delete(value);find;reverse; - doubly linkedlist:双向链表:每个节点包含两个字段,称为链接,它们是对节点序列中上一个节点和下一个节点的引用。 方法:与链表结构一样
- queue:队列基本操作有两种:向队列的后端位置添加实体,称为入队;从队列的前端位置移除实体,称为出队。FIFO
方法:入队enqueue(value);出队dequeue();peek()访问结构中的当前元素(不删除) - stack:栈基本操作有两种:push, 添加元素到栈的顶端;pop, 移除栈最顶端的元素。LIFO
方法:push(value);pop();peek() - HashTable:依赖LinkedList,哈希表(hashtable 或hashmap) 是一种实现 关联数组(associative array) 的抽象数据;该结构可以将 键映射到值。 (mps:实现了数组没有的取值方式)
哈希表使用哈希函数/散列函数来计算一个键在数组或桶(buckets)或槽(slots)中对应的索引,可使用该索引找到所需的值。 理想情况下,散列函数将为每个键分配给一个唯一的桶(bucket)索引,但是大多数哈希表设计采用不完美的散列函数,这可能会导致”哈希冲突(
hash collisions)”,也就是散列函数为多个键(key)生成了相同的索引,这种碰撞必须 以某种方式进行处理(可以类比柳条,柳叶;)。
方法:hash(key)–散列函数;set(key, value)–保存是带有key,做防重复处理; delete(key)
;get(key);has(key);getKeys(); - heap:(直接使用数组存储数据)在计算机科学中, 一个 堆(heap) 是一种特殊的基于树的数据结构。分为两种堆,在一个最小堆(min heap) 中, 如果p是c的一个父级节点, 那么p的key(或value)
应小于或等于c的对应值;在一个最大堆(max heap) 中,p的key(或value)大于c的对应值(都不关心同层级的左右节点间的大小关系)。最大最小维护了所有支点到根节点链路上的递增递减关系。
方法:add();remove();find();peek();poll()-返回堆最顶端的元素(会调整整个结构);swap(
indexOne, indexTwo);heapifyUp(customStartIndex)-从尾巴开始整理树;heapifyDown(customStartIndex = 0)-从顶端开始整理树;index(),has(),element() -基于index操作。 - priority queue:优先队列通常用堆来实现,每个元素都有与之关联的优先级。
二叉树:每个节点分左右子节点的树。二叉树常被用于实现二叉查找树和二叉堆。 - BinaryTreeNode:二叉树,分治思想,递归,双向链表。
- BinarySearchTree:二叉查找树(BST),并且每个节点的值都大于等于其左子树中的所有节点的值而小于等于右子树的所有节点的值(sorted binary trees)。 BST有一个重要性质,就是它的中序遍历结果递增排序。remove()方法是关键。(根据任意两个节点的高度(索引)可以判断大小关系?这里使用的链表结构)
- AvlTree:继承自 BST,self-balancing binary search tree。balance()方法与balanceFactor属性(最终看子节点层级)。
- RedBlackTree:继承自 BST,self-balancing binary search tree。平衡的实现没去理解。
B站红黑树实战
红黑树的约束
- 节点不是红色就是黑色;
- 根节点是黑色,叶节点是不存储数据的黑色空节点;
- 红红节点不能相连;
- 新插入的节点都是红色;
新增节点后的三种操作
- 节点颜色变化
- 场景:父节点,叔叔节点都是红色;
- 操作:父节点,叔叔节点设为黑色,祖父节点设为红色;
- 左旋:
- 场景:父节点是红色,叔叔节点是黑色,当前节点是右子树;
- 操作:父节点逆时针旋转,左子树变成“另一个节点”的右子树;
- 右旋:
- 场景:父节点是红色,叔叔节点是黑色,当前节点是左子树;
- 操作:父节点顺时针旋转,右子树变成“另一个节点”的右子树;
Big O Notation
Big O notation (最大复杂度)is used to classify algorithms according to how their running time or space requirements grow as the input size grows. On
the chart below you may find most common orders of growth of algorithms specified in Big O notation.
Below is the list of some of the most used Big O notations and their performance comparisons against different sizes of the input data.
Big O Notation | Computations for 10 elements | Computations for 100 elements | Computations for 1000 elements |
---|---|---|---|
O(1) | 1 | 1 | 1 |
O(log N) | 3 | 6 | 9 |
O(N) | 10 | 100 | 1000 |
O(N log N) | 30 | 600 | 9000 |
O(N^2) | 100 | 10000 | 1000000 |
O(2^N) | 1024 | 1.26e+29 | 1.07e+301 |
O(N!) | 3628800 | 9.3e+157 | 4.02e+2567 |
Data Structure Operations Complexity
Data Structure | Access | Search | Insertion | Deletion | Comments |
---|---|---|---|---|---|
Array | 1 | n | n | n | |
Stack | n | n | 1 | 1 | |
Queue | n | n | 1 | 1 | |
Linked List | n | n | 1 | n | |
Hash Table | - | n | n | n | In case of perfect hash function costs would be O(1) |
Binary Search Tree | n | n | n | n | In case of balanced tree costs would be O(log(n)) |
B-Tree | log(n) | log(n) | log(n) | log(n) | |
Red-Black Tree | log(n) | log(n) | log(n) | log(n) | |
AVL Tree | log(n) | log(n) | log(n) | log(n) | |
Bloom Filter | - | 1 | 1 | - | False positives are possible while searching |
算法分析指标
算法的复杂性体现在运行该算法时所需的计算机资源多少上,计算机资源最重要的是时间和空间(即寄存器)资源,因此复杂度分为时间和空间复杂度。
- 时间复杂度:是指执行算法所需要的计算工作量;
- 空间复杂度:是指执行这个算法所需要的内存空间。
java 容器实战
HashMap
LinkedHashMap:LinkedHashMap是HashMap的一个子类,记录了的插入顺序。
TreeMap:TreeMap实现SortedMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序。
结构的设计:那么通过什么方式来控制map使得Hash碰撞的概率又小,哈希桶数组(Node[] table)占用空间又少呢?答案就是好的Hash算法和扩容机制。
put 操作
1 | public V put(K key, V value) { |
扩容操作
1 | final Node<K,V>[] resize() { |
1.8的优化
确定哈希桶数组索引位置时:优化了高位运算的算法,通过hashCode()的高16位异或低16位实现的:(h = k.hashCode()) ^ (h >>> 16),主要是从速度、功效、质量来考虑的,这么做可以在数组table的length比较小的时候,也能保证考虑到高低Bit都参与到Hash的计算中,同时不会有太大的开销。
扩容操作时:1.7使用了单链表的头插入方式,1.8单链表的尾插入?;不需要像JDK1.7的实现那样重新计算hash,只需要看看原来的hash值新增的那个bit是1还是0就好了。
链表长度大于8时,链表结构转红黑树。
spring 容器实战
1 | AbstractApplicationContext |