Implementing the LinkedList Data Structure in Go

3115 VIEWS

· · · ·

The Go programming language is fast and that’s why it’s a great choice for building web and cloud applications at Google and many other reputable companies. This article will teach you how to implement the LinkedList data structure in Go.

What is a LinkedList?

A LinkedList is a data structure consisting of nodes in memory, and every field stores a pointer to the following field, forming a connection to nodes of the list. The data fields aren’t in the exact memory location. But using pointers, they get to connect and reference each other just like arrays. 

LinkedList is more efficient and preferable to arrays because they can store heterogeneous data, are dynamically sized, insertion is faster, and they are memory-efficient than arrays. 

You can use a LinkedList in any language, including Go. You can use the list package that’s part of the container package in the standard library, or you can implement a custom LinkedList using Go data structures. This tutorial will teach you about the list package and how to implement custom LinkedList in Go. 

The LinkedList List Package 

The container package contains the implementation of several data structures and their algorithms in Go.

The list package, on the other hand, includes an implementation of the LinkedList data structure you can use in your Go programs. It is part of the standard library, and here’s how you can import the package:

import ( 
"container/list" 
)

You can create a new LinkedList using the New method of the list package. The New method returns a pointer to the initialized list. 

LinkedList := list.New()

You can use your LinkedList instance’s PushBack and PushFront methods to insert elements into your LinkedList. 

LinkedList.PushBack(1) 
LinkedList.PushFront(2)

The PushBack method inserts at the end of the list, and the PushFront method inserts elements at the beginning of the list. 

If you want to delete an element, you’ll need a reference to that element, and then you can use the Remove method. 

choice := LinkedList.Back() 
LinkedList.Remove(choice)

The element choice is the last entry in the LinkedList. The remove method takes only the reference, as in the example above.

You can use a loop to print the elements of the LinkedList starting from the head of the LinkedList. 

for node := LinkedList.Front(); node != nil; element = node.Next() { 
fmt.Println(element.Value) 
}

The for-loop starts from the head node to the tail and prints the values in the LinkedList if there are any.

You can learn more about the list package from the Go documentation page. Let’s see how you can implement a custom LinkedList in Go using Go’s native data structures.

Implementing a Custom LinkedList in Go 

Nodes comprise LinkedLists. The nodes are linked to one another starting from the head node, and every node holds a value and a pointer to the next node. You’ll use a struct for prototyping the node. 

type Node struct { 
data any 
next *Node 
}

The Node struct has the value field that can hold any data structure and the next field that will reference the next node. 

You’ll also need another struct to prototype the LinkedList. The struct would have a reference to the head node and the length of the LinkedList. 

type LinkedList struct { 
headNode *Node 
length int 
}

You’ll LinkedList struct is your custom LinkedList; you’ll implement functions on the LinkedList struct.

Adding Elements to the LinkedList 

The LinkedList should be able to accept any type of data structure, so the function would take in an any type. 

func (list *LinkedList) addElement(element any) { 
newNode := Node{ 
data: element, 
} 
}

The addElement function implements the LinkedList struct and takes in the element as an argument. The newNode variable is an initialization of a node to hold the element that will be inserted. Next, we place the node in the tail of the LinkedList. 

If the length of the LinkedList is zero, the new node is set as the head of the LinkedList.

if list.length == 0 { 
list.headNode = &newNode 
list.length++ 
return 
}

If there are elements in the LinkedList, the solution is to search for the node with a nil pointer and make the new node the next node using a for-loop like starting from the head node. 

else { 
currentNode := list.headNode 
for position := 0; position < list.length; position++ { 
if currentNode.next == nil { 
currentNode.next = &newNode 
list.length++ // increase the length 
return 
} 
currentNode = currentNode.next 
} 
}

You also have to increment the length of the LinkedList. The function would always add elements to the head node since it checks for the length before assignment. 

Replacing Elements in the LinkedList 

If you want to replace an element in your LinkedList, you’ll have to search for the element. You can use a for-loop to traverse the LinkedList and search for the element you want to replace. 

func (list *LinkedList) replaceElement(element, replacer any){ 
currentPosition := list.headNode 
for index := 0; index < list.length; index++ { 
if currentPosition.data == element { 
currentPosition.data = replacer 
} 
currentPosition = currentPosition.next 
} 
}

The replaceElement function takes in an element element and its replacement replacer and sets the replacement as the data in the node when the element is found. The function

Deleting Elements from the LinkedList 

If you want to delete an element, you’ll have to search for it using a for-loop and then delete it. A more efficient way would be to check if the head node is nil or it stores the value you want to delete. 

func (list *LinkedList) DeleteElement(element any) { 
currentPosition := list.headNode 
if list.length == 0 { 
return 
} 
for index := 0; index < list.length; index++ { 
if currentPosition.data == element { 
currentPosition = nil // set the position to nil 
for currentPosition.next != nil { 
currentPosition = currentPosition.next 
} 
} 
} 
list.length -= 1 
}

The DeleteElement function takes in the element you want to delete and checks if the LinkedList is empty. If the LinkedList isn’t empty, the for-loop traverses through the LinkedList in search of the element, and then when it’s found, it’s set to nil. Setting the element to nil isn’t enough because you’ll have a nil node in the middle of the LinkedList, and there should only be one nil (the tail node).

The second for-loop (nested) traverses through the LinkedList and replaces every node next to the deleted node before the deleted node so that the deleted node becomes the new tail node. 

Printing Your LinkedList 

Since your LinkedList is a struct of linked nodes, Just like the Linkedlist you created with the list package, you’ll need a for-loop to traverse through the linkedlist and print the elements. 

func (list *LinkedList) PrintList() { 
if list.length == 0 { 
fmt.Print(nil) 
} 
currentPosition := list.headNode 
for index := 0; index < list.length; index++ { 
fmt.Println(currentPosition.data) 
currentPosition = currentPosition.next 
} 
}

In the PrintList function, the if statement checks if there are elements in the LinkedList; if there is nil, the functions print nil. Suppose there are elements in the LinkedList, the for-loop prints the data in the Nodes of the LinkedList by traversing through the LinkedList. 

Interacting with the LinkedList

Now that you’ve set up your custom LinkedList and respective functions on them, the next step is initializing the LinkedList and testing your functions. 

exampleList := LinkedList{ 
headNode: nil, 
length: 0, 
}

The exampleList variable is an initialization of the LinkedList struct. The length is zero and the head node is nil since the LinkedList is empty.

func main() { 
    exampleList.addElement(4) 
    exampleList.addElement("Golang") 
    exampleList.addElement(false) 
    sampleArray := [4]int{5, 6, 3, 7} 
    exampleList.addElement(sampleArray) 
    exampleList.replaceElement(4, "200") 
    exampleList.DeleteElement(false) 
    exampleList.PrintList() 
}

In the code example, the LinkedList is populated with an integer, a boolean, an array, and a string. Then, the boolean is deleted, and the integer is replaced with a string. On printing the LinkedList using the PrintList function, here’s the output. 

Implement the LinkedList data structure

Conclusion

LinkedLists are one of the most used data structures with many applications like queues and memory management. If you need a data structure to store unrelated data of different types, you could use a LinkedList.

In this article, you learned how to use the list package of the standard library to create and use LinkedLists. You also learned how to implement the LinkedList data structure with a custom linked list and operations for the LinkedList.


Ukeje Goodness Chukwuemeriwo is a Software developer and DevOps Enthusiast writing Go code day-in day-out.


Discussion

Click on a tab to select how you'd like to leave your comment

Leave a Comment

Your email address will not be published. Required fields are marked *

Menu
Skip to toolbar