二查搜索树(Java)
/*****************搜索二叉树*********************/ //《算法导论》P161 /*构建一个有n个不同关键字的二查搜索树的期望高度为h = O(lgn); 下述所有查找等操作的时间复杂度为O(h) */ /******定义搜索二叉树*****/ //对于任一节点x,满足其左子树上的节点key都不大于x.key // 右子树上的节点key都不小于x.key private class SearchTree { int key; SearchTree parent; SearchTree left; SearchTree right; } /*********************查询*********************/ //递归实现 public SearchTree Search1(SearchTree TNode , int target) { if(TNode == null || target == TNode.key) { return TNode; } if(target > TNode.key) { return Search(TNode.right,target);//递归查询右子树 } else { return Search(TNode.left,target); } } //迭代实现(效率相对要高的多) public SearchTree Search(SearchTree TNode,int target) { while(TNode != null && target != TNode.key) { if(target > TNode.key) { TNode = TNode.right; } else { TNode = TNode.left; } } return TNode; } /******************查询最大最小关键字***************/ //最小关键字 public SearchTree MinTreeNode(SearchTree TNode) { while(TNode.left != null) { TNode = TNode.left; } return TNode; } //最小关键字 public SearchTree MaxTreeNode(SearchTree TNode) { while(TNode.right != null) { TNode = TNode.right; } return TNode; } /*****************查找后继和前驱******************/ /* 查找一个节点的后继 */ /*注意要分为两种情况:1.若该节点有右节点,则后继为其右节点的最左节点 2.若该节点无右子树,则应该回溯到期祖宗节点进行考虑 1)若节点为其父节点x.p的左子节点,则x.key小于x.p.key 2)若节点为父节点的右子节点,查找大于其key的后继依然 无法满足;故仍向上追溯直至某一节点z,使得x在其z左子树中。 */ public SearchTree TreeSuccessor(SearchTree XNode) { if(XNode.right != null) { return MinTreeNode(XNode.right);//即查找右子树的最小关键字 } SearchTree YNode = XNode.parent; while(YNode != null && XNode == YNode.right)//循环至根节点之前的NIL或者该节点为父节点的左子节点 { XNode = YNode; YNode = YNode.parent; } return YNode;//注意返回值 } /* 查找一个节点的前驱 */ /*类比于查找前驱的问题,1.当该节点有左子树,则前驱即为其左子树的最大关键字 2.若该节点只有右子树,则返回其祖宗节点考虑 直至找到该节点x为z的右子树中的节点,则z为x的前驱 */ public SearchTree TreePreDecessor(SearchTree XNode) { if(XNode.left != null) { return MaxTreeNode(XNode.left); } SearchTree YNode = XNode.parent; while(YNode != null && XNode == YNode.left) { XNode = YNode; YNode = YNode.left; } return YNode; } /*********************插入节点**********************/ /*注意搜索二叉树的特点,插入的节点最后一定成为了二叉树的叶子节点 通过不断比较x.key与节点y的key,确定节点x应该在y的左子树还是右子树 同时处理二叉树要时常注意根节点的特殊性,进行考虑 */ public void TreeInsert(SearchTree TRoot, SearchTree XNode) { SearchTree YNode = null; while(TRoot != null) { YNode = TRoot;//避免退出循环时TRoot为null,而无法进行访问 if(XNode.key > TRoot.key) { TRoot = TRoot.right; } else { TRoot = TRoot.left; } } XNode.parent = YNode; //注意根节点情况 if(YNode == null)//即TRoot=null,未进入循环 { TRoot = XNode; } //要判断XNode是左节点还是右节点 else if(XNode.key < YNode.key) { YNode.left = XNode; } else { YNode.right = XNode; } } /*********************删除节点*********************/ /*删除要考虑三种情况:(暂不考虑XNode不在树中的情况) 1.XNode为叶子节点,没有子孩子,则将其删除,并将其父节点对应孩子节点置为null即可 2.XNode有一个孩子节点YNode,无论是左右孩子,将YNode替代XNode即可 3.XNode有两个孩子节点时,要分为如下两种情况 1)XNode右孩子节点YNode无左子树 2)YNode有左子树: (x) (x) / \ / () (y) () (y) / \ / NIL () (m) 直接让YNode取代XNode即可 (n) 注意要查找XNode的后继MNode,即右子树的最左节点, 让后让MNode替代XNode,并注意让MNode的右子树替代MNode */ //替代辅助函数,注意这里面的替代仅是将VNode交换到UNode的位置,UNode本身并未作改变,后继也未继承 private void Transplant(SearchTree TRoot, SearchTree UNode, SearchTree VNode) { //考虑根节点的情况 if(UNode.parent == null) { TRoot = VNode; } else if(UNode == UNode.parent.left) { UNode.parent.left = VNode; } else { UNode.parent.right = VNode; } if(VNode != null) //注意此条件判断,null是无法设置各种状态的 { VNode.parent = UNode.parent; } } /**********************删除函数************************/ public void TreeDelete(SearchTree TRoot, SearchTree XNode) { //情况一 if(XNode.left == null && XNode.right == null) { XNode = null;//省去判断XNode是否为根节点 } //情况二 else if(XNode.left != null) { Transplant(TRoot,XNode,XNode.left); } else if(XNode.right != null) { Transplant(TRoot,XNode,XNode.right); } //情况三 else { SearchTree YNode = XNode.right; //情况3.1 if(YNode.left == null) { Transplant(TRoot,XNode,YNode); //交换之后注意设置子孩子 YNode.left = XNode.left; YNode.left.parent = YNode; } //情况3.2 else { SearchTree MNode = MinTreeNode(YNode); Transplant(TRoot,MNode,MNode.right);//用NNode替换MNode //注意MNode发生改变 MNode.right = XNode.right; MNode.right.parent = MNode;//要注意设置XNode孩子的节点的parent Transplant(TRoot,XNode,MNode); MNode.left = XNode.left; MNode.left.parent = MNode; } } }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。