authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-24 22:30:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-11-24 22:33:50-07:00
loge834e95d718fe3eacaec54034462c90fd10bfe76
tree8592deca9862274ce41d9b6b2ca356ad25b757b5
parent8b10970836480a43a3bbb1276cb258c2a8b613f2

Revert "std.SinglyLinkedList: add sort function"

This reverts commit 8b10970836480a43a3bbb1276cb258c2a8b613f2. This implementation has the following problems: * It does not provide context to the less than function. This will be an API break in order to fix. * It uses recursion, causing unbounded stack memory usage - likely depending on user input, which is extra problematic. * Sorting linked lists is generally an inefficient operation; encouraging it by having a standard library function for it may lead to suboptimal software being written in Zig. Furthermore, there is almost no benefit to providing a sort function as a method, when a third party implementation can easily be passed a linked list to then be sorted.

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

lib/std/linked_list.zig-83
...@@ -123,76 +123,9 @@ pub fn SinglyLinkedList(comptime T: type) type {...@@ -123,76 +123,9 @@ 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 }
189 };126 };
190}127}
191128
192fn testLessThan(left: u32, right: u32) bool {
193 return left < right;
194}
195
196test "basic SinglyLinkedList test" {129test "basic SinglyLinkedList test" {
197 const L = SinglyLinkedList(u32);130 const L = SinglyLinkedList(u32);
198 var list = L{};131 var list = L{};
...@@ -236,22 +169,6 @@ test "basic SinglyLinkedList test" {...@@ -236,22 +169,6 @@ test "basic SinglyLinkedList test" {
236 try testing.expect(list.first.?.data == 4);169 try testing.expect(list.first.?.data == 4);
237 try testing.expect(list.first.?.next.?.data == 2);170 try testing.expect(list.first.?.next.?.data == 2);
238 try testing.expect(list.first.?.next.?.next == null);171 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 }
255}172}
256173
257/// A doubly-linked list has a pair of pointers to both the head and174/// A doubly-linked list has a pair of pointers to both the head and