二叉树删除结点

这篇博客探讨了两种删除非叶子节点的方法在二叉树中的实现。方法一是直接删除结点,而方法二是通过替换操作来删除结点。通过示例代码展示了如何在前序、中序和后序遍历中应用这些方法,并在删除节点后重新进行遍历,以验证删除操作的正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

方法一(delNode):若为非叶子结点将此结点的树直接删除(代码163行)

方法二(delNode1):若为非叶子结点(代码188行)
            若只有一个子结点,让该子节点代替结点
            若结点为a,左子结点为b,右子接点为c,让b结点代表a

package tree;

public class BinaryTreeAPP {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		HeroNode root=new HeroNode(1, "宋江");
		HeroNode node1=new HeroNode(2, "吴用");
		HeroNode node2=new HeroNode(3, "卢俊义");
		HeroNode node3=new HeroNode(4, "林冲");
		HeroNode node4=new HeroNode(5, "关胜");
		root.setLeft(node1);
		root.setRight(node2);
		node2.setRight(node3);
		node2.setLeft(node4);
		BinaryTree binaryTree=new BinaryTree(root);
		System.out.println("删除结点前:");
		System.out.println("前序排序");
		binaryTree.preOrder();
		System.out.println("中序排序");
		binaryTree.midOrder();
		System.out.println("后序排序");
		binaryTree.postOrder();
		binaryTree.delNode1(3);
		System.out.println("删除结点后:");
		System.out.println("前序排序");
		binaryTree.preOrder();
		System.out.println("中序排序");
		binaryTree.midOrder();
		System.out.println("后序排序");
		binaryTree.postOrder();
	}

}

//树
class BinaryTree{
	private HeroNode root;
	public BinaryTree(HeroNode root) {
		this.root=root;
	}
	
	//调用前序遍历
	public void preOrder() {
		if(root!=null) {
			root.preOrder();
		}else {
			System.out.println("根节点为空 ");
		}
	}
	
	//调用中序遍历
	public void midOrder() {
		if(root!=null) {
			root.midOrder();
		}else {
			System.out.println("根节点为空 ");
		}
	}
	
	//调用后序遍历
	public void postOrder() {
		if(root!=null) {
			root.postOrder();
		}else {
			System.out.println("根节点为空 ");
		}
	}
	
	//调用删除结点方法
	public void delNode(int no) {
		if(root!=null) {
			root.delNode(root, no);
		}else {
			System.out.println("根节点为空 ");
		}
	}
	
	//调用删除节点方法一
	public void delNode1(int no) {
		if(root!=null) {
			root.delNode1(root, no);
		}else {
			System.out.println("根节点为空 ");
		}
	}
	
}

//结点
//回溯遍历
class HeroNode{
	private int no;
	private String name;
	private HeroNode left;
	private HeroNode right;
	public HeroNode(int no,String name) {
		this.setNo(no);
		this.setName(name);
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public HeroNode getLeft() {
		return left;
	}
	public void setLeft(HeroNode left) {
		this.left = left;
	}
	public HeroNode getRight() {
		return right;
	}
	public void setRight(HeroNode right) {
		this.right = right;
	}
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public void show() {
		System.out.println("HeroNode [no="+no+",name="+name+"]");
	}
	
	//前序遍历
	public void preOrder() {
		this.show();
		if(this.left!=null) {
			this.left.preOrder();
		}
		if(this.right!=null) {
			this.right.preOrder();
		}
	}
	
	//中序遍历
	public void midOrder() {
		if(this.left!=null) {
			this.left.midOrder();
		}
		this.show();
		if(this.right!=null) {
			this.right.midOrder();
		}
	}
	
	//后序遍历
	public void postOrder() {
		if(this.left!=null) {
			this.left.postOrder();
		}
		if(this.right!=null) {
			this.right.postOrder();
		}
		this.show();
	}
	
	//删除结点(若为非叶子结点将此结点的树直接删除)
	public void delNode(HeroNode temp,int flag){
		if(temp.left!=null&&temp.left.no==flag){
			temp.left=null;
			return;
		}
		if(temp.right!=null&&temp.right.no==flag){
			temp.right=null;
			return;
		}
		if(temp.left!=null){
			delNode(temp.left,flag);
		}
		if(temp.right!=null){
			delNode(temp.right,flag);
		}

		System.out.println("未找到此结点");
	}



	//删除结点(若为非叶子结点)
	//若只有一个子结点,让该子节点代替结点
	//若结点为a,左子结点为b,右子接点为c,让b结点代表a
	//node:待删除结点的父节点
	public void delNode1(HeroNode node,int flag){
		if(node.left!=null&&node.left.no==flag){//匹配成功
			HeroNode temp=node.left;//temp承载被删除结点
			if(temp.left==null&&temp.right==null){//叶子结点
				node.left=null;//叶子节点直接删除
			}else if(temp.left!=null&&temp.right!=null){//两个子节点
				temp.left.right=temp.right;//将被删除结点的左子节点的右子节点指向被删除结点子节点的右子节点
				node.left=temp.left;//被删除结点的父节点的左子节点指向被删除节点的左子节点(被删除字节的左子节点取代被删除节点的位置)
			}else if(temp.left!=null&&temp.right==null){//右子结点为空
				node.left=temp.left;
			}else if(temp.right!=null&&temp.left==null){//左子结点为空
				node.left=temp.right;
			}
			return;
		}
		if(node.right!=null&&node.right.no==flag){//匹配成功
			HeroNode temp=node.right;
			if(temp.left==null&&temp.right==null){//叶子结点
				node.right=null;
			}else if(temp.left!=null&&temp.right!=null){//两个子节点
				node.right=temp.left;
				temp.left.left=temp.right;
			}else if(temp.left!=null&&temp.right==null){//右子结点为空
				node.right=temp.left;
			}else if(temp.right!=null&&temp.left==null){//左子结点为空
				node.right=temp.right;
			}
			return;
		}
		if(node.left!=null){
			delNode(node.left,flag);
		}
		if(node.right!=null){
			delNode(node.right,flag);
		}
		System.out.println("未找到该结点");
	}
}

删除前:

 

方法一: 

 

 

 方法二:

 

 

 

<think>我们参考引用[2]和引用[4]中关于二叉树节点删除的方法,特别是引用[2]详细描述了删除节点的三种情况,引用[4]提供了递归实现的代码。 删除节点需要考虑三种情况: 1. 被删除节点是叶子节点(无子节点):直接删除。 2. 被删除节点只有一个子节点:用其子节点替代。 3. 被删除节点有两个子节点:找到右子树的最小节点(或左子树的最大节点)的值复制到当前节点,然后删除那个最小(或最大)节点(此时该节点最多只有一个子节点,可转化为前两种情况)。 我们将实现一个非递归版本和一个递归版本的删除操作。假设我们的二叉树节点结构如下(参考引用[3]): ```cpp struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode() : val(0), left(nullptr), right(nullptr) {} TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} }; ``` 我们以二叉搜索树(BST)为例,因为二叉搜索树有明确的节点值大小关系,删除时需要保持BST的性质。 非递归删除方法步骤: 1. 首先找到要删除的节点及其父节点(因为需要修改父节点的指针)。 2. 根据节点的子节点情况处理: a. 无子节点:父节点指向该节点的指针置为nullptr。 b. 只有一个子节点:父节点指向该节点的指针指向该节点的子节点。 c. 有两个子节点:找到右子树的最小节点(或左子树的最大节点),记录其值,然后递归删除该最小节点,并将当前节点的值替换为最小节点的值。 递归删除方法(参考引用[4]): 使用递归可以避免显式记录父节点,通过引用传递节点指针。 我们分别实现这两种方法。 注意:在非递归方法中,如果要删除的是根节点,需要特殊处理(或者使用指向指针的指针)。 下面我们给出代码实现:</think>### C++二叉树节点删除实现详解 在二叉树删除节点需要处理三种情况,确保删除后仍保持树结构的完整性[^2]。以下是基于二叉搜索树(BST)的节点删除实现方法: #### 节点结构定义 ```cpp struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} }; ``` #### 删除操作实现 ```cpp TreeNode* deleteNode(TreeNode* root, int key) { if (!root) return nullptr; // 空树处理 // 1. 查找目标节点 if (key < root->val) { root->left = deleteNode(root->left, key); } else if (key > root->val) { root->right = deleteNode(root->right, key); } else { // 2. 找到目标节点后的删除逻辑 // 情况1: 无子节点或单子节点 if (!root->left) { TreeNode* temp = root->right; delete root; return temp; } else if (!root->right) { TreeNode* temp = root->left; delete root; return temp; } // 情况2: 双子节点(替换法) TreeNode* successor = root->right; while (successor->left) { successor = successor->left; // 找右子树最小节点 } root->val = successor->val; // 值替换 root->right = deleteNode(root->right, successor->val); // 删除后继节点 } return root; } ``` #### 关键处理逻辑 1. **叶子节点**:直接删除,父节点指针置空 ```cpp // 示例:删除节点5 parent->left = nullptr; // 或 parent->right delete node; ``` 2. **单子节点**:子节点替代被删节点位置 ```cpp // 示例:删除只有左子树的节点 parent->left = node->left; // 孙子变儿子 delete node; ``` 3. **双子节点**(核心难点): - 找到右子树最小节点(或左子树最大节点) - 复制其值到被删节点 - 递归删除该后继节点 ```cpp // 替换值后删除后继节点 node->val = successor->val; node->right = deleteNode(node->right, successor->val); ``` #### 时间复杂度分析 - 平均情况:$O(\log n)$(平衡二叉树) - 最坏情况:$O(n)$(退化成链表) #### 注意事项 1. 内存管理:删除后及时释放节点内存 2. 平衡性:频繁删除可能破坏BST平衡性,可考虑AVL/红黑树 3. 特殊处理:根节点删除需要更新树根指针 > 示例:删除节点6(双子节点情况) > 1. 找到右子树最小节点7 > 2. 将6的值替换为7 > 3. 在右子树中递归删除原节点7 > > 最终树结构保持二叉搜索树性质[^2][^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值