Data Structures Printing Out Values

Given the Codecademy code provided:

Exercise Link:
https://www.codecademy.com/courses/learn-data-structures-and-algorithms-with-python/lessons/learn-linked-lists-python/exercises/linked-lists-python-list-ii

My first question is why did the linked list print out the output in this reversed order from what I was expecting.

output

Output-only Terminal

Output:
90 5675 70 5

# We'll be using our Node class
class Node:
  def __init__(self, value, next_node=None):
    self.value = value
    self.next_node = next_node
    
  def get_value(self):
    return self.value
  
  def get_next_node(self):
    return self.next_node
  
  def set_next_node(self, next_node):
    self.next_node = next_node

# Our LinkedList class
class LinkedList:
  def __init__(self, value=None):
    self.head_node = Node(value)
  
  def get_head_node(self):
    return self.head_node
  
# Add your insert_beginning and stringify_list methods below:

  def insert_beginning(self, new_value):
    new_node = Node(new_value)
    new_node.set_next_node(self.head_node)
    self.head_node = new_node
    
  def stringify_list(self):
    string_list = ""
    current_node = self.get_head_node()
    while current_node:
      if current_node.get_value() != None:
        string_list += str(current_node.get_value()) + "\n"
      current_node = current_node.get_next_node()
    return string_list
  

# Test your code by uncommenting the statements below - did your list print to the terminal?
ll = LinkedList(5)
ll.insert_beginning(70)
ll.insert_beginning(5675)
ll.insert_beginning(90)
print(ll.stringify_list())

My second question is, in the code above it seems that you can create a new node that will replace the head node. How can you create a method to add it to the end node or a specific node?

And than how do you put it to the end?

Is there a way to change a middle node to the end node?

I understand the concept of orphan nodes. I understand that we would update the um… value or the pointer? I think? What would be acting as the pointer in the code above? Would it be the value?

I guess you should clarify what you were expecting.

If I insert foo, bar, baz into the head of a singly linked list in that order. I expect the traversal to then be baz, bar, foo.

You should draw to convince yourself of this, but here is an illustration.

phase 0:
<head>
Empty

phase 1:
<head>
foo

phase 2:
<head>
bar     -> foo

phase 3:
<head>
baz   -> bar -> foo

My second question is, in the code above it seems that you can create a new node that will replace the head node.

Technically you can create a method to do anything. But the method in the code you shared doesn’t replace the node object at head, it simply makes a new node be the head. The previous head is now the 2nd node in the list.

Is there a way to change a middle node to the end node?

Yes, you should verify for yourself as an exercise.

1 Like

“I guess you should clarify what you were expecting”

I was expecting that the output would be foo, bar, baz because that would be how they were created. but instead it is reversed. the first node created is sitting at the end of the linked list. why is that? shouldn’t it be in the first position? why the reversal? → “It simply makes a new node to be the head” → okay so whenever a new node is created with that method it pushes the nodes down a slot and the newly created node takes over as the new head node. Hence when it is printed out the order is reversed. Okay I think I understand that.

So basically the lesson is saying, that nodes have data and than a pointer which is the next_node attribute. We can insert nodes at the beginning or at different places by methods. If we want to remove a node, we orphan it by taking the prior node and updating the pointer to the node after we want to remove or whever it needs to go. If we want to filter out nodes with certain values we use a while loop and have python code that traversees the linked list with a while loop. The method will evaluate the head node, see if its a value that needs to be removed. if so it will update the head node to the next node that does not have that undesirable value. if the head node to start with does not have a value we want removed we use the else condition and have python evaluate the next nodes data value. if the data value is a value we want removed we update the current nodes pointer to point to the node after the node we evaluated so that the undesirable node is orphaned or not pointed to anymore.
if the node that is next in line is a node with a desirable value we simply update the current node to the sequential node and than have the next value be evaluated to see if the next node is desirable or not. we repeat the process until it is none.

very good! :slight_smile:

Thank you @toastedpitabread!

class Node:
def init(self, value, next_node=None):
self.value = value
self.next_node = next_node

def get_value(self):
return self.value

def get_next_node(self):
return self.next_node

def set_next_node(self, next_node):
self.next_node = next_node

class LinkedList:
def init(self, value=None):
self.head_node = Node(value)

def get_head_node(self):
return self.head_node

def insert_beginning(self, new_value):
new_node = Node(new_value)
new_node.set_next_node(self.head_node)
self.head_node = new_node

def stringify_list(self):
string_list = “”
current_node = self.get_head_node()
while current_node:
if current_node.get_value() != None:
string_list += str(current_node.get_value()) + “\n”
current_node = current_node.get_next_node()
return string_list

def remove_node(self, value_to_remove):
current_node = self.get_head_node()
if current_node.get_value() == value_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.set_next_node(next_node.get_next_node())
current_node = None
else:
current_node = next_node

“”"To create a method capable of removing nodes with a specific value from the linked list, we can modify the remove_node method to accept the value to be removed as a parameter. Here’s how you can implement it:

The remove_node_by_value method accepts a value_to_remove parameter.
It checks if the head node contains the value to be removed. If so, it updates the head node to skip over the removed node.
If the value to be removed is not in the head node, it traverses the linked list, looking for the node with the specified value.
Once the node with the specified value is found, it removes it by updating pointers and then exits the loop.“”"

def remove_node_by_value(self, value_to_remove):
    current_node = self.get_head_node()
    # Check if the head node needs to be removed
    if current_node.get_value() == value_to_remove:
        self.head_node = current_node.get_next_node()
    else:
        # Traverse the linked list
        while current_node:
            next_node = current_node.get_next_node()
            # Check if the next node contains the value to be removed
            if next_node.get_value() == value_to_remove:
                # Remove the next node by updating pointers
                current_node.set_next_node(next_node.get_next_node())
                break  # Exit the loop once the node is removed
            else:
                current_node = next_node

linked_list = LinkedList(“A”)
node_b = Node(“B”)
node_c = Node(“C”)
node_d = Node(“D”)

linked_list.insert_beginning(“B”)
linked_list.insert_beginning(“C”)
linked_list.insert_beginning(“D”)

print(linked_list.stringify_list())

linked_list.remove_node(“D”)
print(linked_list.stringify_list())