Banana-Leopard/TASTY huggingface dataset:
# Python3 program to determine whether
# binary tree is level sorted or not.
from queue import Queue
 
# Function to create new tree node.
class newNode:
    def __init__(self, key):
        self.key = key
        self.left = self.right = None
 
# Function to determine if given binary
# tree is level sorted or not.
def isSorted(root):
 
    # to store maximum value of previous
    # level.
    prevMax = -999999999999
 
    # to store minimum value of current
    # level.
    minval = None
 
    # to store maximum value of current
    # level.
    maxval = None
 
    # to store number of nodes in current
    # level.
    levelSize = None
 
    # queue to perform level order traversal.
    q = Queue()
    q.put(root)
 
    while (not q.empty()):
 
        # find number of nodes in current
        # level.
        levelSize = q.qsize()
 
        minval = 999999999999
        maxval = -999999999999
 
        # traverse current level and find
        # minimum and maximum value of
        # this level.
        while (levelSize > 0):
            root = q.queue[0]
            q.get()
 
            levelSize -= 1
 
            minval = min(minval, root.key)
            maxval = max(maxval, root.key)
 
            if (root.left):
                q.put(root.left)
 
            if (root.right):
                q.put(root.right)
 
        # if minimum value of this level
        # is not greater than maximum
        # value of previous level then
        # given tree is not level sorted.
        if (minval <= prevMax):
            return 0
 
        # maximum value of this level is
        # previous maximum value for
        # next level.
        prevMax = maxval
    return 1
 
# Driver Code
if __name__ == '__main__':
     
    #
    #     1
    #     /
    #     4
    #     \
    #     6
    #     / \
    #     8 9
    #     /     \
    # 12     10
    root = newNode(1)
    root.left = newNode(4)
    root.left.right = newNode(6)
    root.left.right.left = newNode(8)
    root.left.right.right = newNode(9)
    root.left.right.left.left = newNode(12)
    root.left.right.right.right = newNode(10)
 
    if (isSorted(root)):
        print("Sorted")
    else:
        print("Not sorted")
 
# This code is contributed by PranchalK

Time complexity: linear
Space complexity: linear
# Python program to count leaf nodes in Binary Tree
  
# A Binary tree node
class Node:
      
    # Constructor to create a new node
    def __init__(self, data):
        self.data = data 
        self.left = None
        self.right = None
  
# Function to get the count of leaf nodes in binary tree
def getLeafCount(node):
    if node is None:
        return 0 
    if(node.left is None and node.right is None):
        return 1 
    else:
        return getLeafCount(node.left) + getLeafCount(node.right)
  
  
# Driver program to test above function
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
  
print ("Leaf count of the tree is %d" %(getLeafCount(root)))
  
#This code is contributed by Nikhil Kumar Singh(nickzuck_007)

Time complexity: linear
Space complexity: logn
# Python3 program to count total number
# of non-leaf nodes in a binary tree
 
# class that allocates a new node with the
#given data and None left and right pointers.
class newNode:
    def __init__(self,data):
        self.data = data
        self.left = self.right = None
 
# Computes the number of non-leaf
# nodes in a tree.
def countNonleaf(root):
     
    # Base cases.
    if (root == None or (root.left == None and
                         root.right == None)):
        return 0
 
    # If root is Not None and its one of 
    # its child is also not None
    return (1 + countNonleaf(root.left) +
                countNonleaf(root.right))
 
# Driver Code
if __name__ == '__main__':
 
    root = newNode(1)
    root.left = newNode(2)
    root.right = newNode(3)
    root.left.left = newNode(4)
    root.left.right = newNode(5)
    print(countNonleaf(root))
 
# This code is contributed by PranchalK

Time complexity: linear
Space complexity: logn
# Python program to count
# half nodes in a Binary Tree
# using iterative approach
  
# A node structure
class Node:
  
    # A utility function to create a new node
    def __init__(self ,key):
        self.data = key
        self.left = None
        self.right = None
  
# Iterative Method to count half nodes of binary tree
def gethalfCount(root):
  
    # Base Case
    if root is None:
        return 0
  
    # Create an empty queue for level order traversal
    queue = []
  
    # Enqueue Root and initialize count
    queue.append(root)
  
    count = 0 #initialize count for half nodes
    while(len(queue) > 0):
  
        node = queue.pop(0)
  
        # if it is half node then increment count
        if node.left is not None and node.right is None or node.left is None and node.right is not None:
            count = count+1
  
        #Enqueue left child
        if node.left is not None:
            queue.append(node.left)
  
        # Enqueue right child
        if node.right is not None:
            queue.append(node.right)
  
    return count
  
#Driver Program to test above function
  
root = Node(2)
root.left = Node(7)
root.right = Node(5)
root.left.right = Node(6)
root.left.right.left = Node(1)
root.left.right.right = Node(11)
root.right.right = Node(9)
root.right.right.left = Node(4)
  
  
print "%d" %(gethalfCount(root))

Time complexity: linear
Space complexity: linear
# Python program to count half nodes in a binary tree
  
# A node structure
class newNode:
    def __init__(self, data):
        self.data = data
        self.left = self.right = None
  
# Function to get the count of half Nodes in a binary tree
def gethalfCount(root):
    if root == None:
        return 0
    res = 0
    if(root.left == None and root.right != None) or \
        (root.left != None and root.right == None):
        res += 1
    res += (gethalfCount(root.left) + \
            gethalfCount(root.right))
    return res
  
# Driver program
''' 2
    / \
    7     5
    \     \
    6     9
    / \ /
    1 11 4
    Let us create Binary Tree shown in
    above example '''
  
root = newNode(2)
root.left = newNode(7)
root.right = newNode(5)
root.left.right = newNode(6)
root.left.right.left = newNode(1)
root.left.right.right = newNode(11)
root.right.right = newNode(9)
root.right.right.left = newNode(4)
print(gethalfCount(root))
  
# This code is contributed by simranjenny84

Time complexity: linear
Space complexity: linear
# Python program to count 
# full nodes in a Binary Tree
# using iterative approach
  
# A node structure
class Node:
    # A utility function to create a new node
    def __init__(self ,key):
        self.data = key
        self.left = None
        self.right = None
  
# Iterative Method to count full nodes of binary tree
def getfullCount(root):
    # Base Case
    if root is None:
        return 0
      
    # Create an empty queue for level order traversal
    queue = []
  
    # Enqueue Root and initialize count
    queue.append(root)
          
    count = 0 #initialize count for full nodes
    while(len(queue) > 0):
        node = queue.pop(0)
  
        # if it is full node then increment count
        if node.left is not None and node.right is not None:
            count = count+1
  
        # Enqueue left child
        if node.left is not None:
            queue.append(node.left)
  
        # Enqueue right child
        if node.right is not None:
            queue.append(node.right)
              
    return count
  
# Driver Program to test above function
root = Node(2)
root.left = Node(7)
root.right = Node(5)
root.left.right = Node(6)
root.left.right.left = Node(1)
root.left.right.right = Node(11)
root.right.right = Node(9)
root.right.right.left = Node(4)
  
  
print(getfullCount(root))

Time complexity: linear
Space complexity: linear
# Python program to count full 
# nodes in a Binary Tree
class newNode(): 
  
    def __init__(self, data): 
        self.data = data
        self.left = None
        self.right = None
          
          
# Function to get the count of  
# full Nodes in a binary tree 
def getfullCount(root):
  
    if (root == None):
        return 0
      
    res = 0
    if (root.left and root.right):
        res += 1
      
    res += (getfullCount(root.left) + 
            getfullCount(root.right)) 
    return res 
  
          
# Driver code 
if __name__ == '__main__':
    """ 2 
    / \ 
    7 5 
    \ \ 
    6 9 
    / \ / 
    1 11 4 
    Let us create Binary Tree as shown 
    """
      
    root = newNode(2) 
    root.left = newNode(7) 
    root.right = newNode(5) 
    root.left.right = newNode(6) 
    root.left.right.left = newNode(1) 
    root.left.right.right = newNode(11) 
    root.right.right = newNode(9) 
    root.right.right.left = newNode(4) 
      
    print(getfullCount(root))
  
# This code is contributed by SHUBHAMSINGH10

Time complexity: linear
Space complexity: linear
#! /usr/bin/env python3
 
# connect nodes at same level using level order traversal
import sys
 
 
class Node:
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None
        self.nextRight = None
 
    def __str__(self):
        return '{}'.format(self.data)
 
 
def printLevelByLevel(root):
    # print level by level
    if root:
        node = root
        while node:
            print('{}'.format(node.data), end=' ')
            node = node.nextRight
        print()
        if root.left:
            printLevelByLevel(root.left)
        else:
            printLevelByLevel(root.right)
 
 
def inorder(root):
    if root:
        inorder(root.left)
        print(root.data, end=' ')
        inorder(root.right)
 
 
def connect(root):
    # set nextRight of all nodes of a tree
    queue = []
    queue.append(root)
    # null marker to represent end of current level
    queue.append(None)
    # do level order of tree using None markers
    while queue:
        p = queue.pop(0)
        if p:
            # next element in queue represents
            # next node at current level
            p.nextRight = queue[0]
            # pus left and right children of current node
            if p.left:
                queue.append(p.left)
            if p.right:
                queue.append(p.right)
        else if queue:
            queue.append(None)
 
 
def main():
    """Driver program to test above functions.
        Constructed binary tree is
                10
               /  \
             8      2
            /        \
          3            90
    """
 
    root = Node(10)
    root.left = Node(8)
    root.right = Node(2)
    root.left.left = Node(3)
    root.right.right = Node(90)
 
    # Populates nextRight pointer in all nodes
    connect(root)
 
    # Let us check the values of nextRight pointers
    print("Following are populated nextRight pointers in \n"
    "the tree (-1 is printed if there is no nextRight) \n")
    if(root.nextRight != None):
        print("nextRight of %d is %d \n" %(root.data,root.nextRight.data))
    else:
        print("nextRight of %d is %d \n" %(root.data,-1))
    if(root.left.nextRight != None):
        print("nextRight of %d is %d \n" %(root.left.data,root.left.nextRight.data))
    else:
        print("nextRight of %d is %d \n" %(root.left.data,-1))
    if(root.right.nextRight != None):
        print("nextRight of %d is %d \n" %(root.right.data,root.right.nextRight.data))
    else:
        print("nextRight of %d is %d \n" %(root.right.data,-1))
    if(root.left.left.nextRight != None):
        print("nextRight of %d is %d \n" %(root.left.left.data,root.left.left.nextRight.data))
    else:
        print("nextRight of %d is %d \n" %(root.left.left.data,-1))
    if(root.right.right.nextRight != None):
        print("nextRight of %d is %d \n" %(root.right.right.data,root.right.right.nextRight.data))
    else:
        print("nextRight of %d is %d \n" %(root.right.right.data,-1))
         
    print()
 
 
if __name__ == "__main__":
    main()
 
# This code is contributed by Ram Basnet

Time complexity: linear
Space complexity: linear
# Iterative program to connect all the adjacent nodes at the same level in a binary tree
class newnode:
    def __init__(self, data):
        self.data = data
        self.left = self.right = self.nextRight = None
 
#   setting right pointer to next right node
 
#              10 ----------> NULL
#             /  \
#           8 --->2 --------> NULL
#          /
#         3 ----------------> NULL
 
 
def connect(root):
 
    # Base condition
    if root is None:
        return
 
    # Create an empty queue like level order traversal
    queue = []
    queue.append(root)
    while len(queue) != 0:
 
        # size indicates no. of nodes at current level
        size = len(queue)
 
        # for keeping track of previous node
        prev = newnode(None)
        for i in range(size):
            temp = queue.pop(0)
            if temp.left:
                queue.append(temp.left)
            if temp.right:
                queue.append(temp.right)
            if prev != None:
                prev.nextRight = temp
                prev = temp
        prev.nextRight = None
 
 
# Driver Code
if __name__ == '__main__':
 
    # Constructed binary tree is
    # 10
    #     / \
    # 8     2
    # /
    # 3
    root = newnode(10)
    root.left = newnode(8)
    root.right = newnode(2)
    root.left.left = newnode(3)
 
    # Populates nextRight pointer in all nodes
    connect(root)
 
    # Let us check the values of nextRight pointers
    print("Following are populated nextRight",
          "pointers in the tree (-1 is printed",
          "if there is no nextRight)")
    print("nextRight of", root.data, "is ", end="")
    if root.nextRight:
        print(root.nextRight.data)
    else:
        print(-1)
    print("nextRight of", root.left.data, "is ", end="")
    if root.left.nextRight:
        print(root.left.nextRight.data)
    else:
        print(-1)
    print("nextRight of", root.right.data, "is ", end="")
    if root.right.nextRight:
        print(root.right.nextRight.data)
    else:
        print(-1)
    print("nextRight of", root.left.left.data, "is ", end="")
    if root.left.left.nextRight:
        print(root.left.left.nextRight.data)
    else:
        print(-1)
 
# This code is contributed by Vivek Maddeshiya

Time complexity: linear
Space complexity: linear
# Python3 implementation to find the 
# level having Maximum number of Nodes
  
# Importing Queue
from queue import Queue 
  
# Helper class that allocates a new 
# node with the given data and None
# left and right pointers. 
class newNode:
    def __init__(self, data):
        self.data = data 
        self.left = None
        self.right = None
  
# function to find the level 
# having Maximum number of Nodes 
def maxNodeLevel(root):
    if (root == None): 
        return -1
  
    q = Queue() 
    q.put(root) 
  
    # Current level 
    level = 0
  
    # Maximum Nodes at same level 
    Max = -999999999999
  
    # Level having Maximum Nodes 
    level_no = 0
  
    while (1):
          
        # Count Nodes in a level 
        NodeCount = q.qsize() 
  
        if (NodeCount == 0):
            break
  
        # If it is Maximum till now 
        # Update level_no to current level 
        if (NodeCount > Max):
            Max = NodeCount 
            level_no = level
  
        # Pop complete current level 
        while (NodeCount > 0):
            Node = q.queue[0] 
            q.get()
            if (Node.left != None):
                q.put(Node.left) 
            if (Node.right != None): 
                q.put(Node.right) 
            NodeCount -= 1
  
        # Increment for next level 
        level += 1
  
    return level_no
  
# Driver Code
if __name__ == '__main__':
      
    # binary tree formation 
    root = newNode(2)     #     2     
    root.left     = newNode(1)     #     / \ 
    root.right     = newNode(3)     #     1     3     
    root.left.left = newNode(4)     # / \ \ 
    root.left.right = newNode(6)     # 4     6 8 
    root.right.right = newNode(8) #     /     
    root.left.right.left = newNode(5)#     5     
  
    print("Level having Maximum number of Nodes : ", 
                                 maxNodeLevel(root))
  
# This code is contributed by Pranchalk

Time complexity: linear
Space complexity: linear
# Python program to print largest value
# on each level of binary tree
 
INT_MIN = -2147483648
 
# Helper function that allocates a new
# node with the given data and None left
# and right pointers.
 
 
class newNode:
 
    # Constructor to create a new node
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None
 
# function to find largest values
 
 
def largestValueInEachLevel(root):
    if (not root):
        return
    q = []
    nc = 10
    max = 0
    q.append(root)
    while (1):
        # node count for the current level
        nc = len(q)
 
        # if true then all the nodes of
        # the tree have been traversed
        if (nc == 0):
            break
 
        # maximum element for the current
        # level
        max = INT_MIN
        while (nc):
 
            # get the front element from 'q'
            front = q[0]
 
            # remove front element from 'q'
            q = q[1:]
 
            # if true, then update 'max'
            if (max < front.data):
                max = front.data
 
            # if left child exists
            if (front.left):
                q.append(front.left)
 
            # if right child exists
            if (front.right != None):
                q.append(front.right)
            nc -= 1
 
        # print maximum element of
        # current level
        print(max, end=" ")
 
 
# Driver Code
if __name__ == '__main__':
    """ Let us construct the following Tree
        4
        / \
        9 2
    / \ \
    3 5 7 """
    root = newNode(4)
    root.left = newNode(9)
    root.right = newNode(2)
    root.left.left = newNode(3)
    root.left.right = newNode(5)
    root.right.right = newNode(7)
     
    # Function call
    largestValueInEachLevel(root)
 
# This code is contributed
# Shubham Singh(SHUBHAMSINGH10)

Time complexity: linear
Space complexity: constant
# Python3 program to find closest
# value in Binary search Tree
 
_MIN = -2147483648
_MAX = 2147483648
 
# Helper function that allocates a new
# node with the given data and None
# left and right pointers.                                    
class getnode:
 
    # Constructor to create a new node
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None
 
# utility function to return level
# of given node
def getlevel(root, data):
 
    q = []
    level = 1
    q.append(root)
 
    # extra None is appended to keep track
    # of all the nodes to be appended
    # before level is incremented by 1
    q.append(None)
    while (len(q)):
        temp = q[0]
        q.pop(0)
        if (temp == None) :
            if len(q) == 0:
                return 0
            if (q[0] != None):
                q.append(None)
            level += 1
        else :
            if (temp.data == data) :
                return level
            if (temp.left):
                q.append(temp.left)
            if (temp.right) :
                q.append(temp.right)    
    return 0
 
# Driver Code
if __name__ == '__main__':
     
    # create a binary tree
    root = getnode(20)
    root.left = getnode(10)
    root.right = getnode(30)
    root.left.left = getnode(5)
    root.left.right = getnode(15)
    root.left.right.left = getnode(12)
    root.right.left = getnode(25)
    root.right.right = getnode(40)
 
    # return level of node
    level = getlevel(root, 30)
    if level != 0:
        print("level of node 30 is", level)
    else:
        print("node 30 not found")
 
    level = getlevel(root, 12)
    if level != 0:
        print("level of node 12 is", level)
    else:
        print("node 12 not found")
         
    level = getlevel(root, 25)
    if level != 0:
        print("level of node 25 is", level)
    else:
        print("node 25 not found")
 
    level = getlevel(root, 27)
    if level != 0:
        print("level of node 27 is", level)
    else:
        print("node 27 not found")
 
# This code is contributed by
# Shubham Singh(SHUBHAMSINGH10)

Time complexity: linear
Space complexity: linear
# Python program to remove all half nodes
 
# A binary tree node
class Node:
    # Constructor for creating a new node
    def __init__(self , data):
        self.data = data
        self.left = None
        self.right = None
 
# For inorder traversal
def printInorder(root):
    if root is not None:
        printInorder(root.left)
        print (root.data,end=" ")
        printInorder(root.right)
 
# Removes all nodes with only one child and returns
# new root(note that root may change)
def RemoveHalfNodes(root):
    if root is None:
        return None
 
    # Recur to left tree
    root.left = RemoveHalfNodes(root.left)
     
    # Recur to right tree
    root.right = RemoveHalfNodes(root.right)
     
    # if both left and right child is None
    # the node is not a Half node
    if root.left is None and root.right is None:
        return root
 
    # If current nodes is a half node with left child
    # None then it's right child is returned and  
    # replaces it in the given tree
    if root.left is None:
        new_root = root.right
        temp = root
        root = None
        del(temp)
        return new_root
 
    if root.right is None:
        new_root = root.left
        temp = root
        root = None
        del(temp)
        return new_root
     
    return root
 
# Driver Program
root = Node(2)
root.left = Node(7)
root.right = Node(5)
root.left.right = Node(6)
root.left.right.left = Node(1)
root.left.right.right = Node(11)
root.right.right = Node(9)
root.right.right.left = Node(4)
 
print ("Inorder traversal of given tree")
printInorder(root)
 
NewRoot = RemoveHalfNodes(root)
 
print ("\nInorder traversal of the modified tree")
printInorder(NewRoot)
 
# This code is contributed by Nikhil Kumar Singh(nickzuck_007)

Time complexity: linear
Space complexity: constant
# Python3 program to find the length of longest
# path with same values in a binary tree.
 
# Helper function that allocates a
# new node with the given data and
# None left and right pointers.
class newNode:
  def __init__(self, data):
      self.val = data
      self.left = self.right = None
    
# Function to print the longest path
# of same values
def length(node, ans):
  if (not node):
    return 0
    
  # Recursive calls to check for subtrees
  left = length(node.left, ans)
  right = length(node.right, ans)
    
  # Variables to store maximum lengths
  # in two directions
  Leftmax = 0
  Rightmax = 0
    
  # If curr node and it's left child has same value
  if (node.left and node.left.val == node.val): 
    Leftmax += left + 1 
    
  # If curr node and it's right child has same value
  if (node.right and node.right.val == node.val):
    Rightmax += right + 1
      
  ans[0] = max(ans[0], Leftmax + Rightmax)
  return max(Leftmax, Rightmax)
    
# Driver function to find length of
# longest same value path
def longestSameValuePath(root):
  ans = [0]
  length(root, ans)
  return ans[0]
    
# Driver code
if __name__ == '__main__':
     
  # Let us construct a Binary Tree
  #      4
  #     / \
  #    4   4
  #   / \   \
  #  4   9   5
  root = None
  root = newNode(4)
  root.left = newNode(4)
  root.right = newNode(4)
  root.left.left = newNode(4)
  root.left.right = newNode(9)
  root.right.right = newNode(5)
  print(longestSameValuePath(root))
   
# This code is contributed by PranchalK

Time complexity: linear
Space complexity: logn