authorgravatar for 117751770+Justus2308@users.noreply.github.comJustus Klausecker <117751770+Justus2308@users.noreply.github.com> 2023-11-25 00:49:12+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-11-24 23:49:12+00:00
log8b10970836480a43a3bbb1276cb258c2a8b613f2
tree72662ed4fde4b8e033dec430586abe6d63c2b360
parenta277181c6615e40f7b2e7392958f127fd934027c
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

std.SinglyLinkedList: add sort function


1 files changed, 83 insertions(+), 0 deletions(-)

lib/std/linked_list.zig+83
...@@ -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}
128191
192fn testLessThan(left: u32, right: u32) bool {
193 return left < right;
194}
195
129test "basic SinglyLinkedList test" {196test "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}
173256
174/// A doubly-linked list has a pair of pointers to both the head and257/// A doubly-linked list has a pair of pointers to both the head and