master
  1//! A singly-linked list is headed by a single forward pointer. The elements
  2//! are singly-linked for minimum space and pointer manipulation overhead at
  3//! the expense of O(n) removal for arbitrary elements. New elements can be
  4//! added to the list after an existing element or at the head of the list.
  5//!
  6//! A singly-linked list may only be traversed in the forward direction.
  7//!
  8//! Singly-linked lists are useful under these conditions:
  9//! * Ability to preallocate elements / requirement of infallibility for
 10//!   insertion.
 11//! * Ability to allocate elements intrusively along with other data.
 12//! * Homogenous elements.
 13
 14const std = @import("std.zig");
 15const debug = std.debug;
 16const assert = debug.assert;
 17const testing = std.testing;
 18const SinglyLinkedList = @This();
 19
 20first: ?*Node = null,
 21
 22/// This struct contains only a next pointer and not any data payload. The
 23/// intended usage is to embed it intrusively into another data structure and
 24/// access the data with `@fieldParentPtr`.
 25pub const Node = struct {
 26    next: ?*Node = null,
 27
 28    pub fn insertAfter(node: *Node, new_node: *Node) void {
 29        new_node.next = node.next;
 30        node.next = new_node;
 31    }
 32
 33    /// Remove the node after the one provided, returning it.
 34    pub fn removeNext(node: *Node) ?*Node {
 35        const next_node = node.next orelse return null;
 36        node.next = next_node.next;
 37        return next_node;
 38    }
 39
 40    /// Iterate over the singly-linked list from this node, until the final
 41    /// node is found.
 42    ///
 43    /// This operation is O(N). Instead of calling this function, consider
 44    /// using a different data structure.
 45    pub fn findLast(node: *Node) *Node {
 46        var it = node;
 47        while (true) {
 48            it = it.next orelse return it;
 49        }
 50    }
 51
 52    /// Iterate over each next node, returning the count of all nodes except
 53    /// the starting one.
 54    ///
 55    /// This operation is O(N). Instead of calling this function, consider
 56    /// using a different data structure.
 57    pub fn countChildren(node: *const Node) usize {
 58        var count: usize = 0;
 59        var it: ?*const Node = node.next;
 60        while (it) |n| : (it = n.next) {
 61            count += 1;
 62        }
 63        return count;
 64    }
 65
 66    /// Reverse the list starting from this node in-place.
 67    ///
 68    /// This operation is O(N). Instead of calling this function, consider
 69    /// using a different data structure.
 70    pub fn reverse(indirect: *?*Node) void {
 71        if (indirect.* == null) {
 72            return;
 73        }
 74        var current: *Node = indirect.*.?;
 75        while (current.next) |next| {
 76            current.next = next.next;
 77            next.next = indirect.*;
 78            indirect.* = next;
 79        }
 80    }
 81};
 82
 83pub fn prepend(list: *SinglyLinkedList, new_node: *Node) void {
 84    new_node.next = list.first;
 85    list.first = new_node;
 86}
 87
 88/// Remove `node` from the list.
 89/// Asserts that `node` is in the list.
 90pub fn remove(list: *SinglyLinkedList, node: *Node) void {
 91    if (list.first == node) {
 92        list.first = node.next;
 93    } else {
 94        var current_elm = list.first.?;
 95        while (current_elm.next != node) {
 96            current_elm = current_elm.next.?;
 97        }
 98        current_elm.next = node.next;
 99    }
100}
101
102/// Remove and return the first node in the list.
103pub fn popFirst(list: *SinglyLinkedList) ?*Node {
104    const first = list.first orelse return null;
105    list.first = first.next;
106    return first;
107}
108
109/// Iterate over all nodes, returning the count.
110///
111/// This operation is O(N). Consider tracking the length separately rather than
112/// computing it.
113pub fn len(list: SinglyLinkedList) usize {
114    if (list.first) |n| {
115        return 1 + n.countChildren();
116    } else {
117        return 0;
118    }
119}
120
121test "basics" {
122    const L = struct {
123        data: u32,
124        node: SinglyLinkedList.Node = .{},
125    };
126    var list: SinglyLinkedList = .{};
127
128    try testing.expect(list.len() == 0);
129
130    var one: L = .{ .data = 1 };
131    var two: L = .{ .data = 2 };
132    var three: L = .{ .data = 3 };
133    var four: L = .{ .data = 4 };
134    var five: L = .{ .data = 5 };
135
136    list.prepend(&two.node); // {2}
137    two.node.insertAfter(&five.node); // {2, 5}
138    list.prepend(&one.node); // {1, 2, 5}
139    two.node.insertAfter(&three.node); // {1, 2, 3, 5}
140    three.node.insertAfter(&four.node); // {1, 2, 3, 4, 5}
141
142    try testing.expect(list.len() == 5);
143
144    // Traverse forwards.
145    {
146        var it = list.first;
147        var index: u32 = 1;
148        while (it) |node| : (it = node.next) {
149            const l: *L = @fieldParentPtr("node", node);
150            try testing.expect(l.data == index);
151            index += 1;
152        }
153    }
154
155    _ = list.popFirst(); // {2, 3, 4, 5}
156    _ = list.remove(&five.node); // {2, 3, 4}
157    _ = two.node.removeNext(); // {2, 4}
158
159    try testing.expect(@as(*L, @fieldParentPtr("node", list.first.?)).data == 2);
160    try testing.expect(@as(*L, @fieldParentPtr("node", list.first.?.next.?)).data == 4);
161    try testing.expect(list.first.?.next.?.next == null);
162
163    SinglyLinkedList.Node.reverse(&list.first);
164
165    try testing.expect(@as(*L, @fieldParentPtr("node", list.first.?)).data == 4);
166    try testing.expect(@as(*L, @fieldParentPtr("node", list.first.?.next.?)).data == 2);
167    try testing.expect(list.first.?.next.?.next == null);
168}