二叉查找树中,最复杂的操作就是删除操作。对于叶子节点,直接删除即可。对于一颗子树的节点,用子树取代原节点即可。对于拥有两颗子树的节点,首先用右子树最小的节点取代源节点,再递归删除此最小节点。
具体代码如下所示:
- package com.Algorithm.Tree;
- import java.util.*;
- import java.io.*;
- /*
- * author:Tammy Pi
- * function:二叉查找树
- */
- public class BiSearchTree {
- public TreeNode root=null;
- private Scanner scanner=null;
- public BiSearchTree()
- {
- scanner=new Scanner(System.in);
- }
- public TreeNode getRoot() {
- return root;
- }
- public void setRoot(TreeNode root) {
- this.root = root;
- }
- public Scanner getScanner() {
- return scanner;
- }
- public void setScanner(Scanner scanner) {
- this.scanner = scanner;
- }
- public void createTree()
- {
- this.root=createTree(this.root);
- }
- public void midTraverse()
- {
- midTraverse(this.root);
- }
- //中序遍历,相当于排序
- public void midTraverse(TreeNode root)
- {
- if(root!=null)
- {
- midTraverse(root.getLchild());
- System.out.print(root.getData()+" ");
- midTraverse(root.getRchild());
- }
- }
- //建立二叉查找树
- public TreeNode createTree(TreeNode root)
- {
- String str=scanner.next();
- int n=Integer.parseInt(str);
- for(int i=0;i<n;i++)
- {
- String data=scanner.next();
- if(root==null)
- {
- root=new TreeNode(data);
- }
- else
- {
- TreeNode node=new TreeNode(data);
- TreeNode x=root,y=root;
- while(x!=null)
- {
- if(x.getData().compareTo(node.getData())>0)
- {
- y=x;
- x=x.getLchild();
- }
- else
- {
- y=x;
- x=x.getRchild();
- }
- }
- if(y.getData().compareTo(node.getData())>0)
- {
- y.setLchild(node);
- }
- else
- {
- y.setRchild(node);
- }
- }
- }//for i
- return root;
- }//createTree
- //查找最小的节点
- public TreeNode findMin(TreeNode node)
- {
- TreeNode x=node;
- while(node!=null)
- {
- x=node;
- node=node.getLchild();
- }
- return x;
- }
- public void testRemove()
- {
- root.setRchild(remove(root.getRchild(),root.getRchild()));
- System.out.print("删除节点后,中序遍历结果为:");
- midTraverse();
- }
- //删除节点
- //node为待删除节点
- public TreeNode remove(TreeNode node,TreeNode subTree)
- {
- if(subTree==null)
- {
- return null;
- }
- int state=node.getData().compareTo(subTree.getData());
- if(state<0)
- {
- node.setLchild(remove(node,subTree.getLchild()));
- }
- else if(state>0)
- {
- node.setRchild(remove(node,subTree.getRchild()));
- }
- else if(node.getLchild()!=null&&node.getRchild()!=null)
- {
- TreeNode temp=findMin(node.getRchild());
- node.setData(temp.getData());
- node.setRchild(remove(temp,node.getRchild()));
- }
- else
- {
- node=(node.getLchild()!=null?node.getLchild():node.getRchild());
- }
- return node;
- }
- //用于测试的主函数
- public static void main(String[] args)
- {
- BiSearchTree biTree=new BiSearchTree();
- biTree.createTree();
- System.out.println("查找二叉树建立完成!");
- System.out.print("中序遍历结果为:");
- biTree.midTraverse();
- System.out.println();
- biTree.testRemove();
- }
- }
在本练习中,我们讨论从二叉查找树删除节点问题。删除算法不像插入算法那么简单明了。删除一个值可能有三种不同的情况————该值包含在一个叶子节点中(没有子节点),该值包含在只有一个子节点中或者包含在两个子节点的节点中。 如果该项在叶节点中,直接删除该节点,将其父节点指向它的指针置为空。 如果该项包含在只含一个子节点的节点中,把父节点的指针指向它的子节点再删除这个数据项,就是由它的子节点替代该节点的位置。最后一种情况是最难的。当要删除的节点含有2个子节点时,由另一个叶子节点代替它的位置 编写一个二叉树的成员函数deleteNode,以树的根节点指针和要删除的值为参数。该函数需要找到包含该值的节点,使用上面讨论的算法将该节点删除。该函数还要打印一条信息以表明该节点被删除。当删除完成后,使用中序、前序和后序遍历来确认该节点是否已被正确删除。 ///BinSTree.h// #pragma on #include <iostream> #include <stdio.h> using namespace std; class BinSTree; class TreeNode { public: friend class BinSTree; TreeNode(char item, TreeNode *lptr = NULL, TreeNode *rptr = NULL ):contents(item),left(lptr),right(rptr){ } private: char contents; //节点值 TreeNode *left; //左孩子 TreeNode *right; //右孩子 }; typedef TreeNode* LPTreeNode; class BinSTree { public: BinSTree(void); ~BinSTree(void); void CreatBinSTree(LPTreeNode &tree); //创建新树 void MiddleRead(TreeNode *t); //中序遍历 void FirstRead(TreeNode *t); //前序遍历 void LastRead(TreeNode *t); //后序遍历 void Find(TreeNode *tree,char i); //查找是否存在值为i的节点 LPTreeNode Search(LPTreeNode &tree); // void DeleteNode(LPTreeNode &tree,char i); //删除值为i的节点 TreeNode *node; //根节点 private: bool tj; }; BinSTree.cpp/ #include "BinSTree.h" BinSTree::BinSTree(void) { tj=false; } BinSTree::~BinSTree(void) { } void BinSTree::CreatBinSTree(LPTreeNode &tree) { char c; scanf("%c",&c); //获得一个节点值 if(c==' ') { tree = NULL; } else { tree = new TreeNode(c); //生成一个新节点 CreatBinSTree(tree->left); //生成左子树 CreatBinSTree(tree->right); //生成右子树 } } void BinSTree::MiddleRead(TreeNode *t) { if(node == NULL) { cout<<"空树,无法遍历!"<<endl; return; } if(t!=NULL) { MiddleRead(t->left); cout<<t->contents<<" "; MiddleRead(t->right); } } void BinSTree::FirstRead(TreeNode *t) { if(node == NULL) { cout<<"空树,无法遍历!"<<endl; return; } if(t!=NULL) { cout<<t->contents<<" "; MiddleRead(t->left); MiddleRead(t->right); } } void BinSTree::LastRead(TreeNode *t) { if(node == NULL) { cout<<"空树,无法遍历!"<<endl; return; } if(t!=NULL) { MiddleRead(t->left); MiddleRead(t->right); cout<<t->contents<<" "; } } void BinSTree::Find(TreeNode *tree,char i) { if(tree!=NULL) { if(tree->contents==i) { tj=true; return; } if(tree->left!=NULL) { if(tree->left->contents == i) { tj=true; return; } } if(tree->right!=NULL) { if(tree->right->contents == i) { tj=true; return; } } Find(tree->left,i); Find(tree->right,i); } } LPTreeNode BinSTree::Search(LPTreeNode &tree) { if(tree!=NULL) { if(tree->left->left==NULL && tree->left->right==NULL) { return tree->left; } else if(tree->right->left==NULL && tree->right->right==NULL) { return tree->right; } return Search(tree->left); return Search(tree->right); } void BinSTree::DeleteNode(LPTreeNode &tree,char i)
总体思想:分多种情况讨论
1.被删除节点没有子树的情况,直接删除,并修改对应父节点的指针为空。 2.对于只有一个子树的情况,考虑将其子树作为其父节点的子树,关于是左还是右,根据被删除的节点确定。 3.最复杂的是有两个子数的情况,可以考虑两种方法,都是同样的思想:用被删除节点A的左子树的最右节点或者A的右子树的最左节点作为替代A的节点,并修改相应的最左或最右节点的父节点的指针,修改方法类似2 ,不做细致讨论
/*************二叉树的节点的删除***********/ /*********该程序描述了从递归建立二叉树到查找*********/ #define Maxsize 16 //定义二叉树节点 //递归建立二叉树 /********查找二叉树的节点********/ /********第二种查找方法,记录其父节点的值********/ parent=point; while(point!=NULL) } } } /**********删除二叉树节点的操作***********/
case 1 :point=parent->right;break; case 0 :point=parent;break; if(point->left==NULL&&point->right==NULL) free(point); if(point->left==NULL&&point->right!=NULL) free(point); if(point->left!=NULL&& point->right!=NULL) free(child); } /*********中序遍历二叉树*************/ /*********主程序测试函数***********/ int nodelist[16]={0,5,4,6,2,0,0,8,1,3,0,0,0,0,7,9}; root=create_btree(nodelist,1); printf("/n the original tree is"); printf("Input the value of the number /n"); root=deletenode(root,test);
|