A080300 平衡二叉树
平衡二叉树深度公式

平衡二叉树深度公式
平衡二叉树深度公式是指计算平衡二叉树的深度的公式。
平衡二叉树是一种特殊的二叉树,它的左右子树的深度相差不超过1,因此可以保证平衡二叉树的查找、插入和删除操作的时间复杂度都是
O(log n)。
平衡二叉树的深度公式如下:
depth = max(left_depth, right_depth) + 1
其中,left_depth表示左子树的深度,right_depth表示右子树的深度,+1表示当前节点的深度。
通过这个公式,可以方便地计算平衡二叉树每个节点的深度。
同时,由于平衡二叉树的左右子树深度相差不超过1,因此可以使用递归的方式快速计算整棵树的深度。
- 1 -。
平衡二叉树旋转例题

平衡二叉树旋转例题摘要:I.平衡二叉树的概念及特点II.平衡二叉树旋转的定义和目的III.平衡二叉树旋转的实例解析IV.平衡二叉树旋转的操作步骤及要点V.平衡二叉树旋转的应用场景正文:I.平衡二叉树的概念及特点平衡二叉树(Balanced Binary Tree)是一种特殊的二叉树结构,具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
平衡二叉树的特点是每个节点的左右子树的高度差的绝对值不超过1,这使得树的高度保持在一个相对平衡的状态,从而保证了树的稳定性和查找效率。
II.平衡二叉树旋转的定义和目的平衡二叉树旋转是一种处理树不平衡问题的方法。
当二叉树的平衡条件被破坏时,需要通过旋转操作来重新平衡树。
旋转的目的是调整树的结构,使得树的左右子树的高度差的绝对值不超过1,从而保证树的稳定性和查找效率。
III.平衡二叉树旋转的实例解析假设有一棵平衡二叉树,其结构如下:```10/4 20/2 6 8```当插入一个新的节点14 后,树的结构变为:```10/4 20/2 6 8 14```由于树的平衡条件被破坏,需要进行旋转操作。
旋转后的树结构如下:```14/4 10/2 6 8```可以看到,通过旋转操作,树的平衡条件得到了恢复。
IV.平衡二叉树旋转的操作步骤及要点平衡二叉树旋转操作分为以下两种:左旋和右旋。
左旋操作:将当前节点的右子树旋转到左子树的左侧,即将右子树的根节点提升为当前节点的左子节点,原左子节点变为右子节点。
右旋操作:将当前节点的左子树旋转到右子树的右侧,即将左子树的根节点提升为当前节点的右子节点,原右子节点变为左子节点。
旋转操作的要点是选择好旋转的中心节点,以及注意旋转后子节点关系的调整。
V.平衡二叉树旋转的应用场景平衡二叉树旋转在实际应用中主要应用于二叉查找树(Binary Search Tree)的维护。
当二叉查找树中的节点不平衡时,通过旋转操作可以调整树的结构,使得树的查询效率保持在较高的水平。
二叉树总结(四)平衡二叉树

⼆叉树总结(四)平衡⼆叉树平衡⼆叉树概念AVL树是根据它的发明者G.M. Adelson-Velsky和E.M. Landis命名的。
它是最先发明的⾃平衡⼆叉查找树,也被称为⾼度平衡树。
相⽐于"⼆叉查找树",它的特点是:AVL树中任何节点的两个⼦树的⾼度最⼤差别为1。
AVL树的查找、插⼊和删除在平均和最坏情况下都是O(logn)。
如果在AVL树中插⼊或删除节点后,使得⾼度之差⼤于1。
此时,AVL树的平衡状态就被破坏,它就不再是⼀棵⼆叉树;为了让它重新维持在⼀个平衡状态,就需要对其进⾏旋转处理。
平衡⼆叉树结构:typedef int Type;typedef struct AVLTreeNode{Type key;int height; //当前节点的⾼度struct AVLTreeNode *left; // 左孩⼦struct AVLTreeNode *right; // 右孩⼦}Node, *AVLTree;平衡⼆叉树修复⽅法当插⼊⼀个元素使平衡⼆叉树不平衡时,可能出现以下的四种情况:1. LL:称为"左左"。
插⼊或删除⼀个节点后,根节点的左⼦树的左⼦树还有⾮空⼦节点,导致"根的左⼦树的⾼度"⽐"根的右⼦树的⾼度"⼤2,导致AVL树失去了平衡。
例如,在上⾯LL情况中,由于"根节点(8)的左⼦树(4)的左⼦树(2)还有⾮空⼦节点",⽽"根节点(8)的右⼦树(12)没有⼦节点";导致"根节点(8)的左⼦树(4)⾼度"⽐"根节点(8)的右⼦树(12)"⾼2。
1. LR:称为"左右"。
插⼊或删除⼀个节点后,根节点的左⼦树的右⼦树还有⾮空⼦节点,导致"根的左⼦树的⾼度"⽐"根的右⼦树的⾼度"⼤2,导致AVL树失去了平衡。
平衡二叉树的旋转操作及多路平衡树算法

平衡二叉树的旋转操作及多路平衡树算法平衡二叉树是一种二叉搜索树,它的每个节点的左右子树高度差不超过1,以保证树的高度不会退化到倾斜的情况,从而保证了树的查找、删除、插入等操作的高效性。
平衡二叉树的常见实现有AVL树、红黑树等。
其中,AVL树是以其创始人Adelson-Velsky和Landis的姓氏命名的。
平衡二叉树的平衡性是通过旋转操作来实现的。
旋转操作可以分为左旋和右旋,它们的本质是交换树中的节点和其孩子节点的位置。
以左旋为例,对于一个节点x,如果其右孩子y的左子树高度大于右子树,则进行左旋操作。
左旋操作会使得y成为x的父节点,y的左子树成为x的右子树,而x则成为y的左子树。
右旋操作也类似,不再赘述。
多路平衡树是一种类似于平衡二叉树的树结构,它允许节点有多个孩子节点。
常见的多路平衡树有B树、B+树、B*树等。
多路平衡树通过将节点的孩子节点个数限制在某个范围内,来保证树的高度不会过高。
这样一来,对于大规模数据的存储和查找操作,多路平衡树比平衡二叉树更加适用。
以B树为例,它的每个节点可以有多个孩子节点,通常包括一个元素序列和比它小的子树数序列。
一个2-3-4 B树(也称为2-3-4树)是一种B树,其中每个节点可以有1、2或3个元素和2、3或4个子节点。
当一个节点中的元素个数达到3时,需要进行分裂操作。
例如,当4插入到一个节点中,它会导致节点分裂成两个,其中3为左子节点,5为右子节点。
此时,中间的元素4会被提升成为父节点,并且左右子树分别指向新的节点。
在多路平衡树中,同样可以通过旋转操作来保持树的平衡性。
不过,与平衡二叉树不同的是,对于多路平衡树来说,旋转操作需要考虑不止一个节点的位置关系。
例如,在2-3-4 B树中,左旋操作会导致3个节点的位置变化,右旋操作会导致4个节点的位置变化。
因此,多路平衡树的旋转操作相对平衡二叉树而言,更加复杂。
同时,多路平衡树也因此在存储和查询效率上更加卓越。
总而言之,平衡二叉树和多路平衡树都是目前常见的数据结构,它们都通过树型结构的特性实现了高效的查找、删除、插入操作。
平衡二叉树(AVLtree)

平衡⼆叉树(AVLtree)⼆叉查找树在极端情况下会演变成⼀棵只有⼀侧⼦孩⼦的树,例如每个⾮叶⼦只有左孩⼦或者右孩⼦,这时候在查找的时候就需要遍历这棵树来找到⽬标值,它的快速搜索价值就体现不出来了,如果这棵搜索树在构建的时候,能够平衡左右⼦树的⾝⾼差,使得左右⼦树⾝⾼差不超过1,那它的搜索效率就是O(lgn),平衡⼆叉树就是这样的树,它有以下特点:1、左右⼦树的⾼度差不超过12、左右⼦树都是平衡⼆叉树,空节点也视其为⼀棵平衡⼆叉树以上有点递归定义问题的意思,平衡⼆叉树的关键特性是其任何⼀个节点为根的左右⼦树⾼度差不能超过1,因为有这个特性限制,所以在创建平衡⼆叉树的时候如果发现这个平衡被打破了,需要对树进⾏旋转操作,以恢复其平衡的性质,具体的旋转有以下⼏种情况:1、LL类型旋转(单向向右):这种情况下是某个节点的左孩⼦的左⼦树导致该节点失衡,需要对该节点进⾏向右旋转,如下图:如上图,值为3的节点,当它只有⼀个左孩⼦2时,此时左右孩⼦的⾼度差是1,当再插⼊1时,它的左右孩⼦的⾼度差变成了2,需要对其进⾏右旋:LL_Rotate(node): leftNode=node.left;//待旋转节点的左孩⼦ leftRightNode=leftNode;//待旋转节点的左孩⼦的右孩⼦ leftNode.right=node;//更新左孩⼦节点,将⾃⼰作为作为左孩⼦的右节点,即上图中3变成了2的右孩⼦ node.left=leftRightNode;//更新⾃⼰的左孩⼦, node.height=max(node.left.height,node.right.height)+1;//更新⾼度 leftNode.height=max(leftNode.left.height,leftNode.right.height)+1;//跟新新的根节点⾼度,需要先更新node节点... return leftNode;//返回左孩⼦替代⾃⼰的位置,⽐如上图中,2替代了3的位置2、RR类型旋转(单向向左):这种情况下是某个节点的右孩⼦的右⼦树导致该节点失衡,需要对该节点进⾏向左旋转,如下图:如上图,因为3的插⼊,根节点1的平衡因⼦变成2,需要对1进⾏左旋,⽅向与LL完全相反:RR_Rotate(node): rightNode=node.right;//获取右孩⼦ rightLeftNode=rightNode.left;//获取右孩⼦的左孩⼦ rightNode.left=node;//更新右孩⼦ node.right=rightLeftNode; node.height=max(node.left.height,node.right.height)+1; rightNode.height=max(rightNode.left.height,right.right.height)+1; return rightNode;//返回3、LR类型旋转(先左后右):这种情况下是某个节点的左孩⼦的右⼦树导致该节点失衡,需要对该节点的左孩⼦进⾏左旋,然后再对其进⾏右旋,如下图:如上图,节点值为8的节点的左孩⼦,因为6的插⼊,导致8节点失衡,需要先对左孩⼦4进⾏左旋,由6替代4的位置,再对8进⾏右旋,由6替代8:Left_Right_Rotate(node): node.left=LL_Rotate(node.left);//对左孩⼦左旋 return RR_Rotate(node);//对⾃⼰进⾏右旋4、RL类型旋转(先右后左):这种情况下是某个节点的右孩⼦的左⼦树导致该节点失衡,需要对该节点的右孩⼦进⾏右旋,然后再对其进⾏左旋,如下图:如上图,4的平衡因⼦因为其右孩⼦7新增了⼀个左孩⼦节点6⽽打破,需要对节点7先右旋,再对4进⾏左旋,同LR完全相反,伪代码如下:Right_Left_Rotate(node): node.right=RR_Rotate(node.right);//对右孩⼦进⾏右旋 return LL_Rotate(node);//对⾃⾝进⾏左旋节点的⾼度的获取:Get_Height(node): if node==null: return 0; leftHeight=Get_Height(node.left); rightHeight=Get_Height(node.right); return max(leftHeight,rightHeight)+1;平衡因⼦的获取,某个节点的平衡因⼦是由左右⼦树的⾼度差决定的:Get_Factor(node): return Get_Height(node.left)-Get_Height(node.right);节点的平衡调整,涉及到左旋、右旋、左右旋转、右左旋转:balance(node): if node==null return null; //左⼦树导致不平衡 if getFactor(node)==2 : //左孩⼦的左⼦树导致不平衡 if getFactor(node.left)==1: node=LL_Rotate(node) else: //左孩⼦的右⼦树导致不平衡 node=Left_Right_Rotate(node); //右⼦树导致不平衡 else if getFactor(node)==-2: 右⼦树的右孩⼦导致不平衡 if getFactor(node.right)==-1: node=RR_Rotate(node); else //右孩⼦的左⼦树导致不平衡 node=Right_Left_Rotate(node); //返回旋转后的节点 return node;树的插⼊操作:insert_val(node,val): if node==null: return new Node(val); //这⾥是⼀个递归创建过程 if val<node.val: node.left=insert_val(node.left,val); node.left.parent=node; else node.right=insert_val(node.right,val); node.right.parent=node; //返回调整后的节点 return balance(node);树的删除操作,删除操作有点复杂,需要找到那个替代⾃⼰的节点,其⽅法就是寻找删除节点的左⼦树的最⼤值;如果待删除节点没有左⼦树,则需要寻找右⼦树的最⼩值,如果待删除的节点是叶⼦节点,则直接删除即可:delete_node(node,val): if node==null: return;//没有找到,直接返回 if val < node.val: delete_node(node.left,val); else if val > node.val: delete_node(node.right,val); else: //寻找到了⽬标节点 //⽬标节点是叶⼦节点 if node.left==null && node.right==null: parent=node.parent; //待删除的节点是根节点 if parent==null: root=null; else if parent.left==node: parent.left=null; else: //删除节点 parent.right=null; else if node.left!=null: left=node.left maxNode=left while left!=null: maxNode=right; left=left.right; node.val=maxNode.val delete_node(node.left,node.val); else: //与上⾯node.left!=null中的left相反,将left修改为right balance(node);//调节树的平衡以上AVL树的构建分析完毕,其中关键点为节点的平衡操作,创建和删除节点时使⽤到了递归操作,算是⼀个设计技巧,如下为完整的⽰例代码:package avl;import java.util.ArrayList;import java.util.List;/*** AVL 树的定义*/public class AVLTree {//根节点Node root=null;/*** 插⼊新值* @param val* @return*/public AVLTree insertVal(int val){if(root==null){root=new Node(val);}else{insertVal(root,val);}return this;* 节点的插⼊* @param node* @param val* @return*/private Node insertVal(Node node,int val){if(node==null){node=new Node(val);return node;}if(val<node.val){Node left=insertVal(node.left,val);node.left=left;left.parent=node;}else{Node right=insertVal(node.right,val);node.right=right;right.parent=node;}//调整节点node=balance(node);return node;}/*** 删除节点* @param val*/public void deleteVal(int val){deleteVal(root,val);}private void deleteVal(Node node,int val){//没有找到,直接返回if(node==null){return;}else if(val<node.val){deleteVal(node.left,val);balance(node);}else if(val>node.val){deleteVal(node.right,val);balance(node);}else{//叶⼦节点,直接删除if(node.left==null && node.right==null){Node parent=node.parent;if(parent==null){root=null;}if(parent.left==node){parent.left=null;}else{parent.right=null;}}else{//如果左⼦树不为空,寻找其最⼤的后继节点if(node.left!=null){Node left=node.left;Node maxNode=left;//注意这⾥是怎么找最⼤的后继节点的while(left!=null){maxNode=left;left=left.right;}node.val=maxNode.val;deleteVal(node.left,maxNode.val);balance(node);}else{Node right=node.right;Node maxNode=right;while(right!=null){maxNode=right;right=right.left;}node.val=maxNode.val;deleteVal(node.right,maxNode.val);balance(node);}}}* 平衡节点的操作动作* @param node* @return*/private Node balance(Node node){if(node==null){return null;}if(getFactor(node)==2){if(getFactor(node.left)==1){node= LL_Rotate(node);}else{node= LR_Rotate(node);}}else if(getFactor(node)==-2){if(getFactor(node.right)==-1){node= RR_Rotate(node);}else{node= RL_Rotate(node);}}return node;}/*** 获取节点的⾼度* @param node* @return*/private int getHeight(Node node){if(node==null){return0;}int left=getHeight(node.left);int right=getHeight(node.right);int max=Math.max(left,right);return max+1;}/*** 获取节点的平衡因⼦* @param node* @return*/private int getFactor(Node node){if(node==null){return0;}return getHeight(node.left)-getHeight(node.right); }/*** 先右后左* @param node* @return*/private Node RL_Rotate(Node node){Node right=LL_Rotate(node.right);node.right=right;right.parent=node;return RR_Rotate(node);}/*** 先左后右* @param node* @return*/private Node LR_Rotate(Node node){Node left=RR_Rotate(node.left);node.left=left;left.parent=node;return LL_Rotate(node);}/*** 单向左旋* @param node* @return*/private Node RR_Rotate(Node node){Node right=node.right,parent=node.parent; Node rightLeft=right.left;right.left=node;node.parent=right;node.right=rightLeft;if(rightLeft!=null){rightLeft.parent=node;}right.parent=parent;if(parent!=null){if(parent.left==node){parent.left=right;}else{parent.right=right;}}else{root=right;}return right;}/*** 单向右旋* @param node* @return*/private Node LL_Rotate(Node node){Node left=node.left,parent=node.parent; Node leftRight=left.right;left.right=node;node.parent=left;node.left=leftRight;if(leftRight!=null){leftRight.parent=node;}left.parent=parent;if(parent!=null){if(parent.left==node){parent.left=left;}else{parent.right=left;}}else{root=left;}return left;}/*** 先序遍历* @param node*/public void preOrder(Node node){if(node!=null){System.out.print(node);preOrder(node.left);preOrder(node.right);}}/*** 中序遍历* @param node*/public void inOrder(Node node){if(node!=null){inOrder(node.left);System.out.print(node);inOrder(node.right);}}/*** 后序遍历* @param node*/public void postOrder(Node node){if(node!=null){postOrder(node.left);postOrder(node.right);System.out.print(node);}}/*** 按层遍历树*/public void printByLevel(){System.out.println("=========================");List<Node> temp=new ArrayList<>();if(root!=null){temp.add(root);}while(temp.size()>0){List<Node> nodes=new ArrayList<>();temp.stream().forEach(obj-> {System.out.print(obj);if(obj.left!=null){nodes.add(obj.left);}if(obj.right!=null){nodes.add(obj.right);}});System.out.println();temp.clear();temp.addAll(nodes);}}public static void main(String[] args) {AVLTree tree=new AVLTree();tree.insertVal(1).insertVal(2).insertVal(3).insertVal(4).insertVal(5).insertVal(7).insertVal(6); tree.printByLevel();tree.deleteVal(6);tree.printByLevel();tree.deleteVal(4);tree.printByLevel();}}class Node{public int val;public Node left,right,parent;public Node(int val){this.val=val;}@Overridepublic String toString() {return val+"";}}View Code。
急求数据结构-平衡二叉树课程设计

急求数据结构-平衡二叉树课程设计平衡二叉树课程设计
一、什么是平衡二叉树平衡二叉树(Balanced Binary Tree),又称AVL树,是一种特殊的二叉查找树,它的每个
节点的两个子树的高度最大差别为
1,平衡二叉树的搜索、插入和删除操作只需要O(logn)的时间复杂度,而普通的二叉查找树则需要O(n)的时间复杂度。
二、平衡二叉树的特点
1、平衡二叉树的每个节点的左右子树的高度差不超过1;
2、平衡二叉树的搜索、插入和删除操作只需要O(logn)的时间复杂度;
3、平衡二叉树的高度可以保持在log2n的高度;
4、平衡二叉树可以用来建立字典和查找表,以及其他应用;
5、平衡二叉树可以用来存储已经排序的数据,以提高搜
索效率。
三、平衡二叉树的实现
1、插入操作插入新节点的操作可以分为两步:首先,将新节点插入到树中,其次,进行调整,使树保持平衡。
2、删除操作删除节点的操作可以分为三步:首先,将要删除的节点从树中移除,其次,找到要删除节点的子节点,最后,将子节点插入到树中,以保证树的平衡性。
3、查找操作查找操作是在平衡二叉树中最常见的操作,它可以在O(logn)的时间内找到目标节点。
四、平衡二叉树课程设计
1、首先,学生需要研究二叉树的基本概念,以及普通二叉查找树的实现;
2、其次,学生需要了解平衡二叉树的概念、特点,并掌握它的实现方法;
3、然后,学生需要编写一个程序,来实现平衡二叉树的插入、删除和查找操作;
4、最后,学生需要编写一个测试程序,来验证程序的正确性。
平衡二叉树的公式

平衡二叉树的公式
平衡二叉树是一种基于AVL树的数据结构,它保证了每个节点的左右子树高度差不超过1。
这种平衡性保证了平衡二叉树的查找、插入和删除操作都能在O(log n)的时间内完成。
平衡二叉树的公式如下:
- 对于任意节点N,其左子树高度为hL,右子树高度为hR,则
该节点的平衡因子BF = hL - hR。
- 对于一棵平衡二叉树,其每个节点的平衡因子都应该在[-1, 0, 1]范围内。
- 在插入和删除节点时,需要对其所在路径上的所有节点重新计算平衡因子,并进行旋转操作。
- 旋转操作分为左旋和右旋两种,具体实现可参考AVL树的旋转操作。
平衡二叉树是一种非常重要的数据结构,在实际应用中广泛使用。
了解平衡二叉树的公式和实现原理,对于提高程序性能和减少BUG都有很大的帮助。
- 1 -。
平衡二叉树旋转例题

平衡二叉树旋转例题(最新版)目录I.平衡二叉树的概念及特点II.平衡二叉树旋转的定义和类型III.平衡二叉树旋转的实例解析IV.平衡二叉树旋转的意义和应用正文I.平衡二叉树的概念及特点平衡二叉树(Balanced Binary Tree)是一种特殊的二叉树结构,具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
平衡二叉树的主要特点是保持树的左右两个子树的高度平衡,这样可以确保在插入、删除和查找操作中,树的高度不会发生显著变化,从而保证树的效率。
II.平衡二叉树旋转的定义和类型平衡二叉树旋转是指在平衡二叉树中,将某个节点作为旋转中心,将其左右子树进行旋转操作,以达到恢复平衡的目的。
平衡二叉树旋转有两种类型:左旋和右旋。
左旋是指将节点的右子树旋转到该节点的左子树上,右旋则相反,将节点的左子树旋转到右子树上。
III.平衡二叉树旋转的实例解析假设有一棵平衡二叉树,其节点存储的值依次为 3、4、2、1、7、6。
现在,将节点 4 作为旋转中心进行左旋,得到的新二叉树如下:4/2 7/1 6左旋后,节点 4 的左子树高度增加了 1,右子树高度减少了 1,树的平衡得到了恢复。
类似地,若将节点 2 作为旋转中心进行右旋,得到的新二叉树如下:2/1 6/4 7右旋后,节点 2 的左子树高度减少了 1,右子树高度增加了 1,树的平衡得到了恢复。
IV.平衡二叉树旋转的意义和应用平衡二叉树旋转在平衡二叉树的维护和操作中具有重要意义。
通过旋转操作,可以在插入、删除和查找过程中调整树的结构,保持树的平衡。
平衡二叉树旋转在实际应用中广泛使用,例如在数据库系统中,通过平衡二叉树旋转可以提高搜索效率;在文件系统中,利用平衡二叉树旋转可以实现文件的快速存储和检索。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
4. 二叉平衡树
这是另一种形式的二叉查找树,其特点为左、右子树深度之差的绝对值不大于1,称有这种特性的二叉树为平衡树。
构造二叉平衡(查找)树的方法:在插入过程中采用平衡旋转技术.
平衡树的查找性能分析:
在平衡树上进行查找的过程和二叉排序树相同,因此,查找过程中和给定值进行比较的关键字的个数不超过平衡树的深度。
假设深度为h的二叉平衡树上所含结点数的最小值为N h,则显然 N h = N h-1 + N h-2 + 1 由此可以推导出:h≈log2(n),因此,在平衡树上进行查找的时间复杂度为O(log2(n))。
5. B_-树
(1).B_ 树的定义
B_ 树是一种平衡的多路查找树, 在m阶的B_ 树上,每个非终端结点可能含有:
n个关键字K i(1≤i≤n) n<m
n个指向记录的指针D i(1≤i≤n)
n+1个指向子树的指针A i(0≤i≤n);
∙非叶结点中的多个关键字均自小至大有序排列,即:K1< K2< … < K n;且A i-1所指子树上所有关键字均小于K i;A i所指子树上所有关键字均大于K i;
∙树中所有叶子结点均不带信息,且在树中的同一层次上;根结点或为叶子结点,或至少有两棵子树;其余非叶结点至少有棵子树,至多有m棵子树。
B-树结构的C语言描述如下:
#define m 3 // B树的阶,暂设为3
typedef struct BTNode {
int keynum; // 结点中关键字个数,即结点的大小
struct BTNode *parent; // 指向双亲结点的指针
KeyType key[m+1]; // 关键字(0号单元不用)
struct BTNode *ptr[m+1]; // 子树指针向量
Record *recptr[m+1]; // 记录指针向量
} BTNode, *BTree; // B树结点和B树的类型
(2) 查找过程
从根结点出发,沿指针搜索结点和在结点内进行顺序(或折半)查找两个过程交叉进行。
若查找成功,则返回指向被查关键字所在结点的指针和关键字在结点中的位置;
若查找不成功,则返回插入位置。
假设返回的是如下所述结构的记录:
typedef struct {
BTNode *pt; // 指向找到的结点
int i; // 1..m,在结点中的关键字序号
int tag; // 1:查找成功,0:查找失败
} Result; // 在B树的查找结果类型
则下列算法简要地描述了B树的查找操作的实现。
Result SearchBTree(BTree T, KeyType K) { // 在m阶B树T上查找关键字K,返回结果(pt,i,tag)
p=T; q=NULL; found=FALSE; i=0; // 初始化,p指向待查结点,q指向p的双亲
while (p && !found) {
n=p->keynum; i=Search(p, K); // 在p->key[1..keynum]中查找 i ,
//p->key[i]<=K<p->key[i+1]
if (i>0 && p->key[i]==K) found=TRUE; //找到待查关键字
else { q=p; p=p->ptr[i]; }
}
if (found) return (p,i,1); // 查找成功
else return (q,i,0);// 查找不成功,返回K的插入位置信息
} // SearchBTree
(3) 插入
在查找不成功之后,需进行插入。
关键字插入的位置必定在最下层的非叶结点,有下列几种情况:
1)插入后,该结点的关键字个数n<m,不修改指针;
2)插入后,该结点的关键字个数n=m,则需进行“结点分裂”,令s =,在原结点中保留(A0,K1,…,Ks-1,As-1);建新结点(As,Ks+1,…,Kn,An);
将(Ks,p)插入双亲结点;
3)若双亲为空,则建新的根结点。
Status InsertBTree(BTree &T, KeyType K,BTree q, int i ) {
// 在m阶B树T上结点*q的key[i]与key[i+1]之间插入关键字K。
若引起结点过大,则沿
// 双亲链进行必要的结点分裂调整,使T仍是m阶B树。
x = K; ap = NULL; finished = FALSE;
while (q && !finished) {
Insert(q, i, x, ap); // 将x和ap分别插入到q->key[i+1]和q->ptr[i+1]
if (q->keynum < m) finished=TRUE; // 插入完成
else {// 分裂结点*q
s= ; split(q, aq); x=q->key[s];
// 将q->key[s+1..m], q->ptr[s..m] 和q->recptr[s+1..m]移入新结点*ap
q=q->parent;
if (q) then i = Search(q, x); // 在双亲结点*q中查找x的插入位置
} // else
} // while
if (!finished) NewRoot(T, q, x, ap);
// 生成含信息(T,x,ap)的新的根结点*T,原T和ap为子树指针
} // InsertBTree
(4) 删除
和插入的考虑相反,首先必须找到待删关键字所在结点,并且要求删除之后,结点中关键字的个数不能小于 -1,否则,要从其左(或右)兄弟结点“借调”关键字,
若其左和右兄弟结点均无关键字可借(结点中只有最少量的关键字),则必须进行结点的“合并”
(5) 查找性能的分析
B-树的查找时间主要花费在搜索结点(访问外存)上,即主要取决于B-树的深度
问:含N个关键字的m阶B-树的深度H为多少?
先推导每一层所含最少结点数:
第1层 1
第2层 2
第3层 2
第4层 2( )2
第H+1层 2( )H-1
假设m阶B-树的深度为H+1,由于第H+1层为叶子结点,而因为树中含有N个关键字,则叶子结点必为N+1个,由此,
N+1≥2( )H-1
H-1≤
H≤
所以,在含N个关键字的B_树上进行一次查找,需访问的结点个数不超过
6. B+ 树
是B- 树的一种变型.
(1) B+ 树的结构特点
∙每个叶子结点中含有n个关键字和n个指向记录的指针;并且所有叶子结点彼此相链接构成一个有序链表,其头指针指向含最小关键字的结点;
∙每个非叶结点中的关键字K i即为其相应指针A i所指子树中关键字的最大值;
∙所有叶子结点都处在同一层次上,每个叶子结点中关键字的个数均介于和m之间
(2) 查找过程
和B-树的查找稍有不同:
∙在B+树上,既可以进行缩小范围的查找,也可以进行顺序查找;
∙在进行缩小范围的查找时,不管成功与否,都必须查到叶子结点才能结束;
若在结点内查找时,给定值≤K i,则应继续在A i所指子树中进行查找;
(3).插入和删除类似于B-树。