数据结构与算法
数据结构
逻辑结构:线性与非线性 逻辑结构揭示了数据元素之间的逻辑关系
线性数据结构: 数组、链表、栈、队列、哈希表,元素之间是一对一的顺序关系。
非线性数据结构: 树、堆、图、哈希表
树形结构:树、堆、哈希表,元素之间是一对多的关系。
网状结构:图,元素之间是多对多的关系
物理结构:连续与分散
系统通过内存地址来访问目标位置的数据
物理结构反映了数据在计算机内存中的存储方式,可分为连续空间存储(数组)和分散空间存储(链表)
:访问、更新、增删--增删改查
实现:数据结构都是基于数组、链表或二者的组合实现的
基于数组可实现:栈、队列、哈希表、树、堆、图、矩阵、张量(维度 的数组)等。
基于链表可实现:栈、队列、哈希表、树、堆、图等。
其他
Bitmap是一种位图数据结构
布隆过滤器是一种基于 Bitmap 的数据结构,可以用来判断一个元素是否存在于一个集合中。它主要由两个部分组成:位数组和哈希函数
算法
搜索:深度优先搜索(DFS)和广度优先搜索(BFS)是一种用于搜索树或图的算法,
在这个过程中保证图或数的每个结点被访问且仅被访问一次,再按照每个结点访问的顺序不同分为深搜和广搜
排序
数据结构的看法
1.顺序表,链表,树,我们可以将它们分成一类,它们的逻辑底层都是结构体(顺序表一般为数组),
它们的功能都是数据的存储,
顺序表强调的是物理空间的连续关系,
链表强调的是逻辑空间的连续关系,
树更多地强调的是逻辑上的多种联系,三者的本质都是数据的存储手法,
只不过三者的优劣不同:
顺序表的优势在于快捷的随机数据访问,缺点是不能随心所欲地在表的中间增删数据;
链表的优势在于在表中增删数据十分容易,且物理空间上的不连续很好地避免了因内存不足导致过多数据无法存储的情况,但它的随机访问能力相对顺序表较弱,
树的优势在于它对于逻辑关系的表述有先天的优势,对于生活中的复杂关系设计出了父子,兄弟祖孙等多种关系,
而前两者只能表示链式关系,而相应地,树的各种操作也变得更加复杂,如AVL树,红黑树,B树都有恐怖的代码量,
为了让程序员的前期学习变得容易,我们设计出了二叉树,而其中的逻辑关系也较为简单,便于操作
2.栈,队列,堆,我们可以将它们分成一类,它们是一种数据的存储方式,它们的逻辑底层都是顺序表和链表,而顺序表,链表,树在它们中和int,char一样,都仅仅是数据。
栈代表的是井式存储,先进后出,栈顶才能增删,可以形象的理解为往井里扔东西,无论取东西还是扔东西都只能在井口,
队列代表的是流水线式存储,数据先进先出,而只能在队尾写入,在队头删除,可以形象地理解为一个人在传送带一头放东西,另一个人在传送带另一头拿东西,
而堆分为大堆和小堆,是一种完全二叉树,它更多地代表了一种排序的思想,大堆的第一个比其他的都大,小堆的第一个比其他的都小,
其实堆是一种树,应该分在第一类也就是树的子集, 认为它更多地代表了数据的存储方式,
实际应用学原理
二叉树数据结构
遍历方式: 中序遍历
Octree 是一种八叉树数据结构
树型结构是一类重要的非线性数据结构。
其中以树和二叉树最为常用,直观看来,树是以分支关系定义的层次结构
B树和B+树(多路平衡树)
红黑树
二叉查找树(Binary Search Tree) 二叉搜索树(Binary Search Tree, BST)
八叉树结构是由 Hunter 博士于1978年首次提出的一种数据模型。
八叉树结构通过对三维空间的几何实体进行体元剖分,
每个体元具有相同的时间和空间复杂度,通过循环递归的划分方法对大小为 (2n∗2n∗2n)
k-d tree,即k-dimensional tree,是一种高维索引树形数据结构
KD-tree 又称 K 维树,是计算机科学中使用的一种数据结构,用来组织表示 K 维空间中点集合。
它是一种带有其他约束条件的二分查找树。
KD-tree对于区间和近邻搜索十分有用
堆 通常是一个可以被看做一棵树的数组对象。堆的具体实现一般不通过指针域,
而是通过构建一个一维数组与二叉树的父子结点进行对应,因此堆总是一颗完全二叉树
图
邻接矩阵 目前常用的图存储方式为邻接矩阵
DAG数据结构的定义 DAG(Directed Acyclic Graph),即有向无环图
KDTree树
from scipy.spatial import cKDTree
import numpy as np
import time
full_dat = np.arange(45000).reshape(15000,3)
points_1 = np.arange(450000).reshape(150000,3)
points_2 = np.ones((150000,3))
pt_1_time = time.perf_counter()
tree = cKDTree(points_1)
mid_time = time.perf_counter()
pt_2_time = mid_time -pt_1_time
dist, idx = tree.query(full_dat)
pt_all_time = time.perf_counter() -mid_time
print("uniq data time spend",pt_2_time,pt_all_time,points_1.shape,full_dat.shape)
duplicate_pt_1_time = time.perf_counter()
tree_2 = cKDTree(points_2)
mid_time = time.perf_counter()
duplicate_pt_2_time =mid_time - duplicate_pt_1_time
dist, idx = tree_2.query(full_dat)
duplicate_pt_all_time = time.perf_counter()-mid_time
print("repreat dat time spend",duplicate_pt_2_time,duplicate_pt_all_time,points_2.shape,full_dat.shape)
points_3,pt_index,pc_inv,pc_cnt =np.unique(points_2,return_index=True,return_inverse=True,return_counts=True,axis=0)
duplicated_pt_1_time = time.perf_counter()
tree_3 = cKDTree(points_3)
mid_time = time.perf_counter()
duplicated_pt_2_time =mid_time - duplicated_pt_1_time
dist, idx = tree_3.query(full_dat)
duplicated_pt_all_time = time.perf_counter()-mid_time
print("uniq repreat dat time spend",duplicated_pt_2_time,duplicated_pt_all_time,points_3.shape,full_dat.shape)
scipy
from scipy.spatial import distance
import numpy as np
在二维数据点中求欧几里得距离
coords = [(1, 1),
(2, 2),
(3, 3),
(4, 4)]
coord =[(1, 1), (2, 2) ]
result = distance.cdist(coords, coord, 'euclidean')
print(len(coords),len(coord),result.shape)
从3D数据点中找到曼哈顿距离,目标是X=a,Y=b X是对象,Y是目标
a = np.array(coords)
b = np.array(coord)
cal_result = distance.cdist(a, b, 'cityblock')
print(a.shape,b.shape,cal_result.shape)
距离可以选
"braycurtis", "canberra", "chebyshev", "cityblock", "correlation",
"cosine", "dice", "euclidean", "hamming", "jaccard",
"jensenshannon", "kulsinski", "mahalanobis", "matching", "minkowski",
"rogerstanimoto", "russellrao", "seuclidean", "sokalmichener", "sokalsneath",
"sqeuclidean", "wminkowski", "yule".
from scipy.spatial.distance import pdist
from scipy.spatial.distance import cdist
from scipy.spatial import cKDTree
from scipy.spatial import distance
scipy.spatial.transform import Rotation
Slerp(times, rotations)
球面线性插值(Spherical linear interpolation,简称Slerp)
Scipy库的RotationSpline类,可以创建一个插值对象,计算出平滑的旋转、角速度和角加速度,从而实现连续且平滑的旋转效果
超矩形(hyperrectangle)
订阅制和买断制
工具属性--更新迭代慢 --买断
服务属性--更新迭代快 --订阅 订阅和退订--续订率---自身产品挖掘需求,帮助客户用好自家产品
客户玩得转---出于复杂的利益瓜西,中间商不太愿意服务商直接与客户建立联系
刘强东的手把手教会
时间和空间的不同,面对的场景不同
筛选-过滤-提取-搜索-匹配-索引-查询
局部敏感性哈希(LSH)
基于近邻图
基于乘积量化
BF算法,即暴力(Brute Force)算法,是普通的模式匹配算法
FLAT (Flat Index)
FLAT是最简单直接的一种索引方式,它不使用任何压缩或近似方法,而是直接存储所有向量,并在查询时通过计算每个向量与查询向量之间的距离来找到最近邻
精确搜索(exhaustive search)
K-最近邻搜索(K-Nearest Neighbour,KNN)
树类索引--适用:低维度(<30)数据
kd Tree 是k-dimensional tree,是一种分割k维数据空间的数据结构
Ball Tree:在高维数据上比 k-d tree 表现更好,尤其是当数据分布不均匀时。scikit-learn 提供了 BallTree 实现。
ball tree将使用超球面而不是超平面来划分空间。虽然在构建数据结构的花费上大过于kd-tree
图类索引
HNSW HNSW(Hierarchical Navigable Small World) HNSW全称Hierarchical NSW,NSW是Navigable Small World,即“可导航小世界网络”算法
HNSW索引是一种基于图的索引算法,可以提高搜索高维浮动向量时的性能
近似最近邻搜索(Approximate Nearest Neighbor, ANN)
哈希类索引
LSH(Locality-Sensitive Hashing)
FLANN(Fast Library for Approximate Nearest Neighbors):用于近似最近邻搜索,比精确搜索更快,尤其适用于大规模高维数据。
FLANN(Fast Library for Approximate Nearest Neighbors)是一个开源的C++库,用于在高维空间中进行近似最近邻搜索
精确最近邻搜索不同,近似最近邻搜索不保证找到距离最小的点,但可以在更短的时间内找到一个距离相对较小的点
FLANN 是 SIFT 发明者 Lowe 开发的近似搜索库
Annoy: (由 Spotify 开源) 开源的近似最近邻算法库,适合大规模高维数据,支持内存映射文件。‘’
ScaNN ScaNN 是谷歌在 2020 年发布的一款向量检索工具
IVFPQ 用的是分桶+倒排的方式
IVF-PQ(Indexed Vector Fields - Product Quantization) 乘积量化(Product Quantization)简称 PQ
其他
Faiss (Facebook AI Similarity Search) 针对高维空间中的海量数据,提供了高效且可靠的检索方法
3.乘积量化
乘积量化的核心思想是通过空间切分,将高维的向量通过预处理压缩到低维度,比较有代表性的有PQ算法,PQ和倒排索引结合的IVFPQ
IVF (Inverted File Index) IVF是一种基于倒排表的索引策略
scipy.spatial.transform.Rotation
欧拉角,旋转向量,四元数,旋转矩阵
from_euler(cls, seq, angles[, degrees])
from_rotvec(cls, rotvec[, degrees])
from_quat(cls, quat, *[, scalar_first])
from_matrix(cls, matrix)
from_mrp(cls, mrp)
from_davenport(cls, axes, order, angles[, ...])
MRP,改进型 Rodrigues 参数 (Modified Rodrigues Parameters, MRP) 描述两坐标系方向关系的数学工具,
修正罗德里格斯参数 由欧拉四元数衍生而来
达文波特角,就像欧拉角一样,存在万向节锁的问题
偏流角(Draft Angle简写为DA)通常指得是受侧风影响航向偏移的最大角度
参考
向量检索中多种类型的索引结构 https://zhuanlan.zhihu.com/p/1920468862580785516
Hello 算法 https://www.hello-algo.com/chapter_hello_algo/
浙公网安备 33010602011771号