FAQ: Asymptotic Notation: Python - HashMaps vs. Linked Lists Runtime

This community-built FAQ covers the “HashMaps vs. Linked Lists Runtime” exercise from the lesson “Asymptotic Notation: Python”.

Paths and Courses
This exercise can be found in the following Codecademy content:

FAQs on the exercise HashMaps vs. Linked Lists Runtime

There are currently no frequently asked questions associated with this exercise – that’s where you come in! You can contribute to this section by offering your own questions, answers, or clarifications on this exercise. Ask or answer a question by clicking reply (reply) below.

If you’ve had an “aha” moment about the concepts, formatting, syntax, or anything else with this exercise, consider sharing those insights! Teaching others and answering their questions is one of the best ways to learn and stay sharp.

Join the Discussion. Help a fellow learner on their journey.

Ask or answer a question about this exercise by clicking reply (reply) below!

Agree with a comment or answer? Like (like) to up-vote the contribution!

Need broader help or resources? Head here.

Looking for motivation to keep learning? Join our wider discussions.

Learn more about how to use this guide.

Found a bug? Report it!

Have a question about your account or billing? Reach out to our customer support team!

None of the above? Find out where to ask other questions here!

Checkpoint 2 in the excersise says:

hashmap_runtime = “1”

Which I believe is wrong.
Big O stands for worst case, which would be searching for a key that is not in the HashMap. In which case we end up in infinite while loop with the existing code, because:

possible_return_value != key

Always evaluates False because possible_return_value is a list and key is a string

possible_return_value is None

Always evaluates False because our HashMap is full and we have value for every index

possible_return_value[0] == key

Alwayse evaluates False because our key is not a valid key

in place of the infinite while loop we could use

for i in range(self.array_size - 1)

with this for loop in place our big O should look like this

hashmap_runtime = “N”

Is this correct?

5 Likes

Once through N items will be O(N), as you suspect.

1 Like

Sorry if my question was not formulated correctly. The second excersise in the lesson is asking for big O for HashMap search.

  1. Through the above solution I came up with the answer “N”
  2. The excersise does not accept this as correct answer and it requires answer “1” to advance to excersise 3

Which of the two is correct and is there a bug in the excersise.

1 Like

Please post a link to this module. Thanks.

1 Like

https://www.codecademy.com/paths/computer-science/tracks/cspath-asymptotic-notation/modules/cspath-asymptotic-notation/lessons/asymptotic-notation-python/exercises/hashmaps-linkedlist-runtime

2 Likes

I haven’t taken this course, but something just occured to me… Does it take the same amount of time to retrieve a item no matter which key we poll in the HashMap? If that is the case, then it would, I believe, be O(1).

2 Likes

HashMaps use collision when assisigning key-value pairs to a list, to avoid writting different keys to same index. When collision occurs the key-value pair is written at the next list index. Without collision we will have O(1) runtime:
1)hash the key
2)compress the hash to an index
3)grab the value at index from the list

With collision we have to iterate the list so it will be O(N):
1)hash the key
2)compress the hash to index
3) if key at index matches our key return value at index
4) else add 1 to collision counter and repeat (1-3)

3 Likes

Hi
Could anyone help me understand why this code doesn’t run successfully for exercise 3 on HashMaps vs. Linked Lists Runtime:

#Get Zachary’s Disease from a Linked List
#Write Code here for Checkpoint 3
current = my_linked_list.get_head_node()
if current_value[0] == ‘Zachary’:
linked_list_zachary_disease = current_value[1]
else:
while current.get_next_node != None:
print(current.get_next_node() != None) #this is just here to show myself that this is None on the iteration where the code fails.
if current.get_next_node().get_value()[0] == ‘Zachary’:
linked_list_zachary_disease = current.get_next_node().get_value()[1]
current = current.get_next_node()

I thought the while loop would stop before I get the error:
Traceback (most recent call last):
File “script.py”, line 40, in
if current.get_next_node().get_value()[0] == ‘Zachary’:
AttributeError: ‘NoneType’ object has no attribute ‘get_value’

Any help much appreciated!

1 Like

It makes your code much more readable if you post it using proper formatting via the </> icon in the menu at the top of the text box.

As to your question, look at these three lines:

while current.get_next_node != None:
    print(current.get_next_node() != None)
    current = current.get_next_node()

Do you see anything in the second and third lines that is missing from the first?

1 Like

@patrickd314 thanks, I’ll use that formatting next time (first time posting here!)

And yes I do - that’s all working now. I can’t believe how long I stared at this without noticing that.

Thanks again!

1 Like

The HashMap of the module employs separate chaining, so big O for this HashMap’s search would not be infinite, it would be N.

However, a HashMap with O(N) isn’t much of a HashMap. That would be literally identical to employing just a Linked List. For a module comparing the runtime of a HashMap to the runtime of a Linked List, it wouldn’t be very effective if the HashMap’s hashing function boiled down to simply another Linked List.

The hashing function uses the encode() method. This will result in a very effective distribution of hash codes. On average, this will result in nearly always O(1), with some exceptions. Strictly speaking, you are correct that big O is intended to represent the worst case, but again, it’s not very meaningful to equate the runtime of a HashMap to a Linked List when the HashMap virtually never reaches the runtime of a Linked List, let alone come anywhere near it. For this purpose, we used the amortized time complexity instead, because clearly a well-designed HashMap is superior in runtime to a Linked List, and we still use big O notation despite no longer strictly representing the absolute worst case.

However, the course makes no mention of amortized time complexity, and selecting O(N) is both an honest and technically correct answer, despite being an impractical answer.

9 Likes

In the exercise, the remove_node function in linked_list.py is given as follows:

def remove_node(self, value_to_remove):
    current_node = self.head_node
    if current_node.get_value() == node_to_remove:
      self.head_node = current_node.get_next_node()
    else:
      while current_node:
        next_node = current_node.get_next_node()
        if next_node.get_value() == value_to_remove:
          current_node.next_node = next_node.get_next_node()
          current_node = None
        else:
          current_node = next_node

is it possible that the third line should be?:

if current_node.get_value() == value_to_remove:

I originally did part 3 of the exercise by removing nodes in my_linked_list. Before changing that line, I was getting the following error:

Traceback (most recent call last):
File “script.py”, line 39, in
my_linked_list.remove_node(entry)
File “/home/ccuser/workspace/asymptotic-notation-python-hashmaps-linkedlist-runtime/linkedlist.py”, line 25, in remove_node
if current_node.get_value() == node_to_remove:
NameError: name ‘node_to_remove’ is not defined

1 Like

the hashmap in this exercise does not employ separate chaining. it employs open addressing.
when a collision is found it finds a new index that is empty.

for it to employ separate chaining the hashmap would add the element to a linked list upon finding a collision

2 Likes

this will only be an infinite loop if the value passed into .retrieve() is not a valid key.

the logic “if possible_return_value[0]” relates to the list that is stored in possible return value [“Zachary”, “Sunburn sickness”]

so therefore possible return value[0] is “Zachary”

if the key entered into .retrieve() is “Zachary” the while loop will be exited.

you did find a bug in the code, however the question is asked for the runtime of the function given. which is still believe is O(N) because for the list to be O(1) the hashmap would have to retrieve the key the FIIRST time every time.
which isnt the case due to possible collisons.

if the key we are looking for collides the maximum possible times we would have O(N)

a well made hashmap should never collide the maximum of times however, but i dont believe our hashmap is made in this way

3 Likes

You’re absolutely correct! After reviewing the module again, this definitely employs open addressing. In fact, virtually nothing I said applies here. The hashing function’s encode() method is completely nullified because of the HashMap’s compressor() method. This construction results in a very ineffective distribution of hash codes, translating literally to a O(N), not O(1). Thank you for updating me. I’m not sure how I so thoroughly overlooked all of this.

4 Likes

There is a mistake on LinkedList.remove_node(), not sure if this part of the lesson.

def remove_node(self, value_to_remove):

   current_node = self.head_node

   if current_node.get_value() == node_to_remove: <------ should be "value_to_remove"

Thanks @code3482255522 for your perseverance and @mdcoulson for your clear explanations. I was also confused as to why the runtime for the hashmap was not N. Makes more sense to me now as they wanted to compare a linked list solution to a hash map solution and although the amortized runtime doesn’t apply fully here I enjoyed reading up about it and understand more now

1 Like

I agree with codesalad.

Big-O notation is for the worst case.

For inserting, the worst case in a hash map is that every single input after the first produces a collision.

For retrieving, the worst case is that every single input produced a collision, the array is full, and the item you’re retrieving is the last one to be found.

That produces a Big-O (worst case) runtime of O(N), not O(1).

I agree with codesalad.

If all entries created the same “hash” value (unlikely, but possibly), then it will have to make N comparisons at worst, until it reaches the correct ‘key’.