📜  不允许修改BST时BST中的第K个最大元素

📅  最后修改于: 2021-05-24 23:43:45             🧑  作者: Mango

给定二进制搜索树(BST)和正整数k,请在二进制搜索树中找到第k个最大元素。

例如,在下面的BST中,如果k = 3,则输出应为14,如果k = 5,则输出应为10。

在本文中,我们讨论了两种方法。方法1需要O(n)时间。方法2花费O(h)时间,其中h是BST的高度,但是需要增加BST(每个子节点在左子树中存储的节点数)。

我们能否在比O(n)时间更好的情况下找到第k个最大元素,并且不进行增广?

方法:

  1. 这个想法是对BST进行反向有序遍历。保持访问的节点数。
  2. 反向有序遍历以降序遍历所有节点,即先访问右节点,然后再居中然后再向左,然后继续递归遍历这些节点。
  3. 在进行遍历时,请跟踪到目前为止已访问的节点数。
  4. 当计数等于k时,停止遍历并打印键。
C++
// C++ program to find k'th largest element in BST
#include
using namespace std;
  
struct Node
{
    int key;
    Node *left, *right;
};
  
// A utility function to create a new BST node
Node *newNode(int item)
{
    Node *temp = new Node;
    temp->key = item;
    temp->left = temp->right = NULL;
    return temp;
}
  
// A function to find k'th largest element in a given tree.
void kthLargestUtil(Node *root, int k, int &c)
{
    // Base cases, the second condition is important to
    // avoid unnecessary recursive calls
    if (root == NULL || c >= k)
        return;
  
    // Follow reverse inorder traversal so that the
    // largest element is visited first
    kthLargestUtil(root->right, k, c);
  
    // Increment count of visited nodes
    c++;
  
    // If c becomes k now, then this is the k'th largest 
    if (c == k)
    {
        cout << "K'th largest element is "
             << root->key << endl;
        return;
    }
  
    // Recur for left subtree
    kthLargestUtil(root->left, k, c);
}
  
// Function to find k'th largest element
void kthLargest(Node *root, int k)
{
    // Initialize count of nodes visited as 0
    int c = 0;
  
    // Note that c is passed by reference
    kthLargestUtil(root, k, c);
}
  
/* A utility function to insert a new node with given key in BST */
Node* insert(Node* node, int key)
{
    /* If the tree is empty, return a new node */
    if (node == NULL) return newNode(key);
  
    /* Otherwise, recur down the tree */
    if (key < node->key)
        node->left  = insert(node->left, key);
    else if (key > node->key)
        node->right = insert(node->right, key);
  
    /* return the (unchanged) node pointer */
    return node;
}
  
// Driver Program to test above functions
int main()
{
    /* Let us create following BST
              50
           /     \
          30      70
         /  \    /  \
       20   40  60   80 */
    Node *root = NULL;
    root = insert(root, 50);
    insert(root, 30);
    insert(root, 20);
    insert(root, 40);
    insert(root, 70);
    insert(root, 60);
    insert(root, 80);
  
    int c = 0;
    for (int k=1; k<=7; k++)
        kthLargest(root, k);
  
    return 0;
}


Java
// Java code to find k'th largest element in BST
  
// A binary tree node
class Node {
  
    int data;
    Node left, right;
  
    Node(int d)
    {
        data = d;
        left = right = null;
    }
}
  
class BinarySearchTree {
  
    // Root of BST
    Node root;
  
    // Constructor
    BinarySearchTree()
    {
        root = null;
    }
      
    // function to insert nodes
    public void insert(int data)
    {
        this.root = this.insertRec(this.root, data);
    }
      
    /* A utility function to insert a new node 
    with given key in BST */
    Node insertRec(Node node, int data)
    {   
        /* If the tree is empty, return a new node */
        if (node == null) {
            this.root = new Node(data);
            return this.root;
        }
  
        if (data == node.data) {
            return node;
        }
          
        /* Otherwise, recur down the tree */
        if (data < node.data) {
            node.left = this.insertRec(node.left, data);
        } else {
            node.right = this.insertRec(node.right, data);
        }
        return node;
    }
  
    // class that stores the value of count
    public class count {
        int c = 0;
    }
  
    // utility function to find kth largest no in 
    // a given tree
    void kthLargestUtil(Node node, int k, count C)
    {
        // Base cases, the second condition is important to
        // avoid unnecessary recursive calls
        if (node == null || C.c >= k)
            return;
          
        // Follow reverse inorder traversal so that the
        // largest element is visited first
        this.kthLargestUtil(node.right, k, C); 
          
        // Increment count of visited nodes
        C.c++;
          
        // If c becomes k now, then this is the k'th largest 
        if (C.c == k) {
            System.out.println(k + "th largest element is " + 
                                                 node.data);
            return;
        }
          
        // Recur for left subtree
        this.kthLargestUtil(node.left, k, C); 
    }
  
    // Method to find the kth largest no in given BST
    void kthLargest(int k)
    {
        count c = new count(); // object of class count
        this.kthLargestUtil(this.root, k, c);
    }
  
    // Driver function
    public static void main(String[] args)
    {
        BinarySearchTree tree = new BinarySearchTree();
          
        /* Let us create following BST
              50
           /     \
          30      70
         /  \    /  \
       20   40  60   80 */
        tree.insert(50);
        tree.insert(30);
        tree.insert(20);
        tree.insert(40);
        tree.insert(70);
        tree.insert(60);
        tree.insert(80);
  
        for (int i = 1; i <= 7; i++) {
            tree.kthLargest(i);
        }
    }
}
  
// This code is contributed by Kamal Rawal


Python3
# Python3 program to find k'th largest 
# element in BST 
  
class Node: 
  
    # Constructor to create a new node 
    def __init__(self, data): 
        self.key = data 
        self.left = None
        self.right = None
          
# A function to find k'th largest 
# element in a given tree. 
def kthLargestUtil(root, k, c):
      
    # Base cases, the second condition 
    # is important to avoid unnecessary
    # recursive calls 
    if root == None or c[0] >= k: 
        return
  
    # Follow reverse inorder traversal 
    # so that the largest element is 
    # visited first 
    kthLargestUtil(root.right, k, c)
  
    # Increment count of visited nodes 
    c[0] += 1
  
    # If c becomes k now, then this is 
    # the k'th largest 
    if c[0] == k:
        print("K'th largest element is", 
                               root.key) 
        return
  
    # Recur for left subtree 
    kthLargestUtil(root.left, k, c)
  
# Function to find k'th largest element 
def kthLargest(root, k):
      
    # Initialize count of nodes
    # visited as 0 
    c = [0]
  
    # Note that c is passed by reference 
    kthLargestUtil(root, k, c)
  
# A utility function to insert a new 
# node with given key in BST */
def insert(node, key): 
      
    # If the tree is empty, 
    # return a new node 
    if node == None:
        return Node(key) 
  
    # Otherwise, recur down the tree 
    if key < node.key: 
        node.left = insert(node.left, key) 
    elif key > node.key:
        node.right = insert(node.right, key) 
  
    # return the (unchanged) node pointer 
    return node
  
# Driver Code
if __name__ == '__main__':
      
    # Let us create following BST 
    #         50 
    #     /     \ 
    #     30     70 
    # / \ / \ 
    # 20 40 60 80 */
    root = None
    root = insert(root, 50)
    insert(root, 30)
    insert(root, 20)
    insert(root, 40)
    insert(root, 70)
    insert(root, 60)
    insert(root, 80)
  
    for k in range(1,8):
        kthLargest(root, k)
          
# This code is contributed by PranchalK


C#
using System;
  
// C# code to find k'th largest element in BST 
  
// A binary tree node 
public class Node
{
  
    public int data;
    public Node left, right;
  
    public Node(int d)
    {
        data = d;
        left = right = null;
    }
}
  
public class BinarySearchTree
{
  
    // Root of BST 
    public Node root;
  
    // Constructor 
    public BinarySearchTree()
    {
        root = null;
    }
  
    // function to insert nodes 
    public virtual void insert(int data)
    {
        this.root = this.insertRec(this.root, data);
    }
  
    /* A utility function to insert a new node  
    with given key in BST */
    public virtual Node insertRec(Node node, int data)
    {
        /* If the tree is empty, return a new node */
        if (node == null)
        {
            this.root = new Node(data);
            return this.root;
        }
  
        if (data == node.data)
        {
            return node;
        }
  
        /* Otherwise, recur down the tree */
        if (data < node.data)
        {
            node.left = this.insertRec(node.left, data);
        }
        else
        {
            node.right = this.insertRec(node.right, data);
        }
        return node;
    }
  
    // class that stores the value of count 
    public class count
    {
        private readonly BinarySearchTree outerInstance;
  
        public count(BinarySearchTree outerInstance)
        {
            this.outerInstance = outerInstance;
        }
  
        internal int c = 0;
    }
  
    // utility function to find kth largest no in  
    // a given tree 
    public virtual void kthLargestUtil(Node node, int k, count C)
    {
        // Base cases, the second condition is important to 
        // avoid unnecessary recursive calls 
        if (node == null || C.c >= k)
        {
            return;
        }
  
        // Follow reverse inorder traversal so that the 
        // largest element is visited first 
        this.kthLargestUtil(node.right, k, C);
  
        // Increment count of visited nodes 
        C.c++;
  
        // If c becomes k now, then this is the k'th largest  
        if (C.c == k)
        {
            Console.WriteLine(k + "th largest element is " + node.data);
            return;
        }
  
        // Recur for left subtree 
        this.kthLargestUtil(node.left, k, C);
    }
  
    // Method to find the kth largest no in given BST 
    public virtual void kthLargest(int k)
    {
        count c = new count(this); // object of class count
        this.kthLargestUtil(this.root, k, c);
    }
  
    // Driver function 
    public static void Main(string[] args)
    {
        BinarySearchTree tree = new BinarySearchTree();
  
        /* Let us create following BST 
              50 
           /     \ 
          30      70 
         /  \    /  \ 
       20   40  60   80 */
        tree.insert(50);
        tree.insert(30);
        tree.insert(20);
        tree.insert(40);
        tree.insert(70);
        tree.insert(60);
        tree.insert(80);
  
        for (int i = 1; i <= 7; i++)
        {
            tree.kthLargest(i);
        }
    }
}
  
  // This code is contributed by Shrikant13


输出:

K'th largest element is 80
K'th largest element is 70
K'th largest element is 60
K'th largest element is 50
K'th largest element is 40
K'th largest element is 30
K'th largest element is 20 

复杂度分析:

  1. 时间复杂度: O(h + k)。
    该代码首先遍历到最右边的节点,该节点花费O(h)时间,然后遍历O(k)时间中的k个元素。因此,总体时间复杂度为O(h + k)。
  2. 辅助空间: O(1)。
    由于不需要额外的空间。