|
| 1 | +# Singly Linked List |
| 2 | + |
| 3 | +Singly linked lists are basic data structures that enable linking of related elements. Linked lists are not unlike arrays. They provide insertion, retrieval, updating, and removal of their elements. The elements of a linked list are referred to as 'nodes.' Each node has two properties: a value, and pointer the the next node in the list.They provide O(n) time for storage and lookup. See below for the memory implications and differences between singly and doubly linked lists. |
| 4 | + |
| 5 | +### Linked List vs. Array |
| 6 | + |
| 7 | +One major difference between linked lists and arrays are that the elements of a linked list are not stored 'contiguously' in memory as in an array. This means that elements can be inserted or removed without having to reorganize their entire structure. Conversely, linked lists do not random access to the data or efficient indexing of their elements. |
| 8 | + |
| 9 | +#### Singly linked list vs. Doubly linked list |
| 10 | +A singly linked list's nodes contain only their key (or data) and a pointer to the next node in the list. A Doubly linked list contains nodes that have a key, a pointer to the next node, and also a pointer to the previous node in the list. |
| 11 | +Doubly linked lists require more memory per node, but can provide easier manipulation than singly linked lists. |
| 12 | + |
| 13 | +In Swift, you might write a simple data structure to represent a node that holds nintegers like this: |
| 14 | + |
| 15 | +```swift |
| 16 | +class Node { |
| 17 | + var key: Int |
| 18 | + var next: Node? |
| 19 | +} |
| 20 | +``` |
| 21 | +Note the type of the 'next' property. If we are at the end of our list or if our list is empty, there is no next link. Because of this, 'next' is of type optional node. What if we want a linked list of something other than integers, or support nil-values for keys? We can make our data structure generic. |
| 22 | + |
| 23 | +```swift |
| 24 | +class Node<T> { |
| 25 | + var key: T? |
| 26 | + var next: Node<T>? |
| 27 | +} |
| 28 | +``` |
| 29 | + |
| 30 | +#### Head and Tail |
| 31 | +A linked list's first node is referred to as its 'head'. The term 'tail' can be used to refer to the last node in the list, or to all the nodes in the list after the head. |
| 32 | + |
| 33 | +To create a linked list of nodes, we create a class with a generic type. Because we'll need to compare the nodes on the basis of equality, we constrain our generic type 'T' to conform to Swift's Equatable protocol. |
| 34 | + |
| 35 | +Here is one implementation of a singly linked list in Swift: |
| 36 | + |
| 37 | +```swift |
| 38 | +class SinglyLinkedList<T: Equatable> { |
| 39 | + var head = Node<T>() |
| 40 | +} |
| 41 | +``` |
| 42 | +To support insertion of nodes to the list, we write a function that takes a key of type 'T'. |
| 43 | + |
| 44 | +```swift |
| 45 | + func addLink(key: T) { |
| 46 | + |
| 47 | + /* Check if the head's key is nil, and if so, |
| 48 | + assign it the value of the parameter passed in */ |
| 49 | + |
| 50 | + guard head.key != nil else { return head.key = key } |
| 51 | + |
| 52 | + //create local variable and initialize it with the head |
| 53 | + var current: Node? = head |
| 54 | + |
| 55 | + /* Begin while loop that finds the last node in the list and creates |
| 56 | + a new node with the value of the parameter at the end of the list */ |
| 57 | + FindEmptySpot: while current != nil { |
| 58 | + if current?.next == nil { |
| 59 | + current?.next = Node<T>(key: key) |
| 60 | + break FindEmptySpot |
| 61 | + } else { |
| 62 | + current = current?.next |
| 63 | + } |
| 64 | + } |
| 65 | + } |
| 66 | +``` |
| 67 | +Before we can write a function that removes a node by its index, we'll need to know the count of nodes in our list. We'll also include a computed property that will tell us if a list is empty. |
| 68 | + |
| 69 | +```swift |
| 70 | +var count: Int { |
| 71 | + guard head.key != nil else { return 0 } |
| 72 | + var current = head |
| 73 | + var x = 1 |
| 74 | + while let next = current.next { |
| 75 | + current = next |
| 76 | + x += 1 |
| 77 | + } |
| 78 | + return x |
| 79 | + } |
| 80 | + |
| 81 | + var isEmpty: Bool { |
| 82 | + return head.key == nil |
| 83 | + } |
| 84 | +``` |
| 85 | + |
| 86 | + |
| 87 | +To support deletion of nodes in the list, we write a function that accepts the index of the node to remove. We'll have to reorganize the nodes that surround the link that is removed. |
| 88 | + |
| 89 | +```swift |
| 90 | + func removeLinkAtIndex(index: Int) { |
| 91 | + /* Verify that the index passed as an argument to the function |
| 92 | + is >= the index of the head and <= the last node in the list. |
| 93 | + If the list is empty, we'll simply return. */ |
| 94 | + |
| 95 | + guard index >= 0 && index <= self.count - 1 && head.key != nil else { return } |
| 96 | + |
| 97 | + |
| 98 | + /* Create local variables for the current node, |
| 99 | + the trailing node, and an index */ |
| 100 | + the current node with the head node */ |
| 101 | + |
| 102 | + var current: Node<T>? = head |
| 103 | + var trailer: Node<T>? |
| 104 | + var listIndex = 0 |
| 105 | + |
| 106 | + /* If the link to be removed is the head */ |
| 107 | + if index == 0 { |
| 108 | + current = current?.next |
| 109 | + head = current?.next ?? Node<T>() |
| 110 | + return |
| 111 | + } |
| 112 | + |
| 113 | + /* Begin while loop that shuffles through the nodes in the list. |
| 114 | + When the index of the node to be removed is reached, we assign |
| 115 | + the node a nil value, and break out of the loop */ |
| 116 | + while current != nil { |
| 117 | + if listIndex == index { |
| 118 | + trailer?.next = current?.next |
| 119 | + current = nil |
| 120 | + break |
| 121 | + } |
| 122 | + trailer = current |
| 123 | + current = current?.next |
| 124 | + listIndex += 1 |
| 125 | + } |
| 126 | + } |
| 127 | +``` |
| 128 | +Linked lists are relatively simple structures, but can be used to implement other common data types like stacks and queues. It can be helpful to better understand how they differ from the Array type and what memory and efficiency implications are associated with their use. |
0 commit comments