📌  相关文章
📜  使用O(1)额外空间的BST中的第K个最小元素

📅  最后修改于: 2021-05-24 21:42:36             🧑  作者: Mango

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

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

在本文中,我们讨论了两种方法,在本文中,讨论了一种方法。所有以前的方法都需要额外的空间。如何在没有多余空间的情况下找到第k个最大元素?

这个想法是使用Morris Traversal。在此遍历中,我们首先创建到Inorder后继程序的链接,并使用这些链接打印数据,最后还原所做的更改以还原原始树。有关更多详细信息,请参见此内容。

以下是该想法的实现。

C++
// C++ program to find k'th largest element in BST
#include
using namespace std;
  
// A BST node
struct Node
{
    int key;
    Node *left, *right;
};
  
// A function to find
int KSmallestUsingMorris(Node *root, int k)
{
    // Count to iterate over elements till we
    // get the kth smallest number
    int count = 0;
  
    int ksmall = INT_MIN; // store the Kth smallest
    Node *curr = root; // to store the current node
  
    while (curr != NULL)
    {
        // Like Morris traversal if current does
        // not have left child rather than printing
        // as we did in inorder, we will just
        // increment the count as the number will
        // be in an increasing order
        if (curr->left == NULL)
        {
            count++;
  
            // if count is equal to K then we found the
            // kth smallest, so store it in ksmall
            if (count==k)
                ksmall = curr->key;
  
            // go to current's right child
            curr = curr->right;
        }
        else
        {
            // we create links to Inorder Successor and
            // count using these links
            Node *pre = curr->left;
            while (pre->right != NULL && pre->right != curr)
                pre = pre->right;
  
            // building links
            if (pre->right==NULL)
            {
                //link made to Inorder Successor
                pre->right = curr;
                curr = curr->left;
            }
  
            // While breaking the links in so made temporary
            // threaded tree we will check for the K smallest
            // condition
            else
            {
                // Revert the changes made in if part (break link
                // from the Inorder Successor)
                pre->right = NULL;
  
                count++;
  
                // If count is equal to K then we found
                // the kth smallest and so store it in ksmall
                if (count==k)
                    ksmall = curr->key;
  
                curr = curr->right;
            }
        }
    }
    return ksmall; //return the found value
}
  
// 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 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);
  
    for (int k=1; k<=7; k++)
       cout << KSmallestUsingMorris(root, k) << " ";
  
    return 0;
}


Java
// Java program to find k'th largest element in BST 
import java.util.*;
class GfG {
  
// A BST node 
static class Node 
{ 
    int key; 
    Node left, right; 
}
  
// A function to find 
static int KSmallestUsingMorris(Node root, int k) 
{ 
    // Count to iterate over elements till we 
    // get the kth smallest number 
    int count = 0; 
  
    int ksmall = Integer.MIN_VALUE; // store the Kth smallest 
    Node curr = root; // to store the current node 
  
    while (curr != null) 
    { 
        // Like Morris traversal if current does 
        // not have left child rather than printing 
        // as we did in inorder, we will just 
        // increment the count as the number will 
        // be in an increasing order 
        if (curr.left == null) 
        { 
            count++; 
  
            // if count is equal to K then we found the 
            // kth smallest, so store it in ksmall 
            if (count==k) 
                ksmall = curr.key; 
  
            // go to current's right child 
            curr = curr.right; 
        } 
        else
        { 
            // we create links to Inorder Successor and 
            // count using these links 
            Node pre = curr.left; 
            while (pre.right != null && pre.right != curr) 
                pre = pre.right; 
  
            // building links 
            if (pre.right== null) 
            { 
                //link made to Inorder Successor 
                pre.right = curr; 
                curr = curr.left; 
            } 
  
            // While breaking the links in so made temporary 
            // threaded tree we will check for the K smallest 
            // condition 
            else
            { 
                // Revert the changes made in if part (break link 
                // from the Inorder Successor) 
                pre.right = null; 
  
                count++; 
  
                // If count is equal to K then we found 
                // the kth smallest and so store it in ksmall 
                if (count==k) 
                    ksmall = curr.key; 
  
                curr = curr.right; 
            } 
        } 
    } 
    return ksmall; //return the found value 
} 
  
// A utility function to create a new BST node 
static Node newNode(int item) 
{ 
    Node temp = new Node(); 
    temp.key = item; 
    temp.left = null;
    temp.right = null; 
    return temp; 
} 
  
/* A utility function to insert a new node with given key in BST */
static 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 
public static void main(String[] args) 
{ 
    /* 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); 
  
    for (int k=1; k<=7; k++) 
    System.out.print(KSmallestUsingMorris(root, k) + " "); 
  
}
}


Python3
# Python 3 program to find k'th 
# largest element in BST
  
# A BST node 
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 
def KSmallestUsingMorris(root, k):
      
    # Count to iterate over elements 
    # till we get the kth smallest number 
    count = 0
  
    ksmall = -9999999999 # store the Kth smallest 
    curr = root # to store the current node 
  
    while curr != None:
          
        # Like Morris traversal if current does
        # not have left child rather than 
        # printing as we did in inorder, we 
        # will just increment the count as the 
        # number will be in an increasing order 
        if curr.left == None:
            count += 1
  
            # if count is equal to K then we 
            # found the kth smallest, so store 
            # it in ksmall 
            if count == k: 
                ksmall = curr.key 
  
            # go to current's right child 
            curr = curr.right
        else:
              
            # we create links to Inorder Successor 
            # and count using these links 
            pre = curr.left 
            while (pre.right != None and 
                   pre.right != curr): 
                pre = pre.right 
  
            # building links 
            if pre.right == None:
                  
                # link made to Inorder Successor 
                pre.right = curr 
                curr = curr.left
  
            # While breaking the links in so made 
            # temporary threaded tree we will check 
            # for the K smallest condition 
            else:
                  
                # Revert the changes made in if part 
                # (break link from the Inorder Successor) 
                pre.right = None
  
                count += 1
  
                # If count is equal to K then we 
                # found the kth smallest and so 
                # store it in ksmall 
                if count == k:
                    ksmall = curr.key 
          
                curr = curr.right
    return ksmall # return the found value 
  
# 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):
        print(KSmallestUsingMorris(root, k),
                                 end = " ") 
  
# This code is contributed by PranchalK


C#
// C# program to find k'th largest element in BST 
using System;
  
class GfG 
{
  
// A BST node 
public class Node 
{ 
    public int key; 
    public Node left, right; 
}
  
// A function to find 
static int KSmallestUsingMorris(Node root, int k) 
{ 
    // Count to iterate over elements till we 
    // get the kth smallest number 
    int count = 0; 
  
    int ksmall = int.MinValue; // store the Kth smallest 
    Node curr = root; // to store the current node 
  
    while (curr != null) 
    { 
        // Like Morris traversal if current does 
        // not have left child rather than printing 
        // as we did in inorder, we will just 
        // increment the count as the number will 
        // be in an increasing order 
        if (curr.left == null) 
        { 
            count++; 
  
            // if count is equal to K then we found the 
            // kth smallest, so store it in ksmall 
            if (count==k) 
                ksmall = curr.key; 
  
            // go to current's right child 
            curr = curr.right; 
        } 
        else
        { 
            // we create links to Inorder Successor and 
            // count using these links 
            Node pre = curr.left; 
            while (pre.right != null && pre.right != curr) 
                pre = pre.right; 
  
            // building links 
            if (pre.right == null) 
            { 
                // link made to Inorder Successor 
                pre.right = curr; 
                curr = curr.left; 
            } 
  
            // While breaking the links in so made temporary 
            // threaded tree we will check for the K smallest 
            // condition 
            else
            { 
                // Revert the changes made in if part (break link 
                // from the Inorder Successor) 
                pre.right = null; 
  
                count++; 
  
                // If count is equal to K then we found 
                // the kth smallest and so store it in ksmall 
                if (count == k) 
                    ksmall = curr.key; 
  
                curr = curr.right; 
            } 
        } 
    } 
    return ksmall; //return the found value 
} 
  
// A utility function to create a new BST node 
static Node newNode(int item) 
{ 
    Node temp = new Node(); 
    temp.key = item; 
    temp.left = null;
    temp.right = null; 
    return temp; 
} 
  
/* A utility function to insert a new node with given key in BST */
static 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 
public static void Main(String[] args) 
{ 
    /* 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); 
  
    for (int k = 1; k <= 7; k++) 
    Console.Write(KSmallestUsingMorris(root, k) + " "); 
  
}
} 
  
// This code has been contributed by 29AjayKumar


输出:

20 30 40 50 60 70 80