Exemplo n.º 1
0
class Vertex(object):
    def __init__(self, location):
        self.edges = HashTable()
        self.value = location

    # add edge to hash table: O(n)
    def add_edge(self, edge):
        self.edges.insert(edge.identifier, edge)

    # find edge from id: O(n)
    def find_edge(self, edge_id):
        return self.edges.find(edge_id)

    # find distance to a neighboring vertex: O(n)
    def distance_to(self, location):
        return self.edges.find(location.identifier).weight
def form_parametrize_delete():
    """Forming parameters for testing function delete"""
    dict_1 = {item: item ** 2 for item in range(100)}
    dict_2 = HashTable(100)
    result = []

    for i in range(100):
        dict_1.pop(i)
        dict_2.delete(str(i))
        result.append((dict_2.find(str(i)), bool(dict_1.get(i))))
    return result
Exemplo n.º 3
0
class TestHashTable(unittest.TestCase):
    def setUp(self):
        self.h_table = HashTable(17, 3)
        self.h_table.put("AA")
        self.h_table.put("Bc")
        self.h_table.put("dE")
        self.h_table.put("eD")

    def test_hash_fun(self):
        """Проверка работы хэш-функции"""
        self.assertEqual(self.h_table.hash_fun("dE"), 16)
        self.assertEqual(self.h_table.hash_fun("eD"), 16)

    def test_put(self):
        """Проверка записи значения по хэш-функции"""
        self.assertEqual(self.h_table.slots, [
            None, None, 'eD', None, None, None, None, None, None, None, None,
            'AA', 'Bc', None, None, None, 'dE'
        ])

    def test_seek_slot(self):
        """ Проверка поиска пустого слота:"""
        self.h_table = HashTable(4, 3)
        self.h_table.put("AA")
        self.h_table.put("Bc")
        self.h_table.put("dE")
        self.h_table.put("eD")
        self.assertEqual(self.h_table.seek_slot("DD"), None)

    def test_find(self):
        """ Проверка поиска элемента по значению:"""
        self.h_table = HashTable(4, 3)
        self.h_table.put("AA")
        self.h_table.put("Bc")
        self.h_table.put("dE")
        self.h_table.put("eD")
        self.assertEqual(self.h_table.seek_slot("DD"), None)

        self.assertEqual(self.h_table.find("dE"), 0)
        self.assertEqual(self.h_table.find("eD"), 3)
        self.assertEqual(self.h_table.find("DD"), None)
Exemplo n.º 4
0
def hash_table_test():
  # Create hash table
  h = HashTable()

  # Populate it
  for _ in range(100):
    h.add(random_element())
  h.add(Element('topher', 1337))

  # Print the table
  h.print()

  # Try a find
  print(h.find('topher').output())
Exemplo n.º 5
0
class Graph(object):
    def __init__(self):
        self.vertices = HashTable(20)

    # creates a vertex from a location and adds to vertex hash table: O(n)
    def add_vertex(self, location):
        self.vertices.insert(location.identifier, Vertex(location))

    # creates a bi-directional weighted edge between two vertexes in the graph: O(n)
    def add_weighted_edge(self, origin, destination, weight):
        self.vertices.find(origin.identifier).add_edge(
            Edge(destination, weight))
        self.vertices.find(destination.identifier).add_edge(
            Edge(origin, weight))

    # finds the vertex matching the location: O(n)
    def find_vertex(self, location):
        return self.vertices.find(location.identifier)

    # finds the distance between two vertexes: O(n)
    def find_distance_between(self, origin, target):
        return self.vertices.find(origin.identifier).distance_to(target)

    # finds the distance between a location and where the package needs to be delivered
    # similar to the method above but it used to sort the priority lists
    def distance_to_deliver(self, location):
        def distance_to(package):
            return self.vertices.find(location.identifier).distance_to(
                package.destination)

        return distance_to

    # creates a closure/lambda that is used to find the distances between locations
    # this is used when finding the next closest location the truck should drive to
    def distance_from(self, origin):
        def distance_to(destination):
            return self.vertices.find(
                origin.identifier).distance_to(destination)

        return distance_to
Exemplo n.º 6
0
    def run():
        graph = Graph()
        locations_hash = HashTable(20)
        packages_hash = HashTable(40)

        # loading all the location data from the csv file
        # populating a hash table and graph with the location data
        with open('location_data.csv') as csvfile:
            location_data = csv.reader(csvfile)

            # looping through location data: O(n)
            for data_row in location_data:
                location = Location(*data_row)

                # inserting location data into hash table: O(n)
                locations_hash.insert(location.identifier, location)
                locations_hash.insert(location.address, location)

                # creating graph vertexes from the location data: O(n)
                graph.add_vertex(location)

        all_packages = []
        high_priority = []
        low_priority = []

        # this section loops through all the package data and creates three lists: high and low priority, and a list of all packages
        with open('package_data.csv') as csvfile:
            package_data = csv.reader(csvfile)

            for data_row in package_data:
                package = Package(*(data_row+[locations_hash.find(data_row[1])]))

                all_packages.append(package)
                packages_hash.insert(package.identifier, package)

                # packages are divided into high or low priority lists depending on whether they have approaching deadlines or special instructions
                # append operations are O(1)
                if package.is_high_priority():
                    high_priority.append(package)
                else:
                    low_priority.append(package)

        # this loops through all the distance data between locations
        # This data is used to create edges between the vertexes in the graph
        with open('distance_data.csv') as csvfile:
            distance_data = csv.reader(csvfile)

            # Looping through each cell in the csv file: O(n^2)
            for i, data_row in enumerate(distance_data):
                for j, data in enumerate(data_row):
                    if data != '':

                        # adding a weighted edge to the graph: O(n) 
                        graph.add_weighted_edge(locations_hash.find(i),
                                                locations_hash.find(j),
                                                float(data))

        start_time = timedelta(hours=8)
        start_location = locations_hash.find(0)

        # only use two trucks. First truck will make two trips.
        trucks = [
            Truck(1, start_time, start_location),
            Truck(2, start_time, start_location)
        ]

        # list of times when trucks should wait to leave the station in order to optimize package distribution
        times_to_leave_hub = [
            timedelta(hours=8),
            timedelta(hours=9, minutes=5),
            timedelta(hours=10, minutes=20)
        ]

        # sort high and low priority lists based on their distance from the main hub: O(n*log(n))
        high_priority = sorted(high_priority, key=graph.distance_to_deliver(start_location))
        low_priority = sorted(low_priority, key=graph.distance_to_deliver(start_location))

        count = 0
        truck_idx = 0
        i = 0

        # continous loop until all packages have been delivered. Three loops in total
        while count < len(all_packages):
            truck = trucks[truck_idx]
            
            if i < len(times_to_leave_hub):
                leave_hub_at = times_to_leave_hub[i]
                truck.wait_at_hub(leave_hub_at)
            
            # filter priority lists based on which packages the given truck can deliver: O(n)
            filtered_high = [p for p in high_priority if truck.can_deliver(p)]

            # take as many high priorty packages as the truck can fit first
            for package in filtered_high:
                # appending a package to the truck list: O(1)
                truck.add_package(package)
                count += 1

                if truck.is_full():
                    break

            # if the truck isn't full yet, fill it up with nearby low priority packages
            if truck.is_full() is not True:
                filtered_low = [p for p in low_priority if truck.can_deliver(p)]
                for package in filtered_low: 
                    truck.add_package(package)
                    count += 1

                    if truck.is_full():
                        break

            # truck delivers packages using a greedy algorithm to find the most optimized path through the graph
            # Time complexity: O(n^2*log(n))
            truck.deliver_packages(graph, (len(all_packages) - count) > truck.max)
            i += 1
            truck_idx = i % len(trucks)

        def total_distance(truck):
            return truck.total_distance

        return [sum(map(total_distance, trucks)), packages_hash, all_packages]
Exemplo n.º 7
0
class Season:
    """A season, contains multiple tournaments and retains a scoreboard for
    both men and women player tracks.

    Attributes:
        circuit: The tournament circuit this season uses.
        previous: The previous season in this circuit.
        name: The name of the season.
        men_stats: Maps all male player names to their season statistics.
        women_stats: Maps all female player names to their season statistics.
        men_scoreboard: An array of male statistics for this season sorted by points.
        women_scoreboard: An array of female statistics for this season sorted by points.
    """
    def __init__(self, circuit, previous, name: str, complete: bool, men_stats,
                 women_stats, men_scoreboard, women_scoreboard):
        self.circuit = circuit
        self.previous = previous
        self.name = name
        self.complete = complete
        self.men_stats = men_stats
        self.women_stats = women_stats
        self.men_scoreboard = men_scoreboard
        self.women_scoreboard = women_scoreboard
        self.tournaments = HashTable()  # <tournament name, tournament>

    def run(self, tournament_name):
        """Runs the season, given a tournament name.

        :param tournament_name: The tournament to run.
        """
        tournament: Tournament = self.tournaments.find(tournament_name)

        if tournament is None:
            print('Starting a new tournament')

            # Check tournament type is valid.
            tournament_type = self.circuit.tournament_types.find(
                tournament_name)

            if tournament_type is None:
                print('A tournament by the name %s does not exist' %
                      tournament_name)
                return

            # Create the tournament.
            previous_tournament = None

            if self.previous is not None:
                previous_tournament = self.previous.tournaments.find(
                    tournament_name)

            tournament = Tournament(self, tournament_type, previous_tournament,
                                    False)
            tournament.men_track = self.create_track(tournament, 'men')
            tournament.women_track = self.create_track(tournament, 'women')

            self.tournaments.insert(tournament_name, tournament)
        else:
            print('Continuing tournament from saved progress')

        tournament.run()

        if len(self.tournaments) == len(self.circuit.tournament_types):
            self.complete = True
            print('Season %s has successfully complete!' % self.name)
            self.print_scoreboard('men')
            self.print_scoreboard('women')

    def create_track(self, tournament, gender):
        """Creates a new track for a given tournament and gender. Starts off
        with an empty scoreboard and mappings for the player stats.

        :param tournament: The tournament to create the track for.
        :param gender: The gender of the track to create.
        :return: The newly created track.
        """
        stats = HashTable()

        for player_name, player_profile in self.circuit.get_players(gender):
            season_stats: SeasonStats = self.get_stats(gender).find(
                player_name)
            tournament_stats = TournamentStats(player_profile, season_stats)
            season_stats.tournament_stats.insert(tournament.type.name,
                                                 tournament_stats)
            stats.insert(player_name, tournament_stats)

        winning_score = get_winning_score(gender)
        forfeit_score = get_forfeit_score(gender)

        previous_stats = None
        previous_season_scoreboard = None

        if tournament.previous is not None:
            previous_stats = tournament.previous.get_track(gender).stats
            previous_season_scoreboard = tournament.previous.season.get_scoreboard(
                gender)

        track_round = 1
        remaining = stats.clone()
        scoreboard = List()

        return Track(gender, track_round, stats, remaining, winning_score,
                     forfeit_score, scoreboard, previous_stats,
                     previous_season_scoreboard)

    def get_stats(self, gender):
        """Gets the season stat mappings for a given gender.

        :param gender: The track gender.
        :return: The stat mappings.
        """
        return self.men_stats if gender == 'men' else self.women_stats

    def get_scoreboard(self, gender):
        return self.men_scoreboard if gender == 'men' else self.women_scoreboard

    def set_scoreboard(self, gender, scoreboard):
        """Updates the scoreboard for a given gender in the season.

        :param gender: The gender of the track scoreboard to update.
        :param scoreboard: The new scoreboard to update the current with.
        """
        if gender == 'men':
            self.men_scoreboard = scoreboard
        else:
            self.women_scoreboard = scoreboard

    def print_scoreboard(self, gender):
        """Prints the scoreboard for the season, given the gender of the
        scoreboard track to print.

        :param gender: The gender of the track to use in printing the scoreboard.
        """
        print('Scoreboard for track %s in season %s' % (gender, self.name))
        rank = 1
        scoreboard = self.get_scoreboard(gender)
        for points, stats in scoreboard:
            print('#%d. %s at %.2f points' %
                  (rank, stats.player.name, stats.points))
            rank += 1