Lekcja – Binary Search Tree – balansowanie drzewa

from time import time, sleep

class Node:

    def __init__(self, id, data):
        self.id = id
        self.data = data
        self.left = None
        self.right = None
        self.depth = None

    def __repr__(self):
        return f"<{self.id}/{self.depth}>"


def insert(parent, child, depth=0):
    if parent is None:
        child.depth = depth
        return child
    elif parent.id == child.id:
        return parent
    elif child.id < parent.id:
        parent.left = insert(parent.left, child, parent.depth+1)
    else:
        parent.right = insert(parent.right, child, parent.depth+1)
    return parent


def load_stock_file(file_name):
    bst = None
    file = open(file_name, 'r')
    line = file.readline()
    line_number = 0

    while True: 
        line = file.readline()
        if not line:
            break
        data = line.split(',')
        line_number +=1
        #print(line_number, data[0], '/', data[1])
        node = Node(data[0], data[1])
        bst = insert(bst, node)        

    file.close()
    return bst


# https://www.nasdaq.com/market-activity/stocks/screener?exchange=NASDAQ&render=download
stock_file = './data/stock.csv'

bst = load_stock_file(stock_file)
print('Done')


def max_depth(node):
    if node is None:
        return 0
    else:
        left_depth = max_depth(node.left) + 1
        right_depth = max_depth(node.right) + 1
        return max(left_depth, right_depth)


print(f"Max depth: {max_depth(bst)}")        
print(f"Balance info: nodes on left: {max_depth(bst.left)} nodes on right: {max_depth(bst.right)}")

def count(node, delay=0):
    sleep(delay)
    if node is None:
        return 0
    else:
        left_count = count(node.left, delay)
        right_count = count(node.right, delay)
        return left_count + right_count + 1        

print(f"Count: {count(bst)}")
print(f"Balance info: nodes on left: {count(bst.left)} nodes on right: {count(bst.right)}")

# start_time = time()
# count(bst.left, 0.001)
# print(f"Operation on left {time() - start_time} s")

# start_time = time()
# count(bst.right, 0.001)
# print(f"Operation on right {time() - start_time} s")

def get_ordered_list(parent, nodes_list):
    if not parent:
        return
    get_ordered_list(parent.left,nodes_list)
    nodes_list.append(parent)
    get_ordered_list(parent.right,nodes_list)

# nodes_list = []
# get_ordered_list(bst, nodes_list)

# for node in nodes_list:
#     print(node)

def build_bst_partially(nodes_list, first_idx, last_idx, depth=0):
    if first_idx > last_idx:
        return None

    middle_idx = (first_idx + last_idx) // 2
    middle_node = nodes_list[middle_idx]
    middle_node.left = build_bst_partially(nodes_list,first_idx,middle_idx-1, depth+1)
    middle_node.right = build_bst_partially(nodes_list,middle_idx+1,last_idx, depth+1)

    middle_node.depth = depth
    return middle_node


def rebuild_bst(bst):
    nodes_list=[]
    get_ordered_list(bst,nodes_list)

    first_idx = 0
    last_idx = len(nodes_list) - 1

    return build_bst_partially(nodes_list, first_idx, last_idx)

bst = rebuild_bst(bst)
print(f"Max depth: {max_depth(bst)}")        
print(f"Balance info: nodes on left: {max_depth(bst.left)} nodes on right: {max_depth(bst.right)}")
print(f"Count: {count(bst)}")
print(f"Balance info: nodes on left: {count(bst.left)} nodes on right: {count(bst.right)}")

Lab

class City:

    def __init__(self, id, country, population):
        self.id = id
        self.country = country
        self.population = population
        self.left = None
        self.right = None
        self.depth = None

    def __repr__(self):
        return f"<{self.id}/{self.depth}>"


def insert(parent, child, depth=0):
    if parent is None:
        child.depth = depth
        return child
    elif parent.id == child.id:
        return parent
    elif child.id < parent.id:
        parent.left = insert(parent.left, child, parent.depth+1)
    else:
        parent.right = insert(parent.right, child, parent.depth+1)
    return parent


def load_file(file_name):
    bst = None
    file = open(file_name, 'r', encoding="utf-8")
    line = file.readline()
    line_number = 0

    while True: 
        line = file.readline()
        if not line:
            break
        data = line.split(',')
        line_number +=1

        city_ascii = data[1].strip().replace('"','').replace("'",'').replace("`",'').upper()
        country = data[4].replace('"','').replace("'",'').replace("`",'').upper()
        try:
            population = int(data[9].replace('"',''))
        except ValueError:
            population = -1

        node = City(city_ascii, country, population)
        bst = insert(bst, node)        

    file.close()
    return bst


# https://www.kaggle.com/juanmah/world-cities
stock_file = './data/worldcities.csv'
bst = load_file(stock_file)
print('Done')

def max_depth(node):
    if node is None:
        return 0
    else:
        left_depth = max_depth(node.left) + 1
        right_depth = max_depth(node.right) + 1
        return max(left_depth, right_depth)

def get_ordered_list(parent, nodes_list):
    if not parent:
        return
    get_ordered_list(parent.left,nodes_list)
    nodes_list.append(parent)
    get_ordered_list(parent.right,nodes_list)


def build_bst_partially(nodes_list, first_idx, last_idx, depth=0):
    if first_idx > last_idx:
        return None

    middle_idx = (first_idx + last_idx) // 2
    middle_node = nodes_list[middle_idx]
    middle_node.left = build_bst_partially(nodes_list,first_idx,middle_idx-1, depth+1)
    middle_node.right = build_bst_partially(nodes_list,middle_idx+1,last_idx, depth+1)

    middle_node.depth = depth
    return middle_node

def rebuild_bst(bst):
    nodes_list=[]
    get_ordered_list(bst,nodes_list)

    first_idx = 0
    last_idx = len(nodes_list) - 1

    return build_bst_partially(nodes_list, first_idx, last_idx)


# Inital values
print(f'Depth on left {max_depth(bst.left)+1} and on right {max_depth(bst.right)+1}')
bst = rebuild_bst(bst)
print(f'Depth on left {max_depth(bst.left)+1} and on right {max_depth(bst.right)+1}')