java 二叉树查找算法 三层二叉树算法?
三层二叉树算法?二叉树的每个节点最多有两个子树(没有度数大于2的节点),二叉树的子树分左右,顺序不能颠倒。二叉树的I层最多有1个2^(i节点;深度为k的二叉树最多有1个2^k节点;对于任意二叉树T,如
三层二叉树算法?
二叉树的每个节点最多有两个子树(没有度数大于2的节点),二叉树的子树分左右,顺序不能颠倒。二叉树的I层最多有1个2^(i节点;深度为k的二叉树最多有1个2^k节点;对于任意二叉树T,如果终端节点数为n0,度为2的节点数为n2,则n0 ^ N2 ^ 1。二叉树算法常用来实现二叉查找树和二叉堆。
如何在Java中实现二叉搜索树?
二分搜索法树木必须符合以下四个条件:
如果任一节点的左子树不为空,则左子树上所有节点的值都小于其根节点的值;如果任一节点的右子树不为空,则右子树上所有节点的值都大于其根节点的值;任一节点的左右子树也分别是二分搜索法树;没有键值相等的节点。二叉查找树的例子:
图1
接下来,将基于图1来介绍二叉查找树的相关操作。
首先,应该有一个与节点对象相关的类,名为Node。
1类Node { 2 int key 3 int value 4 Node left child 5 Node right child 6 7 public Node(int key,int value){ 8 key 9 value 10 } 1112 publicvoid display Node(){ 1314 } 15 } Node类包含键值,用于确定节点在树中的对应位置。value value表示要存储的内容,它还包含对左右两个子节点的两个引用。
接下来,在搜索树中查看相应的类:
1类树{2节点根//保存树的根3 4公共节点find(int key) {//查找指定节点5 6} 7 8公共void insert(int key,Int value) {//插入节点9 10} 11 12公共Boolean Delete(Int key){//删除指定节点13 14} 15 16私有节点getdirectpostnode(Node delnode){//获取要删除的节点的直接后继:17 18} 19 20公共void preorder(节点根节点){//遍历树RootNode) {//中遍历树25 26 } 27 28 public void post order(node根节点){//post遍历树29 30 }31}类表示树的框架,包括相应的查找、插入、遍历、删除的方法,其中删除节点是最复杂的操作,将一一介绍。
首先,找到一个节点
由于二叉查找树定义的特殊性,我们只需要根据输入的键值从根进行比较。如果小于根的键值,则与根的左子树进行比较,如果大于根,则与根的右子树进行比较,以此类推。如果找到,则返回相应的节点,否则返回null。
1公共节点find(int key) { 2节点current Node root 3 while(current Node!空ampamp!key){ 4 if(key lt){ 5 currentnodecurrentnode . left child 6 } else { 7 currentnodecurrentnode . right child 8 } 9 } 10 Return currentnode 11 }其次,插入节点。
与查找操作类似,由于二叉查找树的特殊性,需要从根节点开始比较要插入的节点。如果小于根节点,则与根节点的左子树进行比较,反之亦然,直到左子树为空或者右子树为空,再插入到相应的空位置。在比较过程中,要注意保存父节点的信息,以及要插入的位置是父节点的左子树还是右子树,然后再插入到正确的位置。
1 public void insert(int key,int value){ 2 if(root null){ 3 root new Node(key,value)4 return 5 } 6 Node current Node root 7 Node parent Node root 8 boolean is left child true 9 while(current Node!null){ 10 parent node current node 11 if(key lt){ 12 current node current node . left child 13 is left child true 14 } else { 15 current node current node . right child 16 is left child false 17 } 18 } 19 Node new Node new Node(key,value)20 if(is left child){ 21 parent Node . left child new Node 22 } else { 23 parent Node . right child new Node 24 } 25 }
第三,穿越二叉查找树
遍历操作和普通二叉树的遍历完全一样,所以我赢了 不要重复。
1 public void preOrder(Node root Node){ 2 if(root Node!null){ 3()4 preOrder(root Node . left child)5 preOrder(root Node . right child)6 } 7 } 8 9 public void in order(Node root Node){ 10 if(root Node!null){ 11 in order(root Node . left child)12()13 in order(root Node . right child)14 } 15 } 16 17 public void post order(Node root Node){ 18 if(root Node!null){ 19 post order(root node . left child)20 post order(root node . right child)21()22 } 23 }
第四,删除指定的节点。
在二叉查找树中删除节点很复杂,可以分为以下三种情况。
1.要删除的节点是叶节点,可以直接删除。
public Boolean Delete(int key){ Node当前节点根//用于保存要删除的节点Node parentNode根//用于保存父节点Boolean islefchild true//用于确定要删除的节点是左子节点还是右子节点while (currentNode!空ampamp!key){ parent node current node if(key lt){ current node current node . left child is left child true } eLSE { current node current node . right child is left child false } } If(current node null){ return false } If(当前节点。leftchild空amp amp当前节点。right child null){//要删除的节点是叶节点if(当前节点根)root null else if(是leftchild)。parent node . left child null else parent node . right child null }......}
2.要删除的节点只有一个子节点。
例如,要删除图1中键值为11的节点,只需要将键值为13的节点的左子节点指向键值为12的节点,就可以删除键值为11的节点。
从上面的分析中得到的代码如下(省略了上面提到的delete方法之后):
1 else if(当前节点。right child null){//唯一要删除的节点是左子2 if(当前节点根)3根当前节点。Leftchild4 else if(是Leftchild)。5 parent node . left child current node . left child 6 else 7 parent node . right child current node . left child 8 } else if(current node . left child null){//仅右子9 if(当前节点根)10根当前节点。Rightchild 11 else if(是leftchild) 12父节点。Leftchchild当前节点。Rightchild 13 else 14父节点。Rightchild当前节点。Rightchild 15}将被删除。......
3.要删除的节点有左右两个子节点。
例如,如果您删除图1中键值为10的节点,您需要使用键值为10的节点。序数后继节点(节点11)替换键值为10的节点,并删除键值为10的节点的序数后继节点。根据序数遍历的相关规则,键值为10的节点的直接序数后继节点必然是其右子树中键值最小的节点,所以这个序数后继节点必然不包含子节点或者只包含一个右子节点,删除这个序数后继节点属于上面1和2中提到的情况。在图1中,键值为10的节点的直接中间顺序后继节点是11,节点11包含一个右子节点12。
因此,删除图1中键值为10的节点分为以下几个步骤:
A.找到键值为10的节点的直接中间后继节点(即其右子树中值最小的节点11),删除这个直接中间后继节点。
1 private nodegetdirectpostnode(nodedelnode){//方法用于获取要删除的节点的直接后继节点。2 3节点parentNode delNode//用于保存待删除节点的直接后继节点的父节点,4节点direcrPostNode delNode///用于保存待删除节点的直接后继节点,5节点当前节点del Node。右子6 While(当前节点!null){ 7 parent node direcrPostNode 8 direcrPostNode current node 9 current node current node . left child 10 } 11 if(direcrPostNode!DelNode.rightChild) {//从树中删除此直接后继节点:12parentnode。LeftchildDirecPostnode。RightChild13dDirecPostnode。right child null 14 } 15 Return DirecPostnode//返回直接后继节点16 17} b并将该后继节点的键值赋给要删除的节点的键值。(在情况2中的省略号代码之后)
1 else {//要删除的节点既有左右子节点。2 3 //思路:将待删除节点的值替换为待删除节点右子树中键值最小的节点的值,然后删除右子树中键值最小的节点。4 //右边子树中键最小的节点不能包含左边的子树,所以删除具有最小键的节点必须属于叶节点或只有右子树的节点,5节点DirectPostNode GetDirectPostNode(当前节点)6 9}
至此,删除指定节点的操作结束。
最后给出了完整代码、简单测试代码和测试结果:
1类节点{ 2 int key 3 int value 4 Node left child 5 Node right child 6 7 public Node(int key,int value){ 8 key 9 value 10 } 11 12 public void display Node(){ 13 14 } 15 } 16 17类树{ 18 Node root 19 20 public Node find(int key){ 21 Node current Node root 22 while(current Node!空ampamp!key){ 23 if(key lt){ 24 current Node current Node . left child 25 } else { 26 current Node current Node . right child 27 } 28 } 29 return current Node 30 } 31 32 public void insert(int key,int value){ 33 if(root null){ 34 root new Node(key,value)35 return 36 } 37 Node current Node root 38 Node parent Node root 39 boolean is left child true 40 while(current Node!null){ 41 parent Node current Node 42 if(key lt){ 43 current Node current Node . left child 44 is left child true 45 } else { 46 current Node current Node . right child 47 is left child false 48 } 49 } 50 Node newNode新节点(key,value)51 if(is left child){ 52 parent Node . left child new Node 53 } else { 54 parent Node . right child new Node 55 } 56 } 57 58 public boolean delete(int key){ 59 Node current Node root 60 Node parent Node root 61 boolean is left child true 62 while(current Node!空ampamp!key){ 63 parent node current node 64 if(key lt){ 65 current node current node . left child 66 is left child true 67 } else { 68 current node current node . right child 69 is left child false 70 } 71 } 72 if(current node null){ 73 return false 74 } 75 if(当前节点。leftchild空amp amp当前节点。right child null){ 76//要删除的节点是叶节点77 if (currentNode root)。78根null 79 else if(islefchild)80 parent node . left child null 81 else 82 parent node . right child null 83 } else if(current node . right child null){//唯一要删除的节点是左孩子84 if(当前节点根)85根当前节点。Leftchild86 else if(是Leftchild)。87 parent node . left child current node . left child 88 else 89 parent node . right child current node . left child 90 } else if(cUrrentNode.leftChild null) {//唯一要删除的节点是右子91 if(当前节点根)92根当前节点。Rightchild 93 else if(是leftchild)。94 parentnode。leftchild当前节点。rightchild 95 else 96 parentnode。rightchild当前节点。right child 97 } else {//要删除的节点有左右两个子节点98 //思路:用要删除的节点的右子树中键值最小的节点的值替换要删除的节点的值,然后删除右子树中键值最小的节点。//右边子树中键最小的节点不能包含左边子树。所以键最小的节点一定属于叶节点或者只有右子树的节点100节点DirectPostNode GetDirectPostNode(当前节点)101} 104返回True 105 } 106 107私有节点GetDirectPostNode(Node Delnode){//方法用于获取直接后继节点108 109节点parentNode delNode//父节点110node direcpstnodedelnode用于保存待删除节点的直接后继节点//直接后继节点110nnull){ 113 parent node direcrPostNode 114 direcrPostNode current node 115 current node current node . left child 116 } 117 if(direcrPostNode!DelNode.rightChild) {//从树中删除这个直接后继节点118。Leftchild DirecPostnode。Rightchild 119 DirecPostnode。right child null 120 } 121 Return DirecPostnode//返回此直接后继节点122 123 }124。125 public void preOrder(Node root Node){ 126 if(root Node!null){ 127()128 preOrder(root Node . left child)129 preOrder(root Node . right child)130 } 131 } 132 133 public void in order(Node root Node){ 134 if(root Node!null){ 135 in order(root Node . left child)136 (k:·valu:)137 in order(root Node . right child)138 } 139 } 140 141 public void post order(Node root Node){ 142 if(root Node!null){ 143 post order(rootnode . left child)144 post order(rootnode . right child)145()146 } 147 } private void destroy(Node tree){ if(tree null)return if(tree . left!null)销毁(tree.leftChild) if (tree.right!null)destroy(tree . right child)tree null } public void destory(){ destory(root)} 148 } 149 public class binarysearchtreeapp { 150 public static void main(string[]args){ 151 tree tree new tree()152(6,6)//insert操作,二叉树153 (3,3) 154 (14,14) 155 (16,16) 156 (10,10) 157 (9,9) 15811) 160 (12,12) 161 162(删除前的遍历结果)163 ()//中间遍历操作164 165(删除节点10后的遍历结果)166 (10)//删除操作167 () 168} 169}测试结果: