📌  相关文章
📜  删除二叉树中的最后一个叶子节点

📅  最后修改于: 2022-05-13 01:57:17.371000             🧑  作者: Mango

删除二叉树中的最后一个叶子节点

给定二叉树,任务是找到并删除最后一个叶节点。
叶节点是没有子节点的节点。最后一个叶节点将是在级别顺序遍历期间按顺序最后遍历的节点。问题陈述是识别这个最后访问的节点并删除这个特定的节点。
例子:

Input: 
Given Tree is: 
          6
       /     \
      5       4
    /   \       \
   1     2       5 

Level Order Traversal is: 6 5 4 1 2 5
Output: 
After deleting the last node (5),
the tree would look like as follows. 

          6
       /     \
      5       4
    /   \  
   1     2 
Level Order Traversal is: 6 5 4 1 2

Input: 
Given tree is: 
           1
        /     \
      3        10
    /   \     /   \
   2     15   4     5                        
        /                    
       1    
Level Order Traversal is: 1 3 10 2 15 4 5 1
Output: 
After deleting the last node (1),
the tree would look like as follows.

           1
        /     \
      3        10
    /   \     /   \
   2     15   4     5                        

Level Order Traversal is: 1 3 10 2 15 4 5

这个问题与删除值为 X 的叶节点略有不同,其中我们立即给出要删除的最后一个叶节点 (X) 的值,基于此我们执行检查并将父节点标记为空以将其删除。
这种方法将识别树的最后一层上的最后一个当前叶节点并将其删除。
方法1:遍历最后一级节点并跟踪Parent和遍历的节点。
这种方法将遍历每个节点,直到我们到达给定二叉树的最后一层。在遍历时,我们跟踪最后遍历的节点及其父节点。
完成遍历后,检查父级是否有右子级,如果有,将其设置为 NULL。如果否,将左指针设置为 NULL
下面是该方法的实现:

C++
// CPP implementation of the approach
#include 
using namespace std;
 
// Tree Node
class Node
{
public:
    int data;
    Node *left, *right;
 
    Node(int data) : data(data) {}
};
 
// Method to perform inorder traversal
void inorder(Node *root)
{
    if (root == NULL)
        return;
 
    inorder(root->left);
    cout << root->data << " ";
    inorder(root->right);
}
 
// To keep track of last processed
// nodes parent and node itself.
Node *lastNode, *parentOfLastNode;
 
// Method to get the height of the tree
int height(Node *root)
{
    if (root == NULL)
        return 0;
 
    int lheight = height(root->left) + 1;
    int rheight = height(root->right) + 1;
 
    return max(lheight, rheight);
}
 
// Method to keep track of parents
// of every node
void getLastNodeAndItsParent(Node *root, int level, Node *parent)
{
    if (root == NULL)
        return;
 
    // The last processed node in
    // Level Order Traversal has to
    // be the node to be deleted.
    // This will store the last
    // processed node and its parent.
    if (level == 1)
    {
        lastNode = root;
        parentOfLastNode = parent;
    }
    getLastNodeAndItsParent(root->left, level - 1, root);
    getLastNodeAndItsParent(root->right, level - 1, root);
}
 
// Method to delete last leaf node
void deleteLastNode(Node *root)
{
    int levelOfLastNode = height(root);
    getLastNodeAndItsParent(root, levelOfLastNode, NULL);
 
    if (lastNode and parentOfLastNode)
    {
        if (parentOfLastNode->right)
            parentOfLastNode->right = NULL;
        else
            parentOfLastNode->left = NULL;
    }
    else
        cout << "Empty Tree\n";
}
 
// Driver Code
int main()
{
    Node *root = new Node(6);
    root->left = new Node(5);
    root->right = new Node(4);
    root->left->left = new Node(1);
    root->left->right = new Node(2);
    root->right->right = new Node(5);
 
    cout << "Inorder traversal before deletion of last node :\n";
    inorder(root);
 
    deleteLastNode(root);
 
    cout << "\nInorder traversal after deletion of last node :\n";
    inorder(root);
 
    return 0;
}
 
// This code is contributed by
// sanjeev2552


Java
// Java Implementation of the approach
public class DeleteLastNode {
 
    // Tree Node
    static class Node {
 
        Node left, right;
        int data;
 
        Node(int data)
        {
            this.data = data;
        }
    }
 
    // Method to perform inorder traversal
    public void inorder(Node root)
    {
        if (root == null)
            return;
 
        inorder(root.left);
        System.out.print(root.data + " ");
        inorder(root.right);
    }
 
    // To keep track of last processed
    // nodes parent and node itself.
    public static Node lastNode;
    public static Node parentOfLastNode;
 
    // Method to get the height of the tree
    public int height(Node root)
    {
 
        if (root == null)
            return 0;
 
        int lheight = height(root.left) + 1;
        int rheight = height(root.right) + 1;
 
        return Math.max(lheight, rheight);
    }
 
    // Method to delete last leaf node
    public void deleteLastNode(Node root)
    {
 
        int levelOfLastNode = height(root);
 
        // Get all nodes at last level
        getLastNodeAndItsParent(root,
                                levelOfLastNode,
                                null);
 
        if (lastNode != null
            && parentOfLastNode != null) {
 
            if (parentOfLastNode.right != null)
                parentOfLastNode.right = null;
            else
                parentOfLastNode.left = null;
        }
        else
            System.out.println("Empty Tree");
    }
 
    // Method to keep track of parents
    // of every node
    public void getLastNodeAndItsParent(Node root,
                                        int level,
                                        Node parent)
    {
 
        if (root == null)
            return;
 
        // The last processed node in
        // Level Order Traversal has to
        // be the node to be deleted.
        // This will store the last
        // processed node and its parent.
        if (level == 1) {
            lastNode = root;
            parentOfLastNode = parent;
        }
        getLastNodeAndItsParent(root.left,
                                level - 1,
                                root);
        getLastNodeAndItsParent(root.right,
                                level - 1,
                                root);
    }
 
    // Driver Code
    public static void main(String[] args)
    {
 
        Node root = new Node(6);
        root.left = new Node(5);
        root.right = new Node(4);
        root.left.left = new Node(1);
        root.left.right = new Node(2);
        root.right.right = new Node(5);
 
        DeleteLastNode deleteLastNode = new DeleteLastNode();
 
        System.out.println("Inorder traversal "
                           + "before deletion "
                           + "of last node : ");
 
        deleteLastNode.inorder(root);
 
        deleteLastNode.deleteLastNode(root);
 
        System.out.println("\nInorder traversal "
                           + "after deletion of "
                           + "last node : ");
        deleteLastNode.inorder(root);
    }
}


C#
// C# implementation of the above approach
using System;
     
class GFG
{
 
    // Tree Node
    public class Node
    {
        public Node left, right;
        public int data;
 
        public Node(int data)
        {
            this.data = data;
        }
    }
 
    // Method to perform inorder traversal
    public void inorder(Node root)
    {
        if (root == null)
            return;
 
        inorder(root.left);
        Console.Write(root.data + " ");
        inorder(root.right);
    }
 
    // To keep track of last processed
    // nodes parent and node itself.
    public static Node lastNode;
    public static Node parentOfLastNode;
 
    // Method to get the height of the tree
    public int height(Node root)
    {
        if (root == null)
            return 0;
 
        int lheight = height(root.left) + 1;
        int rheight = height(root.right) + 1;
 
        return Math.Max(lheight, rheight);
    }
 
    // Method to delete last leaf node
    public void deleteLastNode(Node root)
    {
        int levelOfLastNode = height(root);
 
        // Get all nodes at last level
        getLastNodeAndItsParent(root,
                                levelOfLastNode,
                                null);
 
        if (lastNode != null &&
            parentOfLastNode != null)
        {
            if (parentOfLastNode.right != null)
                parentOfLastNode.right = null;
            else
                parentOfLastNode.left = null;
        }
        else
            Console.WriteLine("Empty Tree");
    }
 
    // Method to keep track of parents
    // of every node
    public void getLastNodeAndItsParent(Node root,
                                        int level,
                                        Node parent)
    {
        if (root == null)
            return;
 
        // The last processed node in
        // Level Order Traversal has to
        // be the node to be deleted.
        // This will store the last
        // processed node and its parent.
        if (level == 1)
        {
            lastNode = root;
            parentOfLastNode = parent;
        }
        getLastNodeAndItsParent(root.left,
                                level - 1,
                                root);
        getLastNodeAndItsParent(root.right,
                                level - 1,
                                root);
    }
 
    // Driver Code
    public static void Main(String[] args)
    {
        Node root = new Node(6);
        root.left = new Node(5);
        root.right = new Node(4);
        root.left.left = new Node(1);
        root.left.right = new Node(2);
        root.right.right = new Node(5);
 
        GFG deleteLastNode = new GFG();
 
        Console.WriteLine("Inorder traversal " +
                            "before deletion " +
                             "of last node : ");
 
        deleteLastNode.inorder(root);
 
        deleteLastNode.deleteLastNode(root);
 
        Console.WriteLine("\nInorder traversal " +
                            "after deletion of " +
                                  "last node : ");
        deleteLastNode.inorder(root);
    }
}
 
// This code is contributed by 29AjayKumar


Javascript


Java
// Java implementation
import java.util.LinkedList;
import java.util.Queue;
 
 
public class DeleteLastNode {
     
    // Tree Node
    static class Node {
 
        Node left, right;
        int data;
 
        Node(int data)
        {
            this.data = data;
        }
    }
 
    // Function to perform the inorder traversal of the tree
    public void inorder(Node root)
    {
        if (root == null)
            return;
 
        inorder(root.left);
        System.out.print(root.data + " ");
        inorder(root.right);
    }
 
    // To keep track of last
    // processed nodes parent
    // and node itself.
    public static Node lastLevelLevelOrder;
    public static Node parentOfLastNode;
 
    // Method to delete the last node
    // from the tree
    public void deleteLastNode(Node root)
    {
 
        // If tree is empty, it
        // would return without
        // any deletion
        if (root == null)
            return;
 
        // The queue would be needed
        // to maintain the level order
        // traversal of nodes
        Queue queue = new LinkedList<>();
 
        queue.offer(root);
 
        // The traversing would
        // continue until all
        // nodes are traversed once
        while (!queue.isEmpty()) {
 
            Node temp = queue.poll();
 
            // If there is left child
            if (temp.left != null) {
                queue.offer(temp.left);
 
                // For every traversed node,
                // we would check if it is a
                // leaf node by checking if
                // current node has children to it
                if (temp.left.left == null
                    && temp.left.right == null) {
 
                    // For every leaf node
                    // encountered, we would
                    // keep not of it as
                    // "Previously Visided Leaf node.
                    lastLevelLevelOrder = temp.left;
                    parentOfLastNode = temp;
                }
            }
 
            if (temp.right != null) {
                queue.offer(temp.right);
 
                if (temp.right.left == null
                    && temp.right.right == null) {
 
                    // For every leaf node
                    // encountered, we would
                    // keep not of it as
                    // "Previously Visided Leaf node.
                    lastLevelLevelOrder = temp.right;
                    parentOfLastNode = temp;
                }
            }
        }
 
        // Once out of above loop.
        // we would certainly have
        // last visited node, which
        // is to be deleted and its
        // parent node.
 
        if (lastLevelLevelOrder != null
            && parentOfLastNode != null) {
 
            // If last node is right child
            // of parent, make right node
            // of its parent as NULL or
            // make left node as NULL
            if (parentOfLastNode.right != null)
                parentOfLastNode.right = null;
            else
                parentOfLastNode.left = null;
        }
        else
            System.out.println("Empty Tree");
    }
 
    // Driver Code
    public static void main(String[] args)
    {
 
        Node root = new Node(6);
        root.left = new Node(5);
        root.right = new Node(4);
        root.left.left = new Node(1);
        root.left.right = new Node(2);
        root.right.right = new Node(5);
 
        DeleteLastNode deleteLastNode
            = new DeleteLastNode();
 
        System.out.println("Inorder traversal "
                           + "before deletion of "
                           + "last node : ");
        deleteLastNode.inorder(root);
 
        deleteLastNode.deleteLastNode(root);
 
        System.out.println("\nInorder traversal "
                           + "after deletion "
                           + "of last node : ");
 
        deleteLastNode.inorder(root);
    }
}


C#
// C# implementation of the approach
using System;
using System.Collections.Generic;
public class DeleteLastNode {
      
    // Tree Node
    public class Node {
  
        public Node left, right;
        public int data;
  
        public Node(int data)
        {
            this.data = data;
        }
    }
  
    // Function to perform the inorder traversal of the tree
    public void inorder(Node root)
    {
        if (root == null)
            return;
  
        inorder(root.left);
        Console.Write(root.data + " ");
        inorder(root.right);
    }
  
    // To keep track of last
    // processed nodes parent
    // and node itself.
    public static Node lastLevelLevelOrder;
    public static Node parentOfLastNode;
  
    // Method to delete the last node
    // from the tree
    public void deleteLastNode(Node root)
    {
  
        // If tree is empty, it
        // would return without
        // any deletion
        if (root == null)
            return;
  
        // The queue would be needed
        // to maintain the level order
        // traversal of nodes
        Queue queue = new Queue();
  
        queue.Enqueue(root);
  
        // The traversing would
        // continue until all
        // nodes are traversed once
        while (queue.Count!=0) {
  
            Node temp = queue.Dequeue();
  
            // If there is left child
            if (temp.left != null) {
                queue.Enqueue(temp.left);
  
                // For every traversed node,
                // we would check if it is a
                // leaf node by checking if
                // current node has children to it
                if (temp.left.left == null
                    && temp.left.right == null) {
  
                    // For every leaf node
                    // encountered, we would
                    // keep not of it as
                    // "Previously Visided Leaf node.
                    lastLevelLevelOrder = temp.left;
                    parentOfLastNode = temp;
                }
            }
  
            if (temp.right != null) {
                queue.Enqueue(temp.right);
  
                if (temp.right.left == null
                    && temp.right.right == null) {
  
                    // For every leaf node
                    // encountered, we would
                    // keep not of it as
                    // "Previously Visided Leaf node.
                    lastLevelLevelOrder = temp.right;
                    parentOfLastNode = temp;
                }
            }
        }
  
        // Once out of above loop.
        // we would certainly have
        // last visited node, which
        // is to be deleted and its
        // parent node.
  
        if (lastLevelLevelOrder != null
            && parentOfLastNode != null) {
  
            // If last node is right child
            // of parent, make right node
            // of its parent as NULL or
            // make left node as NULL
            if (parentOfLastNode.right != null)
                parentOfLastNode.right = null;
            else
                parentOfLastNode.left = null;
        }
        else
            Console.WriteLine("Empty Tree");
    }
  
    // Driver Code
    public static void Main(String[] args)
    {
  
        Node root = new Node(6);
        root.left = new Node(5);
        root.right = new Node(4);
        root.left.left = new Node(1);
        root.left.right = new Node(2);
        root.right.right = new Node(5);
  
        DeleteLastNode deleteLastNode
            = new DeleteLastNode();
  
        Console.WriteLine("Inorder traversal "
                           + "before deletion of "
                           + "last node : ");
        deleteLastNode.inorder(root);
  
        deleteLastNode.deleteLastNode(root);
  
        Console.WriteLine("\nInorder traversal "
                           + "after deletion "
                           + "of last node : ");
  
        deleteLastNode.inorder(root);
    }
}
 
// This code contributed by Rajput-Ji


输出:
Inorder traversal before deletion of last node : 
1 5 2 6 4 5 
Inorder traversal after deletion of last node : 
1 5 2 6 4

时间复杂度: O(N)
由于每个节点将被遍历一次,因此所花费的时间将与给定树中的节点数成线性关系。
方法2:使用队列在给定的二叉树上执行级别顺序遍历并跟踪父节点和最后遍历的节点。
这是实现上述方法 1 的一种非递归方式。我们使用队列执行级别顺序遍历,并跟踪每个访问的节点及其父节点。最后访问的节点将是要删除的最后一个节点。
下面是该方法的实现:

Java

// Java implementation
import java.util.LinkedList;
import java.util.Queue;
 
 
public class DeleteLastNode {
     
    // Tree Node
    static class Node {
 
        Node left, right;
        int data;
 
        Node(int data)
        {
            this.data = data;
        }
    }
 
    // Function to perform the inorder traversal of the tree
    public void inorder(Node root)
    {
        if (root == null)
            return;
 
        inorder(root.left);
        System.out.print(root.data + " ");
        inorder(root.right);
    }
 
    // To keep track of last
    // processed nodes parent
    // and node itself.
    public static Node lastLevelLevelOrder;
    public static Node parentOfLastNode;
 
    // Method to delete the last node
    // from the tree
    public void deleteLastNode(Node root)
    {
 
        // If tree is empty, it
        // would return without
        // any deletion
        if (root == null)
            return;
 
        // The queue would be needed
        // to maintain the level order
        // traversal of nodes
        Queue queue = new LinkedList<>();
 
        queue.offer(root);
 
        // The traversing would
        // continue until all
        // nodes are traversed once
        while (!queue.isEmpty()) {
 
            Node temp = queue.poll();
 
            // If there is left child
            if (temp.left != null) {
                queue.offer(temp.left);
 
                // For every traversed node,
                // we would check if it is a
                // leaf node by checking if
                // current node has children to it
                if (temp.left.left == null
                    && temp.left.right == null) {
 
                    // For every leaf node
                    // encountered, we would
                    // keep not of it as
                    // "Previously Visided Leaf node.
                    lastLevelLevelOrder = temp.left;
                    parentOfLastNode = temp;
                }
            }
 
            if (temp.right != null) {
                queue.offer(temp.right);
 
                if (temp.right.left == null
                    && temp.right.right == null) {
 
                    // For every leaf node
                    // encountered, we would
                    // keep not of it as
                    // "Previously Visided Leaf node.
                    lastLevelLevelOrder = temp.right;
                    parentOfLastNode = temp;
                }
            }
        }
 
        // Once out of above loop.
        // we would certainly have
        // last visited node, which
        // is to be deleted and its
        // parent node.
 
        if (lastLevelLevelOrder != null
            && parentOfLastNode != null) {
 
            // If last node is right child
            // of parent, make right node
            // of its parent as NULL or
            // make left node as NULL
            if (parentOfLastNode.right != null)
                parentOfLastNode.right = null;
            else
                parentOfLastNode.left = null;
        }
        else
            System.out.println("Empty Tree");
    }
 
    // Driver Code
    public static void main(String[] args)
    {
 
        Node root = new Node(6);
        root.left = new Node(5);
        root.right = new Node(4);
        root.left.left = new Node(1);
        root.left.right = new Node(2);
        root.right.right = new Node(5);
 
        DeleteLastNode deleteLastNode
            = new DeleteLastNode();
 
        System.out.println("Inorder traversal "
                           + "before deletion of "
                           + "last node : ");
        deleteLastNode.inorder(root);
 
        deleteLastNode.deleteLastNode(root);
 
        System.out.println("\nInorder traversal "
                           + "after deletion "
                           + "of last node : ");
 
        deleteLastNode.inorder(root);
    }
}

C#

// C# implementation of the approach
using System;
using System.Collections.Generic;
public class DeleteLastNode {
      
    // Tree Node
    public class Node {
  
        public Node left, right;
        public int data;
  
        public Node(int data)
        {
            this.data = data;
        }
    }
  
    // Function to perform the inorder traversal of the tree
    public void inorder(Node root)
    {
        if (root == null)
            return;
  
        inorder(root.left);
        Console.Write(root.data + " ");
        inorder(root.right);
    }
  
    // To keep track of last
    // processed nodes parent
    // and node itself.
    public static Node lastLevelLevelOrder;
    public static Node parentOfLastNode;
  
    // Method to delete the last node
    // from the tree
    public void deleteLastNode(Node root)
    {
  
        // If tree is empty, it
        // would return without
        // any deletion
        if (root == null)
            return;
  
        // The queue would be needed
        // to maintain the level order
        // traversal of nodes
        Queue queue = new Queue();
  
        queue.Enqueue(root);
  
        // The traversing would
        // continue until all
        // nodes are traversed once
        while (queue.Count!=0) {
  
            Node temp = queue.Dequeue();
  
            // If there is left child
            if (temp.left != null) {
                queue.Enqueue(temp.left);
  
                // For every traversed node,
                // we would check if it is a
                // leaf node by checking if
                // current node has children to it
                if (temp.left.left == null
                    && temp.left.right == null) {
  
                    // For every leaf node
                    // encountered, we would
                    // keep not of it as
                    // "Previously Visided Leaf node.
                    lastLevelLevelOrder = temp.left;
                    parentOfLastNode = temp;
                }
            }
  
            if (temp.right != null) {
                queue.Enqueue(temp.right);
  
                if (temp.right.left == null
                    && temp.right.right == null) {
  
                    // For every leaf node
                    // encountered, we would
                    // keep not of it as
                    // "Previously Visided Leaf node.
                    lastLevelLevelOrder = temp.right;
                    parentOfLastNode = temp;
                }
            }
        }
  
        // Once out of above loop.
        // we would certainly have
        // last visited node, which
        // is to be deleted and its
        // parent node.
  
        if (lastLevelLevelOrder != null
            && parentOfLastNode != null) {
  
            // If last node is right child
            // of parent, make right node
            // of its parent as NULL or
            // make left node as NULL
            if (parentOfLastNode.right != null)
                parentOfLastNode.right = null;
            else
                parentOfLastNode.left = null;
        }
        else
            Console.WriteLine("Empty Tree");
    }
  
    // Driver Code
    public static void Main(String[] args)
    {
  
        Node root = new Node(6);
        root.left = new Node(5);
        root.right = new Node(4);
        root.left.left = new Node(1);
        root.left.right = new Node(2);
        root.right.right = new Node(5);
  
        DeleteLastNode deleteLastNode
            = new DeleteLastNode();
  
        Console.WriteLine("Inorder traversal "
                           + "before deletion of "
                           + "last node : ");
        deleteLastNode.inorder(root);
  
        deleteLastNode.deleteLastNode(root);
  
        Console.WriteLine("\nInorder traversal "
                           + "after deletion "
                           + "of last node : ");
  
        deleteLastNode.inorder(root);
    }
}
 
// This code contributed by Rajput-Ji
输出:
Inorder traversal before deletion of last node : 
1 5 2 6 4 5 
Inorder traversal after deletion of last node : 
1 5 2 6 4

时间复杂度: O(N)
由于每个节点都会被访问一次,因此所花费的时间与树中存在的节点数成线性关系。
辅助空间: O(N)
由于我们将维护一个队列来进行级别顺序遍历,因此消耗的空间将是O(N)     .