def tree_sort(items):
    tree = BinarySearchTree()
    print(items)
    for item in items:
        tree.insert(item)
    sorted_items = tree.items_in_order()
    print(sorted_items)
    def test_delete(self):
        items = [10, 5, 15, 3, 8, 7, 9]
        tree = BinarySearchTree()
        for item in items:
            tree.insert(item)

        tree.delete(10)
 def test_find_successor(self):
     items = [18, 1, 53, 40, 63]
     tree = BinarySearchTree(items)
     node = tree._find_node_recursive(53)
     assert tree._find_successor(node).data == 63
     tree.insert(57)
     tree.insert(98)
     assert tree._find_successor(node).data == 57
def tree_sort(items):
    '''Running time best and worst case running time: O(n log n).'''
    tree = BinarySearchTree()

    for i in items:
        tree.insert(i)

    return tree.items_in_order
示例#5
0
def read_route_costs(path):
    # routes_cost_dict = {}
    binary_search_tree = BinarySearchTree()
    for line in open(path, 'r'):
        route, cost = line.split(',')
        # routes_cost_dict[route] = cost.strip()
        pair = (route, cost)
        binary_search_tree.insert(pair)
    return binary_search_tree
示例#6
0
class Set:
    """Implements a set using BinarySearchTree"""

    __slots__ = ("data", )

    def __init__(self, it=()):
        self.data = BinarySearchTree(it)

    def add(self, elm):
        self.data.insert(elm)

    def remove(self, elm):
        self.data.delete(elm)

    def union(self, other_set):
        bigger_set = max(self, other_set, key=lambda set: set.size)
        smaller_set = min(self, other_set, key=lambda set: set.size)
        return Set(self.items() + other_set.items())

    def intersection(self, other_set):
        bigger_set = max(self, other_set, key=lambda set: set.size)
        smaller_set = min(self, other_set, key=lambda set: set.size)
        return Set(
            tuple(elm for elm in smaller_set.items()
                  if bigger_set.contains(elm)))

    def difference(self, other_set):
        res = Set()
        for elm in self.items():
            if not other_set.contains(elm):
                res.add(elm)
        return res

    def is_subset(self, other_set):
        for elm in self.items():
            if not other_set.contains(elm):
                return False
        return True

    def items(self):
        return self.data.items_in_order()

    def contains(self, elm):
        return self.data.contains(elm)

    @property
    def size(self):
        return self.data.size

    def __eq__(self, other):
        if isinstance(other, BinarySearchTree):
            return self.data == other
        elif isinstance(other, Set):
            return self.data == other.data
        else:
            raise TypeError("Can only compare with BinarySearchTree and Set")
def get_routes_data(path):
    '''Reads the file at the given path and store the routes data in a binary tree'''
    binary_tree = BinarySearchTree()
    for line in open(path, 'r'):  # Open file and read each line
        route, cost = line.split(
            ',')  # Split each line in route and cost for that route
        # We need strings because the routes should be ordered alphabetically, not on numerical value
        match_node = MatchNode(route,
                               cost)  # Store the route and cost as a pair
        binary_tree.insert(match_node)  # Insert route, cost pair into tree
    return binary_tree
示例#8
0
    def read_cost_file(self, file_name):
        opened_file = open('data/{}'.format(file_name))
        file_lines = opened_file.read().splitlines()
        binary_search_tree = BinarySearchTree()

        for line in file_lines:
            prefix, cost = line.split(',')
            item = (prefix, cost)
            binary_search_tree.insert(item)
        print(binary_search_tree)
        return binary_search_tree
示例#9
0
class CallRouter(object):
    def __init__(self, phone_numbers_unparsed, route_numbers_unparsed):
        self.phone_numbers_parsed = self.parse_phone_numbers(
            phone_numbers_unparsed)
        self.route_numbers_parsed = self.parse_route_numbers(
            route_numbers_unparsed)

        # Data Structure: Binary Search Tree of Prefixes (quick search)
        self.prefixes = BinarySearchTree()
        # Data Structure: Dictionary of prefixes and best prices (quick price fetching and price updating)
        self.best_prices = {}

    # Step 1: Turn import files into useable python objects
    def parse_phone_numbers(self, phone_numbers_unparsed):
        pass

    def parse_route_numbers(self, route_numbers_unparsed):
        # Take each line in raw data, deconstruct
        for entry in route_numbers_unparsed:
            clean_route = entry(',')
            prefix = clean_route[0]
            price = clean_route[1]
        # If not in prefix binary tree, add to binary tree and add to dictionary
            if self.prefixes.contains(prefix) == False:
                self.prefixes.insert(prefix)
                self.best_prices[prefix] = price
        # If already in prefix binary tree, update compare and update dictionary
            else:
                # If stored price is larger than new price
                if self.best_prices[prefix] > price:
                    self.best_prices[prefix] = price

    # Step 2: Find the longest matching prefix (using recursion)
    def routing_cost(self, phone_number):
        # Find the longest prefix that matches phone number
        # Note: We are always storing best prices in the parse route numbers method
        if phone_number is not None:
            if self.prefixes.contains(phone_number):
                return self.best_prices[phone_number]
            else:
                index_to_slice = len(phone_number) - 1
                return self.routing_cost(phone_number[:index_to_slice])
        else:
            return 0

    # Step 3: Record best routing costs results into a readable format
    def record_routing_costs(self, phone_numbers_parsed):
        results = []
        for phone_number in phone_numbers_parsed:
            cost = self.routing_cost(phone_number)
            line_item = "{},{}".format(phone_number, cost)
            results.append(line_item)
        print(results)
 def test_insert_with_7_items(self):
     # Create a complete binary search tree of 7 items in level-order
     items = [4, 2, 6, 1, 3, 5, 7]
     tree = BinarySearchTree()
     for item in items:
         tree.insert(item)
     assert tree.root.data == 4
     assert tree.root.left.data == 2
     assert tree.root.right.data == 6
     assert tree.root.left.left.data == 1
     assert tree.root.left.right.data == 3
     assert tree.root.right.left.data == 5
     assert tree.root.right.right.data == 7
示例#11
0
def _map_route_costs():
    """create a tree to store the prefix and cost of the routes cost"""
    with open(_path_for(file_of_costs)) as f_costs:

        # list of "+123456,0.02"
        arr_routes = f_costs.read().splitlines()

        tree_costs = BinarySearchTree()
        for a_route in arr_routes:

            # create a node with prefix, cost key-value pair
            a_route_key, a_route_cost = a_route.split(',')
            node_cost = CostNode(a_route_key, a_route_cost)

            tree_costs.insert(node_cost)

    return tree_costs
 def test_delete(self):
     tree = BinarySearchTree([2, 4])
     assert tree.height() == 1
     tree.delete(4)
     assert tree.height() == 0
     tree.delete(2)
     assert tree.height() == 0
     items = [18, 1, 53, 40, 63]
     tree.insert(10)
     tree = BinarySearchTree(items)
     tree.delete(1)
     assert tree.search(1) is None
     tree.delete(10)
     assert tree.search(10) is None
     tree.insert(57)
     tree.insert(98)
     tree.delete(63)
     assert tree.search(63) is None
class TreeSet(AbstractSet):
    def __init__(self, elements=None):
        """Initialize this binary tree with the given data."""
        self.tree = BinarySearchTree()
        if elements is not None:
            for element in elements:
                self.add(element)

    @property
    def size(self):
        """ Makes size an attribute """
        return self.tree.size

    def __repr__(self):
        """Return a string representation of this binary tree node."""
        return 'Set({!r})'.format(self.tree.items_in_order())

    def contains(self, item):
        """ Checks if item is in the set
            Time Complexity: O(logN) only grows in relation to the #node vs height
            starts fast/heavy then peeks with a lot for a long time"""
        return self.tree.contains(item)

    def add(self, item):
        """ Insert one item to the set if it doesn't already exist 
            Time complexity: O(logN) based off contains then just O(1) to add"""
        if not self.contains(item):
            self.tree.insert(item)

    def remove(self, item):
        """ Check if item exists and remove it or raise Keyerror
            Time complexity: O() """
        if self.contains(item):
            self.tree.delete(item)
        else:
            raise ValueError(item, "Is not in this set")

    def items(self):
        return self.tree.items_in_order()
 def test_size(self):
     tree = BinarySearchTree()
     assert tree.size == 0
     tree.insert('B')
     assert tree.size == 1
     tree.insert('A')
     assert tree.size == 2
     tree.insert('C')
     assert tree.size == 3
 def test_insert_with_3_items(self):
     # Create a complete binary search tree of 3 items in level-order
     tree = BinarySearchTree()
     tree.insert(2)
     assert tree.root.data == 2
     assert tree.root.left is None
     assert tree.root.right is None
     tree.insert(1)
     assert tree.root.data == 2
     assert tree.root.left.data == 1
     assert tree.root.right is None
     tree.insert(3)
     assert tree.root.data == 2
     assert tree.root.left.data == 1
     assert tree.root.right.data == 3
 def test_height(self):
     tree = BinarySearchTree([2, 1, 3])
     assert tree.height() == 1
     tree.insert(4)
     assert tree.height() == 2
示例#17
0
 def test_insert_duplicate_monotonic(self):
     bst = BinarySearchTree()
     bst.insert('A')
     assert bst.items_in_order() == ['A']
     bst.insert('A')
     assert bst.items_in_order() == ['A']
     bst.insert('B')
     assert bst.items_in_order() == ['A', 'B']
     bst.insert('C')
     assert bst.items_in_order() == ['A', 'B', 'C']
     bst.insert('A')
     assert bst.items_in_order() == ['A', 'B', 'C']
     bst.insert('B')
     assert bst.items_in_order() == ['A', 'B', 'C']
     bst.insert('C')
     assert bst.items_in_order() == ['A', 'B', 'C']
     bst.insert('D')
     assert bst.items_in_order() == ['A', 'B', 'C', 'D']
class Setree:
    def __init__(self, ls=None):
        self.tree = BinarySearchTree()
        self.size = 0
        if ls is not None:
            for item in ls:
                self.add(item)

    def add(self, item):
        '''Add an item to the set. O(log(n))'''
        if self.contains(item) is False:
            self.tree.insert(item)
            self._update_size()

    def contains(self, item):
        '''Check if set contains item. O(log(n))'''
        return self.tree.contains(item)

    def remove(self, item):
        '''Remove item from set or ValueError O(log(n))'''
        self.tree.delete(item)
        self._update_size()

    def union(self, nset):
        '''Create a new set with elements of both sets O((m+n)*log(m+n))'''
        return Setree(self.in_order() + nset.in_order())

    def intersection(self, nset):
        '''Create a new set with elements that are in both sets O(min(m,n)*log(n)*log(m))'''
        if self.size > nset.size:
            small = nset
            big = self
        else:
            big = nset
            small = self
        nnset = Setree()
        for item in small.in_order():
            if big.contains(item):
                nnset.add(item)
        return nnset

    def is_subset(self, nset):
        '''Check if each item in one set is in this set O(n*log(n)*log(m))'''
        if self.size < nset.size:
            return False
        items = nset.in_order()
        for i in items:
            if self.contains(i) is False:
                return False
        return True

    def difference(self, nset):
        '''Check for each item in this is not in another set O(m*log(n))'''
        return Setree(
            [i for i in self.in_order() if nset.contains(i) is False])

    def in_order(self):
        """returns all of the values in a set in sorted order O(m)"""
        return self.tree.items_in_order()

    def _update_size(self):
        """Updates the size."""
        self.size = self.tree.size

    def bad_balance(self):
        print('Previous height:')
        print(self._height())
        queue = LinkedQueue()
        ls = self.in_order()
        self._binary_sorter(ls, queue.enqueue)
        self.tree = BinarySearchTree()
        count = 1
        while queue.front() is not None:
            self.add(ls[queue.dequeue()])
            count += 1
        print('Balanced height:')
        print(self._height())
        print(count)

    def _binary_sorter(self, ls, visit, last=None, left=None, right=None):
        if left is None:
            left, right = 0, len(ls) - 1
        midpoint = left + ((right - left) // 2)
        if midpoint != last:
            visit(midpoint)
        if midpoint != last:
            self._binary_sorter(ls, visit, midpoint, midpoint + 1, right)
        if midpoint != last:
            self._binary_sorter(ls, visit, midpoint, left, midpoint - 1)

    def _height(self):
        return self.tree.root.height_f()
 def test_one_case(self):
     tree = BinarySearchTree()
     node = BinaryTreeNode(3)
     tree.insert(3)
     assert tree.size == 1
     assert tree._find_parent_node_recursive(3, tree.root) == None
示例#20
0
class Set:
    def __init__(self, items):
        self.set = BinarySearchTree()
        self.size = 0
        for item in items:
            self.add(item)

    def __eq__(self, other):
        return self.set.items_in_order() == other.set.items_in_order()

    def contains(self, item):
        '''Check what items are in the set'''
        return self.set.contains(item)

        # Time complexity: O(log n)

    def add(self, item):
        '''Add an item to a set'''
        if self.set.contains(item) != True:
            self.set.insert(item)
            self.size += 1

        # Time Complexity: O(log n)

    def remove(self, item):
        '''Remove item from a set'''
        return self.set.delete(item)

        # Time Complexity: O(log n)

    def union(self, other_set):
        '''Merges sets together, but removes duplicates'''
        unionset = Set(self.set.items_in_order() +
                       other_set.set.items_in_order())
        return unionset

        # Time Complexity: O(m + n)

    def intersection(self, other_set):
        '''Finds the most common elements in both sets'''
        # if item is present in self.set and other_set:
        #     return item
        intersectionitems = []
        for item in self.set.items_in_order():
            if other_set.contains(item) == True:
                intersectionitems.append(item)
        intersectionset = Set(intersectionitems)
        return intersectionset
        #check if item is in otherset using contains
        #if it is add to intersectionitems
        #create a new set out of intersectionitems and return it

    def difference(self, other_set):
        '''Checks what items are present in one set that are not present in the other'''
        differenceitems = []
        for item in self.set.items_in_order():
            if other_set.contains(item) == False:
                differenceitems.append(item)
        differenceset = Set(differenceitems)
        return differenceset

        # Time Complexity: O(m + n)

    def is_subset(self, other_set):
        '''Checks if a set is a subset of another set'''
        for item in self.set.items_in_order():
            if other_set.contains(item) == False:
                return False
        return True
    def test_height_and_size(self):
        # Let's try for a balanced tree first
        items = BinarySearchTree([4])
        assert items.height() == 0
        assert items.size == 1
        # Height 1
        items.insert(2)  # Insert item, tree grows to 1
        assert items.height() == 1
        assert items.size == 2
        items.insert(6)  # Insert item 2; level is full, tree remains 1
        assert items.height() == 1
        assert items.size == 3
        # Height 2
        items.insert(1)
        assert items.height() == 2
        assert items.size == 4
        items.insert(3)
        assert items.height() == 2
        assert items.size == 5
        items.insert(5)
        assert items.height() == 2
        assert items.size == 6
        items.insert(7)
        assert items.height() == 2
        assert items.size == 7

        # Unbalanced tree
        items = BinarySearchTree([1, 2])
        assert items.height() == 1
        assert items.size == 2
        items.insert(3)
        assert items.height() == 2
        assert items.size == 3
        items.insert(4)
        assert items.height() == 3
        assert items.size == 4
        items.insert(6)
        assert items.height() == 4
        assert items.size == 5
        items.insert(7)
        assert items.height() == 5
        assert items.size == 6
        items.insert(5)  # Let's throw a left branching for good measure
        assert items.height() == 5
        assert items.size == 7
示例#22
0
class CallRouter(object):
    def __init__(self, phone_numbers_path, route_prices_path):
          # Turn txt files (data sources) into python objects
          self.phone_numbers = self.parse_phone_numbers(phone_numbers_path)
          # Binary tree of prefixes. Using a BST allows us to find longest prefix as fast as possible
          self.prefixes = BinarySearchTree()
          # Contains best price per unique prefix. Using a dict allows quick fetch AND update
          self.prices = {}
          # Parse routes which populates self.prefixes and self.prices
          self.parse_routes(route_prices_path)

    def turn_txt_file_into_array(self, path_to_file):
        """Turns txt file into list without '\n'"""
        file = open(path_to_file, 'r')
        file_content = file.read() # string representation of .txt file
        file.close()
        array = file_content.split('\n')
        array.pop() # remove last item of array which is empty
        return array

    def parse_phone_numbers(self, phone_numbers_path):
        """Turns txt file into list of phone numbers"""
        return self.turn_txt_file_into_array(phone_numbers_path)
    
    def parse_routes(self, route_prices_path):
        """ Goes through route_prices_path and creates a binary tree """
        # Parse .txt file
        routes = self.turn_txt_file_into_array(route_prices_path)

        # For every route
        for route in routes:
            # get prefix and price (separated by a comma)
            prefix, price = route.split(',')

            if self.prefixes.contains(prefix):
                # Check if price is cheaper
                if self.prices[prefix] > price:
                    self.prices[prefix] = price
            else: # We've never seen prefix before
                self.prefixes.insert(prefix) # insert prefix into our list of prefixes
                self.prices[prefix] = price # log the cost for that prefix

    def get_routing_cost(self, phone_number):
        """Find longest matching prefix and return cheapest cost
        Since routes is a binary tree, we only remember cheapest cost for identical prefix"""
        last_digit_idx = len(str(phone_number)) - 1
        # Search for full phone number inside prefix, then remove one digit at a time
        while last_digit_idx > 0:
            substring = phone_number[0:last_digit_idx]
            if self.prefixes.contains(substring):
                return self.prices[substring]
            last_digit_idx -= 1
        
        # If we have no matching routes, return 0
        else:
            return 0
    
    def save_routing_costs(self, phone_numbers):
        result = []

        for number in phone_numbers:
            cost = self.get_routing_cost(number)
            line = "{},{}".format(number, cost)
            result.append(line)
            # save number and cost to text file
        return result
示例#23
0
    def test_delete(self):
        """
             10
           /    \
          5     15
         / \   /  \
        3  8  14  20
          / \
         7   9
        """
        items = [10, 5, 15, 20, 14, 3, 8, 7, 9]
        tree = BinarySearchTree()
        for item in items:
            tree.insert(item)

        # First Case: Node we want to remove has two children
        tree.remove(10)
        """
             20
           /    \
          5     15
         / \   /  
        3  8  14  
          / \
         7   9
        """
        assert tree.root.data == 20

        with self.assertRaises(ValueError):
            tree.remove(10)

        # Second Case: Node we want to remove has no children, we a leaf
        tree.remove(3)
        """
             20
           /    \
          5     15
           \   /  
           8  14  
          / \
         7   9
        """

        with self.assertRaises(ValueError):
            tree.remove(3)

        # Third: Node we want to remove has one child
        tree.remove(5)
        """
             20
           /    \
          8      15
         / \    /  
        7   9  14  
        """

        print(tree.items_in_order())
        tree.remove(14)
        tree.remove(15)
        tree.remove(20)

        assert tree.root.data == 8

        assert tree.root.left.data == 8
示例#24
0
class Set_Tree(object):
    def __init__(self, elements=None):
        self.tree = BinarySearchTree()
        self.size = 0
        if elements is not None:
            for element in elements:
                self.add(element)

    def __repr__(self):
        """Return a string representation of this hash table."""
        return 'Set_Tree({!r})'.format(self.tree.items_in_order())

    def __iter__(self):
        for item in self.tree.items_in_order():
            yield item

    def contains(self, element):
        '''
        Return true if this set contains the given element, False otherwise
        Time complexity: O(logn)
        Space complexity: O(logn) if recursive, O(1) if iterative
        '''
        return self.tree.contains(element)

    def add(self, element):
        '''
        Adds element to a set if it's not already in the set
        Time complexity: O(logn).O(logn)
        Space complexity: O(1)
        '''
        #if the element is not already in the set, insert it
        if not self.contains(element):  #O(logn)
            self.tree.insert(element)  #O(logn)
            self.size += 1

    def remove(self, element):
        '''
        Removes the element from the set, if it exists
        Time complexity: O(n) + O(logn) = O(n)
        Space complexity: O(n) getting the inorder item to find successor
        '''
        #delete from the set, if it's in the set
        #else raise key error
        if self.contains(element):  #O(1)
            self.tree.delete(element)  #O(n)
            self.size -= 1
        else:
            raise KeyError

    def union(self, other_set):
        '''
        Return a new set that is the union of this set and other_set
        Time complexity: O(mlogm) + O(nlogn)
        Space complexity: O(m+n)
        '''
        #create a new set with items of self
        new_set = Set_Tree(self)  #O(mlogm)
        #then add everything from other_set to new_set
        for element in other_set:  #O(n)
            new_set.add(element)  #O(logn)
        return new_set

    def intersection(self, other_set):
        '''
        Return a new set that is the intersection of this set and other_set
        Time complexity: O(mlogn).O(mlog(min(m,n)))
        Space complexity: O(log(min(m,n)))
        '''
        #create new set
        new_set = Set_Tree()  #O(1)
        ##########check to see which one is smaller####
        #for item in set1
        #if it's in set2, add it to the new_set
        for item in self:  #O(m)
            if other_set.contains(item):  #O(logn)
                new_set.add(item)  #O(log(min(m,n)))
        return new_set

    def difference(self, other_set):
        '''
        Return a new set that is the difference of this set and other_set
        Time complexity: O(mlog(mn))
        Space complexity: O(log(min(m,n)))
        '''
        #create a new set
        new_set = Set_Tree()
        #if item is in set1 but not in set2, add it
        for item in self:  #O(m)
            if not other_set.contains(
                    item):  #O(logn) #if other set doesn't contain item O(logn)
                new_set.add(item)  #O(1)
        return new_set

    def is_subset(self, other_set):
        '''
        Return a boolean indicating whether other_set is a subset of this set
        Time complexity: O(nlogm)
        Space complexity: O(n)
        '''
        if other_set.size > self.size:  #it can't be a subset if it has more items
            return False
        for element in other_set:  #O(n)
            if not self.contains(element):  #O(logm)
                return False  #not all element of set2 are in set1
        return True  #finished the loop, all elements are in set1
class Set:
    def __init__(self, elements=None):
        self.tree = BinarySearchTree()
        self.size = 0
        if elements is not None:
            for elm in elements:
                self.add(elm)

    def size(self):
        return self.tree.size

    def __iter__(self):
        return self

    def contains(self, element):
        if self.tree.contains(element):
            return True
        return False

    def add(self, element):
        if self.contains(element):
            raise ValueError("Cannot add element to Set again")
        else:
            self.tree.insert(element)
            self.size += 1

    def remove(self, element):
        self.tree.delete(element)
        self.size -= 1

    def union(self, other_set):
        """TODO: Running time: O(n*k), have to visit every node
        TODO: Memory usage: O(n+k) nodes are stored on stack"""
        result = self.tree.items_in_order()
        for elm in other_set.tree.items_in_order():
            if elm not in result:
                result.append(elm)
        return Set(result)

    def intersection(self, other_set):
        """TODO: Running time: O(n), have to visit every node
        TODO: Memory usage: O(n+k) nodes are stored on stack"""
        result = Set()
        for elm in self.tree.items_in_order():
            if other_set.contains(elm):
                result.add(elm)
        return result

    def difference(self, other_set):
        """TODO: Running time: O(n), have to visit every node
        TODO: Memory usage: O(n+k) nodes are stored on stack"""
        result = Set()
        for elm in self.tree.items_in_order():
            if not other_set.contains(elm):
                result.add(elm)
        for elm in other_set.tree.items_in_order():
            if elm in result.tree.items_in_order():
                result.remove(elm)
        return result

    def is_subset(self, other_set):
        """TODO: Running time: O(n) worst, O(1 best), have to visit every node
        TODO: Memory usage: O(n+k) nodes are stored on stack"""
        if self.size > other_set.size:
            return False

        for elm in self.tree.items_in_order():
            if not other_set.tree.contains(elm):
                return False
        return True
示例#26
0
class TreeSet:
    def __init__(self, items=None):
        self.tree = BinarySearchTree()
        if items is not None:
            for item in items:
                self.add(item)

    def __len__(self):
        return len(self.tree)

    def __contains__(self, item):
        return item in self.tree

    def __iter__(self):
        for item in self.tree.items_in_order():
            yield item

    def add(self, item):
        if item not in self.tree:
            self.tree.insert(item)

    def remove(self, item):
        self.tree.delete(item)

    def _smaller_larger_pair(self, tree_1, tree_2):
        if len(tree_1) < len(tree_2):
            return tree_1, tree_2

        return tree_2, tree_1

    def intersection(self, other_set):
        new_set = TreeSet()
        smaller, larger = self._smaller_larger_pair(self.tree, other_set.tree)
        for item in smaller.items_pre_order():
            if item in larger:
                new_set.add(item)

        return new_set

    def _alternating_generator(self, tree1, tree2):
        items_1 = tree1.items_pre_order()
        items_2 = tree2.items_pre_order()
        for item_1, item_2 in zip(items_1, items_2):
            yield item_1
            yield item_2

    def union(self, other_set):
        new_set = TreeSet()
        for item in self._alternating_generator(self.tree, other_set.tree):
            new_set.add(item)

        return new_set

    def difference(self, other_set):
        new_set = TreeSet()
        for item in self.tree.items_pre_order():
            if item not in other_set:
                new_set.add(item)

        return new_set

    def is_subset(self, other_set):
        if len(self) > len(other_set):
            return False

        for item in self.tree.items_pre_order():
            if not other_set.contains(item):
                return False

        return True
class TreeSet(object):
    """Initialize a new empty set structure, and add each element if a sequence is given"""
    def __init__(self, elements=None):
        self.tree = BinarySearchTree()
        self.element = BinaryTreeNode
        if elements is not None:
            for element in elements:
                self.add(element)

    @property
    def size(self):
        """Property that tracks the number of elements in constant time"""
        return self.tree.size

    def contains(self, element):
        """return a boolean indicating whether element is in this set
        Running time: O(log n) since we just search through a binary tree"""
        return self.tree.contains(element)

    def add(self, element):
        """add element to this set, if not present already
        Running time: O(log n) because we must binary search"""
        if self.tree.contains(element):
            raise KeyError(f'{element} is already in tree.')
        else:
            self.tree.insert(element)

    def remove(self, element):
        """remove element from this set, if present, or else raise KeyError
        Running time: 
        Best Case: O(h) because we have to either scale the tree or move everything down
        once found.
        Worst Case: O(n) because the element could be the last we check in the tree."""
        if self.tree.contains(element) != True:
            raise KeyError(f'No such element exists: {element}')
        else:
            self.tree.delete(element)

    def union(self, other_set):
        """return a new set that is the union of this set and other_set
        Best and worst case: (m + n) * log m because we add the length of each set to the time of the .add calls"""
        # m log m + n*2logm = (m + 2n) * log m =
        # (m + n) * log m
        new_set = TreeSet()
        for element in self.tree.items_pre_order():  # O(h(self))
            new_set.add(element)  # + O(m)

        # Adds remaining other_set elements
        for element in other_set.tree.items_pre_order():
            if not new_set.contains(element):  # O(log m)
                new_set.add(element)  # +O(log m)

        return new_set

    def intersection(self, other_set):
        """return a new set that is the intersection of this set and other_set
        Best case/worst case: O(log n) due to binary search"""
        new_set = TreeSet()
        for element in self.tree.items_in_order():
            if other_set.contains(element):
                new_set.add(element)
        return new_set

    def difference(self, other_set):
        """return a new set that is the difference of this set and other_set
        Best/Worst case: O(n) because we require checking all nodes"""
        new_set = TreeSet()
        for element in self.tree.items_in_order():
            new_set.add(element)

        for element in other_set.tree.items_in_order():
            if new_set.contains(element):
                new_set.remove(element)
        return new_set

    def is_subset(self, other_set):
        """return a boolean indicating whether other_set is a subset of this set
        Best case:e O(1), incase the size is bigger than other_set and we don't need to do anything.
        Worst case: O(n), if we must traverse through all nodes"""
        if self.size > other_set.size:
            return False

        for element in other_set.tree.items_in_order():
            if not self.contains(element):
                return False

        return True
示例#28
0
def tree_sort(items):
    binary_tree = BinarySearchTree()  # constant time
    for item in items:  # n iterations
        binary_tree.insert(item)  # O(n)
    print(binary_tree.items_in_order())
    binary_tree.items_in_order()
示例#29
0
class TreeSet:
    def __init__(self, elements=None):
        """initialize a new empty set structure, and add each element if a sequence is given
        size - property that tracks the number of elements in constant time"""
        self.tree = BinarySearchTree()
        self.size = 0
        if elements is not None:
            for element in elements:
                self.add(element)

    def length(self):
        return self.size

    def contains(self, element):
        """return a boolean indicating whether element is in this set"""
        if self.tree.contains(element):
            return True
        # return self.tree.contains(element) is not None
        return False

    def add(self, element):
        """add element to this set, if not present already"""
        if self.contains(element):
            raise ValueError('Cannot add element to set again: {}'.format(element))
        else:
            self.tree.insert(element)
            self.size += 1

    def remove(self, element):
        """remove element from this set, if present, or else raise KeyError"""
        self.tree.delete(element)
        self.size -= 1

    def union(self, other_set):
        """return a new set that is the union of this set and other_set"""
        union_set = self.tree.items_in_order()
        for element in other_set.tree.items_in_order():
            if element not in union_set:
                union_set.append(element)

        return TreeSet(union_set)

    def intersection(self, other_set):
        """return a new set that is the intersection of this set and other_set"""
        intersection_set = TreeSet()
        for element in self.tree.items_in_order():
            if other_set.contains(element):
                intersection_set.add(element)

        return intersection_set

    def difference(self, other_set):
        """return a new set that is the difference of this set and other_set"""
        difference_set = TreeSet()
        for element in other_set.tree.items_in_order():
            if self.tree.contains(element) is False:
                difference_set.add(element)

        for element in self.tree.items_in_order():
            if other_set.contains(element) is False:
                difference_set.add(element)


        return difference_set

    def is_subset(self, other_set):
        """return a boolean indicating whether this set is a subset of other_set"""
        if other_set.size < self.size:
            return False

        for element in self.tree.items_in_order():
            if other_set.contains(element) is False:
                return False

        return True
class TreeSet(object):
    """Class for sets implemented with binary trees"""
    def __init__(self, items=None):
        """Initialize a new Set"""
        self.tree = BinarySearchTree(items)
        # self.size = self.tree.size

    def __repr__(self):
        """Return a string representation of this set"""
        items = ['({!r})'.format(item) for item in self.tree.items_in_order()]
        return ', '.join(items)

    def __iter__(self):
        """Allow the set to be iterated over (i.e. in for loops)"""
        return iter([value for value in self.tree.items_level_order()])

    def __eq__(self, other):
        """Allow sets to be compared to other sets"""
        return self.tree.items_in_order() == other.tree.items_in_order()

    @property
    def size(self):
        """Use tree size property"""
        return self.tree.size

    def contains(self, item):
        """Return a boolean indicating whether item is in this set
        Best case time complexity: O(1) if item is in the tree root
        Worst case: O(logn) if item is a leaf
        """
        return self.tree.search(item) is not None

    def add(self, item):
        """Add the item to the set if not present
        Best case time complexity: O(1) if tree is empty
        Worst case: O(n) if tree is poorly balanced
        """
        if not self.contains(item):
            self.tree.insert(item)

    def remove(self, item):
        """Remove element from this set, if present, or else raise KeyError
        Best case time complexity: O(1) if item is in the tree root
        Worst case: O(logn) if item isn't there
        """
        if not self.contains(item):
            raise KeyError("Item not found")
        else:
            self.tree.delete(item)

    def union(self, other_set):
        """Return a new set that is the union of this set and other_set
        Best and worst case time complexity: O(n+m), where n is the size of
        self, and m is the size of other_set, because every item has to
        be accounted for
        """
        new_set = TreeSet(self)
        for item in other_set:
            new_set.add(item)
        return new_set

    def intersection(self, other_set):
        """Return a new set that is the intersection of this and other_set
        Best and worst case time complexity: O(m) where m is the size of
        other_set, because it iterates over the other set.
        """
        new_set = TreeSet()
        for item in other_set:
            if self.contains(item):
                new_set.add(item)
        return new_set

    def difference(self, other_set):
        """Return a new set that is the difference of this set and other_set
        Best and worst case time complexity: O(n + logm) where n is the size of
        self, and m is the size of other_set, because it iterates over self and
        checks if other_set contains the items
        """
        new_set = TreeSet()
        for item in self:
            if not other_set.contains(item):
                new_set.add(item)
        return new_set

    def is_subset(self, other_set):
        """Return a boolean indicating if other_set is a subset of this
        Best case time complexity: O(1) if other_set is larger than self
        Worst case: O(m) where m is the size of other_set, as it has to
        iterate over each element of it
        """
        if other_set.size > self.size:
            return False

        for item in other_set:
            if not self.contains(item):
                return False

        return True