📌  相关文章
📜  检查值是否存在于按级别顺序排序的完整二叉树中

📅  最后修改于: 2021-04-21 21:05:18             🧑  作者: Mango

给定一个按级别排序的完整二叉树,任务是检查其中是否存在键。一个完整的二叉树具有除最后一个完全填充的级别之外的所有级别,所有节点都尽可能地位于最左侧。

例子:

7
          /     \
         10      15
       /   \    /  \
      17   20  30  35
     / \   /     
    40 41 50      
Input: Node = 3
Output: No

Input: Node = 7
Output: Yes

Input: Node = 30
Output: Yes


方法一个简单的O(n)解决方案是完全遍历树并检查键值。但是,我们可以利用对树进行排序的信息,并在时间复杂度方面做得更好。

  • 找出可能存在密钥的级别。从根节点开始,一直向左移动,直到遇到一个大于键值的值。如果树中存在所有密钥,则此级别之前的密钥将包含该密钥。让我们假设这是l级。
  • 现在,在l的节点上执行二进制搜索。与常规二进制搜索不同,此级别的节点无法直接访问。但是,可以使用二进制逻辑对从根到此级别中每个节点的路径进行编码。例如,考虑样本树中的第3级。它最多可以包含2 3 = 8个节点。可以通过向左,向左,向左移动从根节点到达这些节点。或向左,向左,向右走;等等。如果左边用0表示,右边用1表示,则到达该级别节点的可能方式可以编码为arr = [ 000,001,010,011,100,101,110,111 ]。
  • 但是,不需要创建此数组,可以通过递归选择中间索引并仅生成该索引的1位格雷码来应用二进制搜索(请参阅本文)。
  • 如果路径不完整,只需检查数组的左侧。例如,编码路径011不对应于样本树中的任何值。由于树是完整的,因此可以确保右边不再有其他元素。
  • 如果找到键,则返回true,否则返回false。

下面是上述方法的实现:

C++
// C++ implementation of the approach
#include
using namespace std;
 
/* Class containing left and right
child of current node and key value*/
class Node
{
    public :
    int data;
    Node *left, *right;
 
    Node(int item)
    {
        data = item;
        left = right = NULL;
    }
};
 
/* Function to locate which level to check
for the existence of key. */
int findLevel(Node *root, int data)
{
 
    // If the key is less than the root,
    // it will certainly not exist in the tree
    // because tree is level-order sorted
    if (data < root->data)
        return -1;
 
    // If the key is equal to the root then
    // simply return 0 (zero'th level)
    if (data == root->data)
        return 0;
 
    int cur_level = 0;
 
    while (true)
    {
        cur_level++;
        root = root->left;
 
        // If the key is found in any leftmost element
        // then simply return true
        // No need for any extra searching
        if (root->data == data)
            return -2;
 
        // If key lies between the root data and
        // the left child's data OR if key is greater
        // than root data and there is no level
        // underneath it, return the current level
        if (root->data < data
            && (root->left == NULL
            || root->left->data > data))
        {
            break;
        }
    }
 
    return cur_level;
}
 
/* Function to traverse a binary
encoded path and return the value
encountered after traversal. */
int traversePath(Node *root,vector path)
{
    for (int i = 0; i < path.size(); i++)
    {
        int direction = path[i];
 
        // Go left
        if (direction == 0)
        {
 
            // Incomplete path
            if (root->left == NULL)
                return -1;
            root = root->left;
        }
 
        // Go right
        else
        {
 
            // Incomplete path
            if (root->right == NULL)
                return -1;
            root = root->right;
        }
    }
 
    // Return the data at the node
    return root->data;
}
 
/* Function to generate gray code of
corresponding binary number of integer i */
vector generateGray(int n, int x)
{
 
    // Create new arraylist to store
    // the gray code
    vector gray ;
 
    int i = 0;
    while (x > 0)
    {
        gray.push_back(x % 2);
        x = x / 2;
        i++;
    }
 
    // Reverse the encoding till here
    reverse(gray.begin(),gray.end());
 
    // Leftmost digits are filled with 0
    for (int j = 0; j < n - i; j++)
        gray.insert(gray.begin(), 0);
 
    return gray;
}
 
/* Function to search the key in a
particular level of the tree. */
bool binarySearch(Node *root, int start,
                    int end, int data,
                    int level)
{
    if (end >= start)
    {
 
        // Find the middle index
        int mid = (start + end) / 2;
 
        // Encode path from root to this index
        // in the form of 0s and 1s where
        // 0 means LEFT and 1 means RIGHT
        vector encoding = generateGray(level, mid);
 
        // Traverse the path in the tree
        // and check if the key is found
        int element_found = traversePath(root, encoding);
 
        // If path is incomplete
        if (element_found == -1)
 
            // Check the left part of the level
            return binarySearch(root, start,
                                mid - 1, data, level);
 
        if (element_found == data)
            return true;
 
        // Check the right part of the level
        if (element_found < data)
            return binarySearch(root, mid + 1,
                                end, data, level);
 
        // Check the left part of the level
        else
            return binarySearch(root, start,
                                mid - 1, data, level);
    }
 
    // Key not found in that level
    return false;
}
 
// Function that returns true if the
// key is found in the tree
bool findKey(Node *root, int data)
{
    // Find the level where the key may lie
    int level = findLevel(root, data);
 
    // If level is -1 then return false
    if (level == -1)
        return false;
 
    // If level is -2 i.e. key was found in any
    // leftmost element then simply return true
    if (level == -2)
        return true;
 
    // Apply binary search on the elements
    // of that level
    return binarySearch(root, 0, (int)pow(2, level) -
                        1, data, level);
}
 
// Driver code
int main()
{
    /* Consider the following level-order sorted tree
     
                    5
                / \
                8     10
                / \ / \
            13 23 25 30
            / \ /
            32 40 50
    */
 
    Node* root = new Node(5);
    root->left = new Node(8);
    root->right = new Node(10);
    root->left->left = new Node(13);
    root->left->right = new Node(23);
    root->right->left = new Node(25);
    root->right->right = new Node(30);
    root->left->left->left = new Node(32);
    root->left->left->right = new Node(40);
    root->left->right->left = new Node(50);
 
    // Keys to be searched
    int arr[] = { 5, 8, 9 };
    int n = sizeof(arr)/sizeof(int);
 
    for (int i = 0; i < n; i++)
    {
        if (findKey(root, arr[i]))
            cout << ("Yes") << endl;
        else
            cout << ("No") << endl;
    }
}
 
// This code is contributed by Arnab Kundu


Java
// Java implementation of the approach
import java.util.*;
import java.io.*;
 
/* Class containing left and right
child of current node and key value*/
class Node {
    int data;
    Node left, right;
 
    public Node(int item)
    {
        data = item;
        left = right = null;
    }
}
 
class GFG {
 
    /* Function to locate which level to check
    for the existence of key. */
    public static int findLevel(Node root, int data)
    {
 
        // If the key is less than the root,
        // it will certainly not exist in the tree
        // because tree is level-order sorted
        if (data < root.data)
            return -1;
 
        // If the key is equal to the root then
        // simply return 0 (zero'th level)
        if (data == root.data)
            return 0;
 
        int cur_level = 0;
 
        while (true) {
            cur_level++;
            root = root.left;
 
            // If the key is found in any leftmost element
            // then simply return true
            // No need for any extra searching
            if (root.data == data)
                return -2;
 
            // If key lies between the root data and
            // the left child's data OR if key is greater
            // than root data and there is no level
            // underneath it, return the current level
            if (root.data < data
                && (root.left == null
                    || root.left.data > data)) {
                break;
            }
        }
 
        return cur_level;
    }
 
    /* Function to traverse a binary
    encoded path and return the value
    encountered after traversal. */
    public static int traversePath(Node root,
                                   ArrayList path)
    {
        for (int i = 0; i < path.size(); i++) {
            int direction = path.get(i);
 
            // Go left
            if (direction == 0) {
 
                // Incomplete path
                if (root.left == null)
                    return -1;
                root = root.left;
            }
 
            // Go right
            else {
 
                // Incomplete path
                if (root.right == null)
                    return -1;
                root = root.right;
            }
        }
 
        // Return the data at the node
        return root.data;
    }
 
    /* Function to generate gray code of
    corresponding binary number of integer i */
    static ArrayList generateGray(int n, int x)
    {
 
        // Create new arraylist to store
        // the gray code
        ArrayList gray = new ArrayList();
 
        int i = 0;
        while (x > 0) {
            gray.add(x % 2);
            x = x / 2;
            i++;
        }
 
        // Reverse the encoding till here
        Collections.reverse(gray);
 
        // Leftmost digits are filled with 0
        for (int j = 0; j < n - i; j++)
            gray.add(0, 0);
 
        return gray;
    }
 
    /* Function to search the key in a
    particular level of the tree. */
    public static boolean binarySearch(Node root,
                                       int start,
                                       int end,
                                       int data,
                                       int level)
    {
        if (end >= start) {
 
            // Find the middle index
            int mid = (start + end) / 2;
 
            // Encode path from root to this index
            // in the form of 0s and 1s where
            // 0 means LEFT and 1 means RIGHT
            ArrayList encoding = generateGray(level, mid);
 
            // Traverse the path in the tree
            // and check if the key is found
            int element_found = traversePath(root, encoding);
 
            // If path is incomplete
            if (element_found == -1)
 
                // Check the left part of the level
                return binarySearch(root, start, mid - 1, data, level);
 
            if (element_found == data)
                return true;
 
            // Check the right part of the level
            if (element_found < data)
                return binarySearch(root, mid + 1, end, data, level);
 
            // Check the left part of the level
            else
                return binarySearch(root, start, mid - 1, data, level);
        }
 
        // Key not found in that level
        return false;
    }
 
    // Function that returns true if the
    // key is found in the tree
    public static boolean findKey(Node root, int data)
    {
        // Find the level where the key may lie
        int level = findLevel(root, data);
 
        // If level is -1 then return false
        if (level == -1)
            return false;
 
        // If level is -2 i.e. key was found in any
        // leftmost element then simply return true
        if (level == -2)
            return true;
 
        // Apply binary search on the elements
        // of that level
        return binarySearch(root, 0, (int)Math.pow(2, level) - 1, data, level);
    }
 
    // Driver code
    public static void main(String[] args)
    {
        /* Consider the following level-order sorted tree
         
                          5
                       /    \
                      8      10
                    /  \    /  \
                  13    23 25   30
                 / \   /
                32 40 50
        */
 
        Node root = new Node(5);
        root.left = new Node(8);
        root.right = new Node(10);
        root.left.left = new Node(13);
        root.left.right = new Node(23);
        root.right.left = new Node(25);
        root.right.right = new Node(30);
        root.left.left.left = new Node(32);
        root.left.left.right = new Node(40);
        root.left.right.left = new Node(50);
 
        // Keys to be searched
        int arr[] = { 5, 8, 9 };
        int n = arr.length;
 
        for (int i = 0; i < n; i++) {
            if (findKey(root, arr[i]))
                System.out.println("Yes");
            else
                System.out.println("No");
        }
    }
}


Python3
# Python3 implementation of the approach
from sys import maxsize
from collections import deque
 
INT_MIN = -maxsize
 
# Class containing left and right
# child of current node and key value
class Node:
     
    def __init__(self, data):
         
        self.data = data
        self.left = None
        self.right = None
 
# Function to locate which level to check
# for the existence of key.
def findLevel(root: Node, data: int) -> int:
     
    # If the key is less than the root,
    # it will certainly not exist in the tree
    # because tree is level-order sorted
    if (data < root.data):
        return -1
 
    # If the key is equal to the root then
    # simply return 0 (zero'th level)
    if (data == root.data):
        return 0
 
    cur_level = 0
 
    while True:
 
        cur_level += 1
        root = root.left
 
        # If the key is found in any leftmost
        # element then simply return true
        # No need for any extra searching
        if (root.data == data):
            return -2
 
        # If key lies between the root data and
        # the left child's data OR if key is greater
        # than root data and there is no level
        # underneath it, return the current level
        if (root.data < data and
           (root.left == None or
            root.left.data > data)):
            break
 
    return cur_level
 
# Function to traverse a binary
# encoded path and return the value
# encountered after traversal.
def traversePath(root: Node, path: list) -> int:
     
    for i in range(len(path)):
        direction = path[i]
 
        # Go left
        if (direction == 0):
 
            # Incomplete path
            if (root.left == None):
                return -1
                 
            root = root.left
 
        # Go right
        else:
 
            # Incomplete path
            if (root.right == None):
                return -1
                 
            root = root.right
 
    # Return the data at the node
    return root.data
 
# Function to generate gray code of
# corresponding binary number of integer i
def generateGray(n: int, x: int) -> list:
     
    # Create new arraylist to store
    # the gray code
    gray = []
 
    i = 0
    while (x > 0):
        gray.append(x % 2)
        x = x / 2
        i += 1
 
    # Reverse the encoding till here
    gray.reverse()
 
    # Leftmost digits are filled with 0
    for j in range(n - i):
        gray.insert(0, gray[0])
 
    return gray
 
# Function to search the key in a
# particular level of the tree.
def binarySearch(root: Node, start: int,
                  end: int, data: int,
                level: int) -> bool:
 
    if (end >= start):
 
        # Find the middle index
        mid = (start + end) / 2
 
        # Encode path from root to this index
        # in the form of 0s and 1s where
        # 0 means LEFT and 1 means RIGHT
        encoding = generateGray(level, mid)
 
        # Traverse the path in the tree
        # and check if the key is found
        element_found = traversePath(root, encoding)
 
        # If path is incomplete
        if (element_found == -1):
 
            # Check the left part of the level
            return binarySearch(root, start,
                                mid - 1, data,
                                level)
 
        if (element_found == data):
            return True
 
        # Check the right part of the level
        if (element_found < data):
            return binarySearch(root, mid + 1,
                                end, data, level)
 
        # Check the left part of the level
        else:
            return binarySearch(root, start,
                                mid - 1, data,
                                level)
 
    # Key not found in that level
    return False
 
# Function that returns true if the
# key is found in the tree
def findKey(root: Node, data: int) -> bool:
     
    # Find the level where the key may lie
    level = findLevel(root, data)
 
    # If level is -1 then return false
    if (level == -1):
        return False
 
    # If level is -2 i.e. key was found in any
    # leftmost element then simply return true
    if (level == -2):
        return True
 
    # Apply binary search on the elements
    # of that level
    return binarySearch(root, 0,
                        int(pow(2, level) - 1),
                        data, level)
 
# Driver code
if __name__ == "__main__":
 
    # Consider the following level
    # order sorted tree
    '''
     
                5
               /  \
              8    10
            /  \  /  \
           13  23 25  30
          / \  /
        32  40 50
    '''
 
    root = Node(5)
    root.left = Node(8)
    root.right = Node(10)
    root.left.left = Node(13)
    root.left.right = Node(23)
    root.right.left = Node(25)
    root.right.right = Node(30)
    root.left.left.left = Node(32)
    root.left.left.right = Node(40)
    root.left.right.left = Node(50)
 
    # Keys to be searched
    arr = [ 5, 8, 9 ]
    n = len(arr)
 
    for i in range(n):
        if (findKey(root, arr[i])):
            print("Yes")
        else:
            print("No")
 
# This code is contributed by sanjeev2552


输出:
Yes
Yes
No








时间复杂度:可以在O(logn)时间中找到级别。遍历任何路径执行二进制搜索的时间为O(logn)。此外,在最坏的情况下,该级别最多具有n / 2个节点。
因此,执行搜索的时间复杂度变为O(logn)* O(log(n / 2))= O(logn)^ 2