数据结构笔记

 

目录

首先较常见的线性结构如下:

向量(vector):

列表(LIST):

堆栈(Stack):

队列(queue):

下面介绍半线性结构——树:

二叉树(二叉树-BinTree):

二叉搜索树(Binary search tree-BST):

平衡二叉搜索树(BBST):

AVL:

伸展树:

B树(B-Tree): 

红黑树(Red-Black Tree):

词典-散列表(哈希表-Hash table):

优先队列(priority queue):

完全二叉堆(Complete Binary Heap):

左式堆 :

串:

KMP算法:

BM算法:

Karp-Rabin(KR)算法:

下面介绍非线性结构——图:

图(Graph):

排序算法:

1、冒泡排序:

2、插入排序:

3、希尔排序(缩小增量排序):

4、选择排序:

5、快速排序

6、堆排序:

7、归并排序:

8、计数排序:

9、桶排序:


首先较常见的线性结构如下:

向量(vector):

与常见的数组极为相似,申请的是连续地址下的一段内存空间。不同点有很多,主要的点包括:作为一个类,接口的使用很方便,有很多较为使用的函数(包括排序、查找等),其占用的内存空间可以动态变化,当当前大小的内存空间被利用完后仍需要增加数据时会自动扩容(当然自动指的也是类里面定义的扩容函数)。向量的查找(search)操作效率很高为O(logn)的时间复杂度(这是采用二分查找的优势)。常用的排序方法为起泡排序(时间复杂度为稳定的O(n^2))和归并排序(时间复杂度为稳定的O(nlogn))。数据的获取采用call by rank模式,为O(1)的时间复杂度。

列表(LIST):

通过链表实现,与向量的区别在于其不要求数据的地址空间连续,而是通过记录前驱和后驱指针来保持数据的连续性,与向量结构相比,其优点在于对数据的插入和删除操作时O(1)的时间复杂度,而向量是O(n),缺点是其对于数据的查找工作是O(n)的时间复杂度,而向量是O(logn)。常用的排序方法为选择排序(每次找到无序列表中最小的取出)和插入排序(向已排序序列中插入新数据以满足有序性,类似于摆扑克牌)。数据的获取采用call by position模式。

堆栈(Stack):

LIFO(后入先出)结构,通过vector结构实现(这是因为只需要再栈顶进行数据的添加和删除,而vector结构的最后一个数据的插入和删除操作时间复杂度均为O(1),且对应的接口基本满足堆栈的要求)。

队列(queue):

FIFO(先入先出)结构,通过List结构实现(这是因为队列要在数据的头部尾部分别进行插入和删除操作,而List结构的插入和删除擦欧总均为O(1),且对应的接口基本满足队列的要求)。

上面提到的线性基础结构为vector和List都有其优缺点,但其都无法满足高查找效率和高插入删除效率的要求,即高效地兼顾静态操作和动态操作。

下面介绍半线性结构——树:

可以视为List<List>(列表的列表)结构,也可以看作是二维的列表,可以视为半线性结构,其更多的表示一种层次关系。

二叉树(二叉树-BinTree):

利用类似于链表的结构,不同的是每个二叉树节点-BinNode其带有的指针为一个父亲节点和两个孩子节点,其用于描述任意有根且有序的多叉树,其演绎的过程如下图。

 值得注意的是,在对二叉树遍历的时候有时需要用到其他数据结构,对于先序(根-左-右)、中序(左-根-右)、后序(左-右-根)遍历来说,其模式类似于DFS,因此在不采用递归调用的情况下需要使用堆栈结构;而对于层次遍历来说,其模式类似于BFS,因此其在不采用递归调用的情况下需要利用队列结构。

二叉搜索树(Binary search tree-BST):

数据的获取采用call by key模式,其数据获取和查找、插入、删除的操作时间复杂度均为O(h),其中h为树的高度。不同于基本的二叉树,BST的结构具有有序性,每个轴点都不小于其左子树并且不大于其右子树,这一特性就使得对其进行中序遍历后,得到的序列为非降序列(这里指的是key),示意图如下:

其中,插入、删除、查找的操作都是从根节点出发依次与节点key值进行比较进而判断将要操作的值所在的位置以满足其有序性。

平衡二叉搜索树(BBST):

由于BST的O(h)的时间复杂度带有很大的不确定性,即树的高度h的范围为[logn,n]这样一个区间。而BBST在设计上保证了高度渐进的不超过logn,继而将时间复杂度降至O(logn),具体的方法是通过等价变换来调整树达到平衡。典型的实现类型包括AVL树和红黑树等。下面详细介绍:

AVL:

AVL树在判断树是否平衡时引入了平衡因子,即每一节点的左右子树的高度差,如果差值的绝对值大于1,说明不平衡需要恢复平衡。可以证明这样的一种结构要求使得其高度渐进为logn。

这里失衡后的回复平衡操作对于插入和删除而言是有区别的,但都可以通过单旋和双旋来完成,区别在于插入操作无需要向上判断至根节点而删除操作需要判断以恢复由旋转而导的更高层的节点失衡(最坏的情况需要重新调整logn次)。通过旋转的方法比较复杂,一般采用3+4重构的方法直接进行恢复平衡,形象的来说,旋转对应于魔方的扭动,而3+4相当于打散重新组装。具体的3+4就是找到失衡节点的祖孙三代的三个节点以及致其下面的4个子树,进而进而重构。如下图所示,即为3+4重构的示意图(在g处失衡)。

             

伸展树:

伸展树是在BST的基础上进行调整。考虑到局部性(即上一次被查找的数据,更有可能在这次中被查找),对每次查找的节点将其移至根节点,这样对于伸展树来说,search操作将会改变树的拓扑结构,将不再是静态操作。其中移至根节点可以通过旋转逐层向上,如下图,这种方法的时间复杂度为O(n),显然不能够让人满意。

而根据Tarjan的双层伸展算法,这个移至根节点的均摊时间复杂度为O(logn),其采用的是每次对两层进行调整,这样使得每次调整后的树在该路径下深度减半,其操作示意图如下,注意的是,其不同是旋转次序不同,双层调整首先以祖父节点(g)为轴旋转,而单层调整先以父节点(p)为轴旋转。

 两种调整策略在坏的情况下的不同表现如下:

 

B树(B-Tree): 

B树与上述的树结构不同,其并不是二叉树的结构,而是一种多路平衡的搜索树。其设计是考虑到实际需要的数据越来越多而内存却并不够用的情况,更具体的是在I/O访问的情况,即内存与外存的数据交换需要大量的时间(不过这种消耗在1B和1KB的数据量上的时间花费是基本相当的)。其结构如下图所示,与AVL树的区别在于每个节点不仅只有一个关键码(key),而是具有多个(可称之为超级节点),这样每次访问时得到的数据即为多个(大小即为数据块的大小,常在200-300间,设256),这种方式使得单词查找所需的I/O操作为log(256,n)。同时其每个叶节点的深度都相等,同时外部节点的深度也都相等(外部节点即叶节点的孩子)。

不同的B树,阶数不同,对于一m阶B树,其每个内部节点中关键码个数不超过m-1个࿰

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值