数据结构与算法分析 java语言描述-树

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/u010597819/article/details/89304171

磁盘与CPU访问成本分析

CPU:1台500-MIPS(500MHz)的机器,即可能每秒执行50010001000=5亿条指令。
磁盘:7200RPM的磁盘,即每分钟7200转;因此1转=60/7200=1/120秒,或即8.3毫秒。
磁盘访问时间分为三部分:

  • 寻道时间,也称寻找时间:磁头移动到指定磁道需要的时间
  • 延迟时间:磁头定位到某一磁道的扇区所需要的时间
  • 传输时间:从磁盘读出或者写入经历的时间

平均可以认为磁盘转到一半的时候发现我们要寻找的信息,但是移动磁盘磁头读取磁道上数据耗时通常简化计算,即读取一个磁道上数据的耗时就是转动一圈的时间,即我们得到访问时间为8.3毫秒。
一次磁盘访问的价值约是80W(万)条指令。
这里每一个数据都是粗略的计算,不过相对速度还是清楚的:磁盘访问的代价太高了。
因此,为了节省一次磁盘访问,我们愿意进行大量的计算。几乎在所有的情况下,控制运行时间的都是磁盘访问的次数。于是把磁盘访问次数减少一半,那么运行时间也将减半。

二叉树与B树

二叉树基础知识

  1. 深度:根节点至各个节点的层数。根节点深度为0
  2. 高度:叶子节点至各个节点的层数。叶子节点高度为0
  3. 深度与二叉树层数关系
  4. 二叉树节点数:2^0 + 2^1 + 2^3 + … + 2^m
  5. 等比数列求和公式:。a1是第一个元素值,q为公约数即等比的比值,例如二叉树为2,n为前n项
  6. 二叉树节点数量代入公式计算得:n=2^(m+1)-1;由于m>=0,顾此处是m+1。
  7. 深度m等于log以2为底(n+1)的对数-1,即log2(n+1)-1。
  8. 平均查找长度:ASL=∑PiCi (i=1,2,3,…,n),可以简单以数学上的期望来这么理解。其中:Pi 为查找表中第i个数据元素的概率,Ci为找到第i个数据元素时已经比较过的次数。
  9. 假定每个元素的概率相同也就是1/n。
  10. 查找每个节点比较的次数也就是节点的深度d+1。
  11. 平均查找长度= 每个结点的深度的总和 / 总结点数。每个结点的深度的总和=对深度的等差数列(0至log2(n+1)-1)求和;总结点数=2^(m+1)-1,其中m=log2(n+1)-1。
  12. ∴ P(n)=P(n,i)/n <= 2(1+I/n)lnn
  13. 因为 2(1+I/n)lnn≈1.38logn。故P(n)=O(logn),与时间复杂度相等
  14. 时间复杂度:log以2为底N的对数。伪代码中可以看到,第一次二分剩余元素数量n/2;第二次剩余n/2/2;第m次剩余n/2^m; 假设最后一次查找到元素,即n/2^m=1(命中目标时只剩下一个元素)。所以时间复杂度计算单元计算次数m=log2(N)。
//伪代码
lookup(Node node, int aim) {
  if (node == null) {
    return null;
  }
	if (node.getData == aim) {
		return node.getData;
  }
  if (node.getData < aim) {
    lookup(node.getLeft, aim);
  } else {
    lookup(node.getRight, aim);
  }
}
  1. 时间复杂度数学证明
  2. 定理:如果x是一棵有n个节点子树(二叉树)的根,那么调用INORDER-TREE-WALK(x)遍历树需要花费log2(N)时间
  3. 证明:当INORDER-TREE-WALK作用于一棵有n个节点子树的根时,用T(n)表示需要的时间。由于INORDER-TREE-WALK要访问全部n个节点,T(n)=Ω(n)。下面仍需要证明T(n) = O(n).
  4. 由于对于一棵空树,INORDER-TREE-WALK需要耗费一个小的常数时间(因为测试node不为null),因此对于某个常数c>0,有T(0)=c。
  5. 对n>0,假设调用INORDER-TREE-WALK作用在一个节点x上,x节点左子树有k个节点且右子树有n-k-1个节点,则执行INORDER-TREE-WALK(x)的时间有T(n)≤T(k)+T(n-k-1)+d限界,其中常数d>0。
  6. 使用替换法,通过证明T(n)≤(c+d)n+c,可以得证T(n)=O(n)。对于n=0,有(c+d)*0+c=c=T(0)。对于n>0,有:image.png
INORDER-TREE-WALK(node)
	if node != null
    INORDER-TREE-WALK(node.left)
    print node.data
    INORDER-TREE-WALK(node.right)

在磁盘上,典型的查找树执行如下:假设有1000W项数据,每一个关键字是32字节(代表一个名字),而一个记录是256字节。假设这些数据不能都装入主存,而我们是正在使用系统的20个用户之一(因此有1/20的资源)。这样,在1秒内,我们可以执行2500万次指令,或者执行6次磁盘访问。
不平衡的二叉查找树是一个灾难。在最坏情形下它具有线程深度,从而可能需要1千万(10000000)次磁盘访问。平均来看,一次二叉树存储结构成功的查找可能需要1.38logN(以2为底N的对数)次磁盘访问,由于log10000000≈24,因此平均一次查找需要32次磁盘访问,或5秒(32次8.3毫秒20个用户)的时间。在一棵典型的随机构造的树中,我们预料会有一些节点的深度要深3倍;他们需要大约100次磁盘访问,或16秒(100次8.3毫秒20个用户)的时间。AVL树(自平衡二叉树)多少要好一些。1.44logN的最坏情形不可能发生,典型的情形是非常接近与logN(接近完全平衡)。这样,一棵AVL树平均将使用大约25次磁盘访问,需要的时间是4秒(25次8.3毫秒20个用户)。
我们想要把磁盘访问次数减小到一个非常小的常数,比如3或4;由于AVL树接近到最优的高度,所以二叉查找树是不可行的。使用二叉查找树我们不能行进到低于logN。
解法直觉上看是简单的:如果有更多的分支,那么就有更少的深度。于是便有了B树以及B+Tree等树结构
阶为M的B树是一棵具有下列特性的树:

  1. 数据项存储在树叶上。
  2. 非叶节点存储直到M-1个关键字以指示搜索的方向;关键字i代表子树i+1中最小的关键字
  3. 树的根或者是一片树叶,或者其儿子数在2和M之间。
  4. 除根外,所有非树叶节点的儿子数在[M/2]和M之间。
  5. 所有的树叶都在相同的深度上并有[L/2]和L之间个数据项。

image.png

猜你喜欢

转载自blog.csdn.net/u010597819/article/details/89304171