🎉 I'm releasing 12 products in 12 months! If you love product, checkout my new blog workingoutloud.dev

Back to home

Go Linked List

    Basic unidirectional linked lists with Golang.

    Setting up the test

    Set up linked_list_test.go with the following file:

    package linkedlist import ( "testing" ) func TestInsertFirst(t *testing.T) { for _, tt := range insertFirstTestCases { t.Log(tt.description) l := List{} l.insertFirst(&tt.input) if tt.expectedLen != l.size { t.Errorf("FAIL: Return value expected %d but got %d", tt.expectedLen, l.size) return } if tt.expectedData != l.head.data { t.Errorf("FAIL: Return value expected %d but got %d", tt.expectedData, l.head.data) return } hasNext := l.head.next != nil if tt.expectedNext != hasNext { t.Errorf("FAIL: Return value expected %d but got %d", tt.expectedData, l.head.data) return } t.Logf("PASS: Expected length %d and got %d", tt.expectedLen, l.size) t.Logf("PASS: Expected data %d and got %d", tt.expectedData, l.head.data) t.Logf("PASS: Expected data %t and got %t", tt.expectedNext, hasNext) } } func TestInsertFirstFromArray(t *testing.T) { l := List{} n1 := Node{data: 12} n2 := Node{data: 2} n3 := Node{data: 8} l.insertFirst(&n1) l.insertFirst(&n2) l.insertFirst(&n3) if &n3 != l.head { t.Errorf("FAIL: First list value expected %+v but got %+v", &n3, l.head) return } t.Logf("PASS: First list value expected %+v but got %+v", &n3, l.head) } func TestInsertLastFromArray(t *testing.T) { l := List{} n1 := Node{data: 12} n2 := Node{data: 2} n3 := Node{data: 8} l.insertLast(&n1) l.insertLast(&n2) l.insertLast(&n3) last := l.getLast() if &n3 != last { t.Errorf("FAIL: Last list value expected %+v but got %+v", &n3, l.head) return } t.Logf("PASS: Last list value expected %+v but got %+v", &n3, l.head) } func TestGetFirst(t *testing.T) { for _, tt := range getFirstTestCases { t.Log(tt.description) l := List{} l.insertFirst(&tt.input) firstNode := l.getFirst() if firstNode != &tt.input { t.Errorf("FAIL: Return value expected %+v but got %+v", &tt.input, firstNode) return } t.Logf("PASS: Expected %+v and got %+v", &tt.input, firstNode) } } func TestClearList(t *testing.T) { l := List{} n1 := Node{data: 12} n2 := Node{data: 2} n3 := Node{data: 8} l.insertLast(&n1) l.insertLast(&n2) l.insertLast(&n3) l.clear() if l.head != nil { t.Errorf("FAIL: Last list value expected nil but got %+v", l.head) return } t.Logf("PASS: Last list value expected nil and got %+v", l.head) } func TestGetNodeAtIndexOfList(t *testing.T) { l := List{} n1 := Node{data: 12} n2 := Node{data: 2} n3 := Node{data: 8} l.insertLast(&n1) l.insertLast(&n2) l.insertLast(&n3) res, err := l.getAt(1) if err != nil { t.Errorf("FAIL: Return error from GetNodeAtIndex") return } if &n2 != res { t.Errorf("FAIL: Get list value expected %+v but got %+v", &n2, res) return } t.Logf("PASS: Get list value expected %+v and got %+v", &n2, res) } func TestRemoveNodeAtIndexOfList(t *testing.T) { l := List{} n1 := Node{data: 12} n2 := Node{data: 2} n3 := Node{data: 8} l.insertLast(&n1) l.insertLast(&n2) l.insertLast(&n3) err := l.removeAt(1) res, getErr := l.getAt(1) if err != nil { t.Errorf("FAIL: Return error from GetNodeAtIndex") return } if getErr != nil { t.Errorf("FAIL: Return error from GetNodeAtIndex") return } if &n3 != res { t.Errorf("FAIL: Post-removed list value expected %+v but got %+v", &n3, res) return } t.Logf("PASS: Post-removed list value expected %+v and got %+v", &n3, res) } func TestInsertNodeAtIndexOfList(t *testing.T) { l := List{} n1 := Node{data: 12} n2 := Node{data: 2} n3 := Node{data: 8} n4 := Node{data: 123} l.insertLast(&n1) l.insertLast(&n2) l.insertLast(&n3) err := l.insertAt(1, &n4) if err != nil { t.Errorf("FAIL: Return error from GetNodeAtIndex") return } res, getErr := l.getAt(1) if getErr != nil { t.Errorf("FAIL: Return error from GetNodeAtIndex") return } if &n4 != res { t.Errorf("FAIL: Insert list value expected %+v but got %+v", &n4, res) return } t.Logf("PASS: Insert list value expected %+v and got %+v", &n4, res) }

    Trees implementation

    /* @author Dennis O'Keeffe Methods: 1. insertFirst: Insert at the head of list 2. size: Fetch size 3. getFirst: Fetch the first node 4. getLast: Fetch the last node 5. clear: Remove all node 6. removeFirst: Remove head of list 7. removeLast: Remove last node 8. insertLast: Insert at end of list 9. getAt: Fetch node at index 10. removeAt: Remove node at index 11. insertAt: Insert at index 12. forEach: Iterate through list and run function on list */ package linkedlist import ( "errors" "sync" ) // Node - Setup base node type for linked list type Node struct { data int next *Node } // List - Basic singularly linked list type List struct { head *Node size int lock sync.Mutex } func (l *List) insertFirst(n *Node) { l.lock.Lock() if l.head != nil { tmp := l.head l.head = n n.next = tmp } else { l.head = n } l.size++ l.lock.Unlock() } func (l *List) insertLast(n *Node) { l.lock.Lock() if l.head == nil { l.head = n } else { last := l.head for { if last.next == nil { break } last = last.next } last.next = n } l.size++ l.lock.Unlock() } func (l *List) getFirst() *Node { return l.head } func (l *List) getLast() *Node { l.lock.Lock() n := l.head for { if n.next == nil { break } n = n.next } l.lock.Unlock() return n } func (l *List) clear() { l.lock.Lock() l.head = nil l.lock.Unlock() } func (l *List) getAt(index int) (*Node, error) { if l.head == nil { return nil, errors.New("No elements in list") } l.lock.Lock() i := 0 n := l.head for { if i == index { break } if n.next == nil { return nil, errors.New("No elements in list") } i++ n = n.next } l.lock.Unlock() return n, nil } func (l *List) removeAt(index int) error { if l.head == nil { return errors.New("No elements at index found in list") } l.lock.Lock() n := l.head i := 0 for { if i == index-1 { tmp := n.next.next n.next = tmp break } if n.next == nil { return errors.New("Out of range") } n = n.next } l.lock.Unlock() return nil } func (l *List) insertAt(index int, node *Node) error { if l.head == nil { return errors.New("No elements at index found in list") } l.lock.Lock() n := l.head i := 0 for { if i == index-1 { tmp := n.next.next n.next = node node.next = tmp break } if n.next == nil { return errors.New("Out of range") } n = n.next } l.lock.Unlock() return nil }

    Running Tests

    In the directory, run go test.

    Personal image

    Dennis O'Keeffe

    @dennisokeeffe92
    • Melbourne, Australia

    Hi, I am a professional Software Engineer. Formerly of Culture Amp, UsabilityHub, Present Company and NightGuru.
    I am currently working on Visibuild.

    1,200+ PEOPLE ALREADY JOINED ❤️️

    Get fresh posts + news direct to your inbox.

    No spam. We only send you relevant content.

    Go Linked List

    Introduction

    Share this post