| ... | @@ -123,9 +123,76 @@ pub fn SinglyLinkedList(comptime T: type) type { | ... | @@ -123,9 +123,76 @@ pub fn SinglyLinkedList(comptime T: type) type { |
| 123 | return 0; | 123 | return 0; |
| 124 | } | 124 | } |
| 125 | } | 125 | } |
| | 126 | |
| | 127 | /// Performs a stable in-place merge sort on the entire list. |
| | 128 | /// This operation is O(N log N) with O(1) memory (no allocator required). |
| | 129 | /// Sorts in ascending order with respect to the given `lessThan` function. |
| | 130 | /// Arguments: |
| | 131 | /// lessThanFn: Comparison function for the data of two nodes. |
| | 132 | pub fn sort( |
| | 133 | list: *Self, |
| | 134 | comptime lessThanFn: fn (left: Node.Data, right: Node.Data) bool, |
| | 135 | ) void { |
| | 136 | list.first = mergeSort(list.first, lessThanFn); |
| | 137 | } |
| | 138 | |
| | 139 | /// Performs a stable in-place merge sort on the given node and its descendants. |
| | 140 | /// This operation is O(N log N) with O(1) memory (no allocator required). |
| | 141 | /// Sorts in ascending order with respect to the given `lessThan` function. |
| | 142 | /// Arguments: |
| | 143 | /// node: Pointer to the first node of the list to sort. |
| | 144 | /// lessThanFn: Comparison function for the data of two nodes. |
| | 145 | /// Returns: |
| | 146 | /// A pointer to the first node of the sorted list. |
| | 147 | pub fn mergeSort( |
| | 148 | node: ?*Node, |
| | 149 | comptime lessThanFn: fn (left: Node.Data, right: Node.Data) bool, |
| | 150 | ) ?*Node { |
| | 151 | if (node == null or node.?.next == null) return node; |
| | 152 | |
| | 153 | // find middle of list |
| | 154 | var slow = node; |
| | 155 | var fast = node; |
| | 156 | |
| | 157 | while (fast.?.next != null and fast.?.next.?.next != null) { |
| | 158 | slow = slow.?.next; |
| | 159 | fast = fast.?.next.?.next; |
| | 160 | } |
| | 161 | |
| | 162 | // split list in half |
| | 163 | const half = slow.?.next; |
| | 164 | slow.?.next = null; |
| | 165 | |
| | 166 | // sort both halfs |
| | 167 | const left = mergeSort(node, lessThanFn); |
| | 168 | const right = mergeSort(half, lessThanFn); |
| | 169 | |
| | 170 | // merge sorted halfs |
| | 171 | return merge(left, right, lessThanFn); |
| | 172 | } |
| | 173 | fn merge( |
| | 174 | left: ?*Node, |
| | 175 | right: ?*Node, |
| | 176 | comptime lessThanFn: fn (left: Node.Data, right: Node.Data) bool, |
| | 177 | ) ?*Node { |
| | 178 | var left_ptr = left orelse return right; |
| | 179 | var right_ptr = right orelse return left; |
| | 180 | |
| | 181 | if (lessThanFn(left_ptr.data, right_ptr.data)) { |
| | 182 | left_ptr.next = merge(left_ptr.next, right_ptr, lessThanFn); |
| | 183 | return left_ptr; |
| | 184 | } else { |
| | 185 | right_ptr.next = merge(left_ptr, right_ptr.next, lessThanFn); |
| | 186 | return right_ptr; |
| | 187 | } |
| | 188 | } |
| 126 | }; | 189 | }; |
| 127 | } | 190 | } |
| 128 | | 191 | |
| | 192 | fn testLessThan(left: u32, right: u32) bool { |
| | 193 | return left < right; |
| | 194 | } |
| | 195 | |
| 129 | test "basic SinglyLinkedList test" { | 196 | test "basic SinglyLinkedList test" { |
| 130 | const L = SinglyLinkedList(u32); | 197 | const L = SinglyLinkedList(u32); |
| 131 | var list = L{}; | 198 | var list = L{}; |
| ... | @@ -169,6 +236,22 @@ test "basic SinglyLinkedList test" { | ... | @@ -169,6 +236,22 @@ test "basic SinglyLinkedList test" { |
| 169 | try testing.expect(list.first.?.data == 4); | 236 | try testing.expect(list.first.?.data == 4); |
| 170 | try testing.expect(list.first.?.next.?.data == 2); | 237 | try testing.expect(list.first.?.next.?.data == 2); |
| 171 | try testing.expect(list.first.?.next.?.next == null); | 238 | try testing.expect(list.first.?.next.?.next == null); |
| | 239 | |
| | 240 | list.prepend(&five); // {5, 4, 2} |
| | 241 | list.prepend(&one); // {1, 5, 4, 2} |
| | 242 | list.prepend(&three); // {3, 1, 5, 4, 2} |
| | 243 | |
| | 244 | list.sort(testLessThan); |
| | 245 | |
| | 246 | // Traverse forwards. |
| | 247 | { |
| | 248 | var it = list.first; |
| | 249 | var index: u32 = 1; |
| | 250 | while (it) |node| : (it = node.next) { |
| | 251 | try testing.expect(node.data == index); |
| | 252 | index += 1; |
| | 253 | } |
| | 254 | } |
| 172 | } | 255 | } |
| 173 | | 256 | |
| 174 | /// A doubly-linked list has a pair of pointers to both the head and | 257 | /// A doubly-linked list has a pair of pointers to both the head and |