Updating a binary tree using a pointer - swift

I'm trying to update a self-balancing binary tree. Normally, you can update it by 1) searching a node, 2) deleting it, 3) and inserting the tree with a new node. But, I want to see if this is possible simply by retaining a pointer to a node from the first step and updating it so that I can bypass the deletion and insertion and improve the time complexity, especially when it comes to a large number of nodes.
The tree itself is standard binary search tree.
public class TreeNode<T: Comparable>: Equatable {
public typealias Node = TreeNode<T>
var key: T?
var leftChild: Node?
var rightChild: Node?
fileprivate weak var parent: Node?
var isNullLeaf: Bool {
return key == nil && isLeaf
}
var isLeaf: Bool {
return rightChild == nil && leftChild == nil
}
public init(key: T?, leftChild: Node?, rightChild: Node?, parent: Node?) {
self.key = key
self.leftChild = leftChild
self.rightChild = rightChild
self.parent = parent
self.leftChild?.parent = self
self.rightChild?.parent = self
}
/// Null leaf
public convenience init() {
self.init(key: nil, leftChild: nil, rightChild: nil, parent: nil)
}
static public func == <T>(lhs: TreeNode<T>, rhs: TreeNode<T>) -> Bool {
return lhs.key == rhs.key
}
}
public final class Tree<T: Comparable> {
public typealias Node = TreeNode<T>
fileprivate(set) var root: Node
fileprivate let nullLeaf = Node()
public init() {
root = nullLeaf
}
func search(key: T, f: (inout Node) -> Void) {
search(key: key, node: &root, f: f)
}
fileprivate func search(key: T, node: inout Node, f: (inout Node) -> Void) {
if !node.isNullLeaf {
if let nodeKey = node.key {
/// When a node is found, pass by reference as an argument to a closure so that it retains the connection to the node when it's being update.
if key == nodeKey {
f(&node)
} else if key < nodeKey {
guard node.leftChild != nil else {
return
}
search(key: key, node: &node.leftChild!, f: f)
} else {
guard node.rightChild != nil else {
return
}
search(key: key, node: &node.rightChild!, f: f)
}
}
}
}
public func insert(key: T) {
/// insertion logic
}
/// Other operations
}
My idea was to search the tree through recursion and when a node is found, pass it as an argument to a closure function, which will ultimately be called to update the node. Also, the found node would be pass by reference.
class Test<T: Comparable> {
private(set) var tree = Tree<T>()
func insert(key: T) {
tree.insert(key: key)
}
func update(for node: T, with newNode: T) {
tree.search(key: node) { foundNode in
foundNode.key = newNode
}
}
}
let test = Test<MyNode>()
let node = MyNode()
let anotherNode = MyNode()
test.insert(key: node)
test.update(for: node, with: anotherNode)
The problem is the update doesn't happen. If I search for newly updated node in the tree, it doesn't exist.
Update
Above code is a modified version of a Red-Black tree, specifically modifying the search method to use a pointer instead.
I've tried my idea on a simplified version of a binary search tree below and it seems to be updating the value of a specified node.
public final class BinaryTree<T: Comparable> {
public final class Node<T> {
public var value: T
public var leftChild: Node<T>?
public var rightChild: Node<T>?
public init(value: T, leftChild: Node<T>? = nil, rightChild: Node<T>? = nil) {
self.value = value
self.leftChild = leftChild
self.rightChild = rightChild
}
}
public var rootNode: Node<T>
public init(rootNode: Node<T>) {
self.rootNode = rootNode
}
public func addNodes(to parent: Node<T>, leftChild: Node<T>?, rightChild: Node<T>?) {
parent.leftChild = leftChild
parent.rightChild = rightChild
}
public func searchTree(_ value: T, node: inout Node<T>?, f: (inout Node<T>?) -> Void) {
if node == nil || value == node?.value {
f(&node)
} else if value < node!.value {
searchTree(value, node: &node!.leftChild, f: f)
} else {
searchTree(value, node: &node!.rightChild, f: f)
}
}
}
Tested here.
var rootNode: BinaryTree<Int>.Node<Int>? = BinaryTree<Int>.Node(value: 100, leftChild: nil, rightChild: nil)
let tree = BinaryTree(rootNode: rootNode!)
/// add new nodes. This is not a self-balancing tree so the left child's value has to be smaller than the parent and the right child's value greater than the parent.
let leftChild = BinaryTree<Int>.Node(value: 0, leftChild: nil, rightChild: nil)
let rightChild = BinaryTree<Int>.Node(value: 200, leftChild: nil, rightChild: nil)
tree.addNodes(to: rootNode!, leftChild: leftChild, rightChild: rightChild)
/// the node argument is the starting point of the search so let's start from the root node.
/// the found node will be updated with a new node with a value 50
tree.searchTree(0, node: &rootNode) { foundNode in
let newNode = BinaryTree<Int>.Node(value: 50, leftChild: nil, rightChild: nil)
foundNode = newNode
}
/// The node with a value as 0 is now gone.
tree.searchTree(0, node: &rootNode) { foundNode in
print(foundNode) /// nil
}
/// The node has bee properly updated.
tree.searchTree(50, node: &rootNode) { foundNode in
print(foundNode) /// node with 50 as the value found
}
But can't seem to figure out why the original code isn't updating a node by pointer.

For me the main issue as I mentioned in the comments was with these line of code
fileprivate(set) var root: Node
fileprivate let nullLeaf = Node()
public init() {
root = nullLeaf
}
Root is currently pointing to a nullLeaf which has the following properties:
key = nil
leftChild = nil
self.rightChild = nil
self.parent = nil
I wasn't sure how your insert function was implemented but when I used my insert implementation, this updated the root's properties to the following:
key = nil
leftChild = node
self.rightChild = nil
self.parent = nil
Now when you run your search function which starts at the root:
func search(key: T, f: (inout Node) -> Void) {
search(key: key, node: &root, f: f)
}
fileprivate func search(key: T, node: inout Node, f: (inout Node) -> Void) {
if !node.isNullLeaf {
if let nodeKey = node.key {
/// When a node is found, pass by reference as an
/// argument to a closure so that it retains the
/// connection to the node when it's being update.
if key == nodeKey {
f(&node)
} else if key < nodeKey {
guard node.leftChild != nil else {
return
}
search(key: key, node: &node.leftChild!, f: f)
} else {
guard node.rightChild != nil else {
return
}
search(key: key, node: &node.rightChild!, f: f)
}
}
}
}
if let nodeKey = node.key { is false based on the above root attributes and so it does go into your block where the logic and completion handler gets executed.
Changes and Implementation
Since your main question to answer is
But can't seem to figure out why the original code isn't updating a
node by pointer.
I am using my insertion implementation of a Binary Search Tree even though you mentioned Binary Tree as the main purpose is to show the pointer working.
Here is what I updated to your code:
TreeNode - no changes to your code
// No change to your original code
public class TreeNode<T: Comparable>: Equatable {
public typealias Node = TreeNode<T>
var key: T?
var leftChild: Node?
var rightChild: Node?
fileprivate weak var parent: Node?
var isNullLeaf: Bool {
return key == nil && isLeaf
}
var isLeaf: Bool {
return rightChild == nil && leftChild == nil
}
public init(key: T?, leftChild: Node?, rightChild: Node?, parent: Node?) {
self.key = key
self.leftChild = leftChild
self.rightChild = rightChild
self.parent = parent
self.leftChild?.parent = self
self.rightChild?.parent = self
}
/// Null leaf
public convenience init() {
self.init(key: nil, leftChild: nil, rightChild: nil, parent: nil)
}
static public func == <T>(lhs: TreeNode<T>, rhs: TreeNode<T>) -> Bool {
return lhs.key == rhs.key
}
}
Tree - minor changes and some additions, I have added comments
public final class Tree<T: Comparable> {
public typealias Node = TreeNode<T>
// root starts off as nil
fileprivate(set) var root: Node?
// I don't make use of this
//fileprivate let nullLeaf = Node()
// No initialization of root
public init() {
//root = nullLeaf
}
// No change to your code except to safely evaluate root
func search(key: T, f: (inout Node) -> Void) {
if var root = root {
search(key: key, node: &root, f: f)
}
}
// No change to your code here
fileprivate func search(key: T, node: inout Node, f: (inout Node) -> Void)
{
if !node.isNullLeaf {
if let nodeKey = node.key {
/// When a node is found, pass by reference as an argument
/// to a closure so that it retains the connection to the node
/// when it's being update.
if key == nodeKey {
f(&node)
} else if key < nodeKey {
guard node.leftChild != nil else {
return
}
search(key: key, node: &node.leftChild!, f: f)
} else {
guard node.rightChild != nil else {
return
}
search(key: key, node: &node.rightChild!, f: f)
}
}
}
}
// My insert implementation
public func insert(key: T) {
if let root = insertInternal(key, currentNode: root)
{
self.root = root
}
}
// My insert recursion implementation
private func insertInternal(_ data: T, currentNode: Node?) -> Node?
{
if currentNode == nil
{
let newNode = Node()
newNode.key = data
return newNode
}
if let currentData = currentNode?.key, data > currentData
{
currentNode?.rightChild
= insertInternal(data, currentNode: currentNode?.rightChild)
return currentNode
}
currentNode?.leftChild
= insertInternal(data, currentNode: currentNode?.leftChild)
return currentNode
}
// My implementation ofLevel order / Breadth first traversal
// to display values
func printLevelOrder()
{
print("\n** PRINTING BST IN LEVEL ORDER (BFS) ** ")
var queue: [Node] = []
if let root = root
{
queue.append(root)
}
while !queue.isEmpty
{
let currentNode = queue.removeFirst()
if let currentData = currentNode.key
{
print(currentData)
if let left = currentNode.leftChild
{
queue.append(left)
}
if let right = currentNode.rightChild
{
queue.append(right)
}
}
}
}
}
Test class - no much changes
// No change to your code here except display function
class Test<T: Comparable> {
private(set) var tree = Tree<T>()
func insert(key: T) {
tree.insert(key: key)
}
func update(for node: T, with newNode: T) {
tree.search(key: node) { foundNode in
foundNode.key = newNode
}
}
// Just added a display
func display() {
tree.printLevelOrder()
}
}
Finally here is the main
Test 1 - simple with 1 node
print("Test 1")
var test = Test<Int>()
print("Inserting 10")
test.insert(key: 10)
print("Updating 10 with 8")
test.update(for: 10, with: 8)
test.display()
Output
Test 1
Inserting 10
Updating 10 with 8
** PRINTING BST IN LEVEL ORDER (BFS) **
8
As you can see the exchange of values has happened successfully with the pointer
Test 2 - a little more complex tree with many nodes
print("\n\nTest 2")
test = Test<Int>()
print("Inserting 5")
test.insert(key: 5)
print("Inserting 11")
test.insert(key: 11)
print("Inserting 4")
test.insert(key: 4)
print("Inserting 7")
test.insert(key: 7)
print("Inserting 17")
test.insert(key: 17)
print("Current tree before update")
test.display()
This should give us a binary search tree like this:
And printing the BFS traversal shows us this:
Test 2
Inserting 5
Inserting 11
Inserting 4
Inserting 7
Inserting 17
Current tree before update
** PRINTING BST IN LEVEL ORDER (BFS) **
5
4
11
7
17
Now Let's try to change the value of 7 with 16 which is done with the pointer
print("Updating 7 with 16")
test.update(for: 7, with: 16)
print("Current tree after update")
test.display()
The output is as expected with the value of 7 and swapped with 16
Updating 7 with 16
Current tree after update
** PRINTING BST IN LEVEL ORDER (BFS) **
5
4
11
16
17
Ofcourse, after this swap, the tree is no longer a Binary Search Tree but I think you can see the pointer working well with the above tweaks.

Related

How can I build a recursive function in Swift to return a String?

I have a Node class defined as follows. value: T is a String
class Node<T> {
var value: T
weak var parent: Node?
var children = [Node<T>]()
init(_ value: T) {
self.value = value
}
func add(_ node: Node<T>) {
children.append(node)
node.parent = self
}
}
I'd like to build a function to return a String of the current Node's value and all Parent values. Ideally, the function would be defined in the class. For example,
currentnode.listAllValues()
would return -> "/parent2value/parent1value/currentnodevalue"
So far the following function works with a simple print(), and I've also considered using an inout parameter.
func listAllValues(node: Node<String>) {
print(node.value)
if node.parent?.value != nil {
listAllValues(node: node.parent!)
}
}
You can achieve this with an instance method which calls itself on the parent node first, if there is one:
func listAllValues() -> String {
if let p = parent {
return "\(p.listAllValues())/\(value)"
} else {
return "/\(value)"
}
}
Or as an obfuscated one-liner:
func listAllValues() -> String {
return "\(parent?.listAllValues() ?? "")/\(value)"
}
Example:
let p2 = Node("parent2value")
let p1 = Node("parent1value") ; p2.add(p1)
let n = Node("currentNodeValue") ; p1.add(n)
print(n.listAllValues())
// --> /parent2value/parent1value/currentNodeValue
Here you go:
func desc(_ s:String? = nil) -> String {
var me = String(describing:self.value)
if let prev = s {
me += "/" + prev
}
return self.parent?.desc(me) ?? me
}
Example:
let n = Node("hey")
n.add(Node("ho"))
n.children.first?.add(Node("nonny nonny no"))
let start = n.children.first!.children.first!
print(start.desc())

Custom Index for Linked List in Swift

Custom Index Type for Linked List
Swift 5.0, Xcode 10.3
I recently implemented a doubly linked list type in Swift. When I set out to make it, my goal was to give users most of the same ease of use as using an Array, but with the algorithmic complexities associated with doubly linked lists. With this goal in mind, I decided one of the primary ways I would achieve this would be making the Node type an implementation detail; out of sight and out of mind for the user. I also decided that LinkedList must be implemented as a struct so to provide support proper immutability/mutability.
Deciding on the semantics for the LinkedList type and its private Node type was quite tricky though. This was mainly due to LinkedList being a struct and Node being a class. Because of this, whenever a copy of a LinkedList value was made, mutating the copied linked list would also mutate the initial variable. For example, under the described circumstances, this would occur:
let list1 = LinkedList([1, 2, 3])
var list2 = list1
list2.append(4) // Mutates both list1 and list2
print(list1)
// Prints "[1, 2, 3, 4]"
This was, for obvious reasons, unintended and required me to put thought into the behaviour and semantics associated with making a copy of a LinkedList and mutation thereof. To combat this, in the only two mutating defined on LinkedList that were made accessible to the user, I checked whether or not the head node of the list was known to be uniquely referenced or not. If it was, the mutation would go under way as normal. But if it wasn't, a function would create a copy of all the nodes in list before mutating them. This would prevent mutating operations on an instance of LinkedList from affecting any other instance. This check before mutation effectively implemented copy-on-write semantics for LinkedList's nodes. With this, the previous example perform as expected:
let list1 = LinkedList([1, 2, 3])
var list2 = list1
list2.append(4) // Nodes are copied
print(list1)
// Prints "[1, 2, 3]"
print(list2)
// Prints "[1, 2, 3, 4]"
This seemed to provide a fix to the problem of shared references to nodes and their mutation therein quite nicely. Unfortunately, to my chagrin, I then realized that I had not tied up all of my loose ends. This is where I am currently stuck. To this point in time, my custom index type, LinkedList.Index, has been defined as following:
extension LinkedList: Collection {
//...
public struct Index: Comparable {
fileprivate weak var node: Node?
fileprivate var offset: Int
fileprivate init(node: Node?, offset: Int) {
self.node = node
self.offset = offset
}
public static func ==(lhs: Index, rhs: Index) -> Bool {
return lhs.offset == rhs.offset
}
public static func <(lhs: Index, rhs: Index) -> Bool {
return lhs.offset < rhs.offset
}
}
}
Let me break down some of the decisions I made while constructing this... Firstly, the offset property was put in to allow for comparison with other indices and to provide the ability to check if an index was within the bounds of a list. Secondly, the node property was essential to giving each Index actual meaning and usefulness. This meant that both index(after:) and index(before:) could rely on the node property's next and previous properties to provide their respective desired indices in O(1) time. To me, this in it of itself is seems to be a requirement for an index type of a linked list implementation. Presently, I do not think there is any way to circumvent this requirement of associating each index with its respective node. In testing, I also came across a bug wherein the list's node were being copied too frequently and also not being deallocated by ARC. I realized this was because of a strong reference being held to nodes by Index. To combat that, I made node a weak reference.
Before I state the problem I am having, here is my current code for LinkedList:
public struct LinkedList<Element> {
private var headNode: Node?
private var tailNode: Node?
public private(set) var count: Int = 0
public init() { }
}
//MARK: - LinkedList Node
extension LinkedList {
fileprivate class Node {
public var value: Element
public var next: Node?
public weak var previous: Node?
public init(value: Element) {
self.value = value
}
}
}
//MARK: - Initializers
public extension LinkedList {
private init(_ nodeChain: NodeChain?) {
guard let chain = nodeChain else {
return
}
headNode = chain.head
tailNode = chain.tail
count = chain.count
}
init<S>(_ sequence: S) where S: Sequence, S.Element == Element {
if let linkedList = sequence as? LinkedList<Element> {
self = linkedList
} else {
self = LinkedList(NodeChain(of: sequence))
}
}
}
//MARK: NodeChain
extension LinkedList {
private struct NodeChain {
let head: Node!
let tail: Node!
private(set) var count: Int
// Creates a chain of nodes from a sequence. Returns `nil` if the sequence is empty.
init?<S>(of sequence: S) where S: Sequence, S.Element == Element {
var iterator = sequence.makeIterator()
guard let firstValue = iterator.next() else {
return nil
}
var currentNode = Node(value: firstValue)
head = currentNode
count = 1
while let nextElement = iterator.next() {
let nextNode = Node(value: nextElement)
currentNode.next = nextNode
nextNode.previous = currentNode
currentNode = nextNode
count += 1
}
tail = currentNode
}
}
}
//MARK: - Copy Nodes
extension LinkedList {
private mutating func copyNodes(settingNodeAt index: Index, to value: Element) {
var currentIndex = startIndex
var currentNode = Node(value: currentIndex == index ? value : currentIndex.node!.value)
let newHeadNode = currentNode
currentIndex = self.index(after: currentIndex)
while currentIndex < endIndex {
let nextNode = Node(value: currentIndex == index ? value : currentIndex.node!.value)
currentNode.next = nextNode
nextNode.previous = currentNode
currentNode = nextNode
currentIndex = self.index(after: currentIndex)
}
headNode = newHeadNode
tailNode = currentNode
}
#discardableResult
private mutating func copyNodes(removing range: Range<Index>) -> Range<Index> {
var currentIndex = startIndex
while range.contains(currentIndex) {
currentIndex = index(after: currentIndex)
}
guard let headValue = currentIndex.node?.value else {
self = LinkedList()
return endIndex..<endIndex
}
var currentNode = Node(value: headValue)
let newHeadNode = currentNode
var newCount = 1
var removedRange: Range<Index> = Index(node: currentNode, offset: 0)..<Index(node: currentNode, offset: 0)
currentIndex = index(after: currentIndex)
while currentIndex < endIndex {
guard !range.contains(currentIndex) else {
currentIndex = index(after: currentIndex)
continue
}
let nextNode = Node(value: currentIndex.node!.value)
if currentIndex == range.upperBound {
removedRange = Index(node: nextNode, offset: newCount)..<Index(node: nextNode, offset: newCount)
}
currentNode.next = nextNode
nextNode.previous = currentNode
currentNode = nextNode
newCount += 1
currentIndex = index(after: currentIndex)
}
if currentIndex == range.upperBound {
removedRange = Index(node: nil, offset: newCount)..<Index(node: nil, offset: newCount)
}
headNode = newHeadNode
tailNode = currentNode
count = newCount
return removedRange
}
}
//MARK: - Computed Properties
public extension LinkedList {
var head: Element? {
return headNode?.value
}
var tail: Element? {
return tailNode?.value
}
}
//MARK: - Sequence Conformance
extension LinkedList: Sequence {
public typealias Element = Element
public __consuming func makeIterator() -> Iterator {
return Iterator(node: headNode)
}
public struct Iterator: IteratorProtocol {
private var currentNode: Node?
fileprivate init(node: Node?) {
currentNode = node
}
public mutating func next() -> Element? {
guard let node = currentNode else {
return nil
}
currentNode = node.next
return node.value
}
}
}
//MARK: - Collection Conformance
extension LinkedList: Collection {
public var startIndex: Index {
return Index(node: headNode, offset: 0)
}
public var endIndex: Index {
return Index(node: nil, offset: count)
}
public var first: Element? {
return head
}
public var isEmpty: Bool {
return count == 0
}
public func index(after i: Index) -> Index {
precondition(i.offset != endIndex.offset, "LinkedList index is out of bounds")
return Index(node: i.node?.next, offset: i.offset + 1)
}
public struct Index: Comparable {
fileprivate weak var node: Node?
fileprivate var offset: Int
fileprivate init(node: Node?, offset: Int) {
self.node = node
self.offset = offset
}
public static func ==(lhs: Index, rhs: Index) -> Bool {
return lhs.offset == rhs.offset
}
public static func <(lhs: Index, rhs: Index) -> Bool {
return lhs.offset < rhs.offset
}
}
}
//MARK: - MutableCollection Conformance
extension LinkedList: MutableCollection {
public subscript(position: Index) -> Element {
get {
precondition(position.offset != endIndex.offset, "Index out of range")
guard let node = position.node else {
preconditionFailure("LinkedList index is invalid")
}
return node.value
}
set {
precondition(position.offset != endIndex.offset, "Index out of range")
// Copy-on-write semantics for nodes
if !isKnownUniquelyReferenced(&headNode) {
copyNodes(settingNodeAt: position, to: newValue)
} else {
position.node?.value = newValue
}
}
}
}
//MARK: LinkedList Specific Operations
public extension LinkedList {
mutating func prepend(_ newElement: Element) {
replaceSubrange(startIndex..<startIndex, with: CollectionOfOne(newElement))
}
mutating func prepend<S>(contentsOf newElements: __owned S) where S: Sequence, S.Element == Element {
replaceSubrange(startIndex..<startIndex, with: newElements)
}
#discardableResult
mutating func popFirst() -> Element? {
if isEmpty {
return nil
}
return removeFirst()
}
#discardableResult
mutating func popLast() -> Element? {
guard isEmpty else {
return nil
}
return removeLast()
}
}
//MARK: - BidirectionalCollection Conformance
extension LinkedList: BidirectionalCollection {
public var last: Element? {
return tail
}
public func index(before i: Index) -> Index {
precondition(i.offset != startIndex.offset, "LinkedList index is out of bounds")
if i.offset == count {
return Index(node: tailNode, offset: i.offset - 1)
}
return Index(node: i.node?.previous, offset: i.offset - 1)
}
}
//MARK: - RangeReplaceableCollection Conformance
extension LinkedList: RangeReplaceableCollection {
public mutating func append<S>(contentsOf newElements: __owned S) where S: Sequence, Element == S.Element {
replaceSubrange(endIndex..<endIndex, with: newElements)
}
public mutating func replaceSubrange<S, R>(_ subrange: R, with newElements: __owned S) where S: Sequence, R: RangeExpression, Element == S.Element, Index == R.Bound {
var range = subrange.relative(to: indices)
precondition(range.lowerBound >= startIndex && range.upperBound <= endIndex, "Subrange bounds are out of range")
// If range covers all elements and the new elements are a LinkedList then set references to it
if range.lowerBound == startIndex, range.upperBound == endIndex, let linkedList = newElements as? LinkedList {
self = linkedList
return
}
var newElementsCount = 0
// There are no new elements, so range indicates deletion
guard let nodeChain = NodeChain(of: newElements) else {
// If there is nothing in the removal range
// This also covers the case that the linked list is empty because this is the only possible range
guard range.lowerBound != range.upperBound else {
return
}
// Deletion range spans all elements
if range.lowerBound == startIndex && range.upperBound == endIndex {
headNode = nil
tailNode = nil
count = 0
return
}
// Copy-on-write semantics for nodes and remove elements in range
guard isKnownUniquelyReferenced(&headNode) else {
copyNodes(removing: range)
return
}
// Update count after mutation to preserve startIndex and endIndex validity
defer {
count = count - (range.upperBound.offset - range.lowerBound.offset)
}
// Move head up if deletion starts at start index
if range.lowerBound == startIndex {
// Can force unwrap node since the upperBound is not the end index
headNode = range.upperBound.node!
headNode!.previous = nil
// Move tail back if deletion ends at end index
} else if range.upperBound == endIndex {
// Can force unwrap since lowerBound index must have an associated element
tailNode = range.lowerBound.node!.previous
tailNode!.next = nil
// Deletion range is in the middle of the linked list
} else {
// Can force unwrap all bound nodes since they both must have elements
range.upperBound.node!.previous = range.lowerBound.node!.previous
range.lowerBound.node!.previous!.next = range.upperBound.node!
}
return
}
// Obtain the count of the new elements from the node chain composed from them
newElementsCount = nodeChain.count
// Replace entire content of list with new elements
if range.lowerBound == startIndex && range.upperBound == endIndex {
headNode = nodeChain.head
tailNode = nodeChain.tail
count = nodeChain.count
return
}
// Copy-on-write semantics for nodes before mutation
if !isKnownUniquelyReferenced(&headNode) {
range = copyNodes(removing: range)
}
// Update count after mutation to preserve startIndex and endIndex validity
defer {
count += nodeChain.count - (range.upperBound.offset - range.lowerBound.offset)
}
// Prepending new elements
guard range.upperBound != startIndex else {
headNode?.previous = nodeChain.tail
nodeChain.tail.next = headNode
headNode = nodeChain.head
return
}
// Appending new elements
guard range.lowerBound != endIndex else {
tailNode?.next = nodeChain.head
nodeChain.head.previous = tailNode
tailNode = nodeChain.tail
return
}
if range.lowerBound == startIndex {
headNode = nodeChain.head
}
if range.upperBound == endIndex {
tailNode = nodeChain.tail
}
range.lowerBound.node!.previous!.next = nodeChain.head
range.upperBound.node!.previous = nodeChain.tail
}
}
//MARK: - ExpressibleByArrayLiteral Conformance
extension LinkedList: ExpressibleByArrayLiteral {
public typealias ArrayLiteralElement = Element
public init(arrayLiteral elements: ArrayLiteralElement...) {
self.init(elements)
}
}
//MARK: - CustomStringConvertible Conformance
extension LinkedList: CustomStringConvertible {
public var description: String {
return "[" + lazy.map { "\($0)" }.joined(separator: ", ") + "]"
}
}
Note: if/when I do update my code, the up-to-date version can be found here.
My Problem
The current problem I am experiencing is with Index instances. When an index is provided either to a method, as is the case currently, the method has no way of knowing and checking whether or not that index/node belongs to that specific LinkedList instance. That allows for bugs such as this:
let immutableList: LinkedList = [1, 2, 3, 4]
var mutableList: LinkedList = [5, 6, 7, 8]
let immutableIndex = immutableList.index(after: immutableList.startIndex)
mutableList[immutableIndex] = 0
print("Immutable List:", immutableList)
print("Mutable List:", mutableList)
// Prints:
// Immutable List: [1, 0, 3, 4]
// Mutable List: [5, 6, 7, 8]
All methods that deal with Index must have a way to confirm that the index they are dealing with contains a node owned by the current LinkedList instance, though I have no idea how I would be able to do this.
Furthermore, indices' offset invalidate after mutation to their node's parent list, thus causing absurd situations like this wherein the indices are said to be equal:
var list: LinkedList = [1, 2, 3, 4]
let idx1 = list.index(list.startIndex, offsetBy: 2) // Index to node with value of 3 and offset of 2
list.remove(at: list.index(before: idx1))
print(list)
// Prints: "[1, 3, 4]"
let idx2 = list.index(before: list.endIndex) // Index to node with value of 4 and offset of 2
print(idx1 == idx2)
// Prints: "true"
print(Array(list[idx1...idx2]))
// Prints: "[3]"
In the previous example, because, upon mutation of a LinkedList, instances of its indices' offsets are not updated, though they still have a weak reference to their associated node, many unintended consequences and incorrect behaviour can arise.
When creating the Index type initially, I was hard pressed to find similar examples to mine online and as a result I am not totally sure whether things like startIndex and endIndex and how index(before:) and index(after:) handle them are the optimal/proper way. I am looking for input on how I can go about fixing all of these problems brought on by LinkedList.Index and properly implement it. Any and all input is appreciated!
Let's address the second problem first:
Furthermore, indices' offset invalidate after mutation to their node's parent list, thus causing absurd situations ...
That is to be expected with all collections. From Collections:
Saved indices may become invalid as a result of mutating operations.
Using an invalidated index is undefined behavior, and anything can happen: An unexpected result, a fatal error, ... Here is a simple example for Swift strings:
var s = "a🇩🇪bcd"
let i = s.firstIndex(of: "🇩🇪")!
s.remove(at: s.startIndex) // invalidates `i`
s.remove(at: i)
print(s) // \360cd
Now the first (main?) problem:
... the method has no way of knowing and checking whether or not that index/node belongs to that specific LinkedList instance.
Quoting from Collections again:
You can pass only valid indices to collection operations. You can find a complete set of a collection’s valid indices by starting with the collection’s startIndex property and finding every successor up to, and including, the endIndex property. All other values of the Index type, such as the startIndex property of a different collection, are invalid indices for this collection.
In your case
mutableList[immutableIndex] = 0
immutableIndex is not a valid index for mutableList, so this is again undefined behavior. A user of your library can not expect that this does anything sensible.
A possible way to protect against this misuse could be to store in the LinkedList.Index a (weak) pointer to the head node of the linked list, and verify that owner in the accessor methods (subscripts).

declare generic class with a generic class as a parameter in swift

I wrote these simple generic classes and it worked great:
class LinkedListNode <T> {
var value: T
var next: LinkedListNode<T>?
weak var prev: LinkedListNode<T>?
init(value: T) {
self.value = value
self.next = nil
}
}
class LinkedList<T> {
var first: LinkedListNode<T>? = nil
var last: LinkedListNode<T>? = nil
var count = 0
#discardableResult func append(_ value: T) -> LinkedListNode<T> {
let new = LinkedListNode(value: value)
new.prev = last
last?.next = new
count += 1
last = new
if first == nil {
first = new
}
return new
}
}
And I used it like:
let list = LinkedList<Int>()
list.append(3)
let lastNode = list.append(5)
Now I realized there are some cases when I need to have a customized node: CustomNode<T>, subclass of LinkedListNode<T>. So I would like to be able to pass the class to be used as the node as:
let list = LinkedList<CustomNode<Int>>()
list.append(3)
let customNode = list.append(5)
How can I declare my class to have it like this or something similar?
I have tried the following declaration but weird errors rise. Is this even possible?
class LinkedList<Node<T>: LinkedListNode<T>> { ...
Update 2019/07/26.
Even with Kamran's approach this method does not compile. I am not sure if this is doable without a protocol. See my comment on Kamran's answer.
func remove(node: LinkedListNode<T>) { // change to `func remove(node: U)`
node.next?.prev = node.prev
node.prev?.next = node.next
if node === first {
first = first?.next
}
if node === last {
last = last?.prev // Error here: "Cannot assign value of LinkedListNode<T>? to U?"
}
}
The syntax you are trying can be achieved as below,
class LinkedListNode <T> {
var value: T
var next: LinkedListNode<T>?
weak var prev: LinkedListNode<T>?
required init(value: T) {
self.value = value
self.next = nil
}
}
class GenericCustomNode<T>: LinkedListNode<T> {
required init(value: T) {
super.init(value: value)
}
}
class NonGenericCustomNode: LinkedListNode<Int> {
required init(value: Int) {
super.init(value: value)
}
}
class LinkedList<T, U: LinkedListNode<T>> {
var first: U? = nil
var last: U? = nil
var count = 0
#discardableResult func append(_ value: T) -> U {
let new = U(value: value)
new.prev = last
last?.next = new
count += 1
last = new
if first == nil {
first = new
}
return new
}
func remove(node: U) {
node.next?.prev = node.prev
node.prev?.next = node.next
if node === first {
first = first?.next as? U
}
if node === last {
last = last?.prev as? U
}
}
}
Usage:
let list = LinkedList<Int, LinkedListNode<Int>>()
list.append(5)
print(list.first?.value)
let someCustom = LinkedList<Int, GenericCustomNode<Int>>()
someCustom.append(15)
print(someCustom.first?.value)
let otherCustom = LinkedList<Int, NonGenericCustomNode>()
otherCustom.append(2)
print(otherCustom.first?.value)
Output:
Optional(5)
Optional(15)
Optional(2)
You will need to define a protocol with an associated type:
protocol Node: class {
associatedtype Value
var value: Value {get set}
var next: Self? {get set}
var prev: Self? {get set}
init(value: Value)
}
final class BasicNode<Value>: Node {
var value: Value
var next: BasicNode<Value>?
weak var prev: BasicNode<Value>?
init(value: Value) {
self.value = value
}
}
final class CustomNode<Value>: Node {
// customize however you want
var value: Value
var next: BasicNode<Value>?
weak var prev: BasicNode<Value>?
init(value: Value) {
self.value = value
}
}
class LinkedList<N: Node> {
var first: N? = nil
var last: N? = nil
var count = 0
#discardableResult
func append(_ value: N.Value) -> N {
let new = N(value: value)
new.prev = last
last?.next = new
count += 1
last = new
if first == nil {
first = new
}
return new
}
}
However, this will require using your basic linked list in an annoying way all the time:
let list = LinkedList<BasicNode<Int>>()
Depending on how you need to customize the node, I would consider finding a way to customize the behavior in the LinkList class itself using dependency injection.

Swift binary tree list of nodes at given depth

I'm writing a Swift algorithm for a binary tree. My goal is to create a list of nodes at specific depth something like
func listNodeAt(_n: Int) --> [T] {
}
Here is my tree class
public class BinaryTreeNode<T:Comparable> {
//Value and children vars
public var value:T
public var leftChild:BinaryTreeNode?
public var rightChild:BinaryTreeNode?
public weak var parent:BinaryTreeNode?
//Initialization
public convenience init(value: T) {
self.init(value: value, left: nil, right: nil, parent:nil)
}
public init(value:T, left:BinaryTreeNode?, right:BinaryTreeNode?, parent:BinaryTreeNode?) {
self.value = value
self.leftChild = left
self.rightChild = right
self.parent = parent
}
}
I have build a helper function to calculate the depth of a Node
//Depth
public func depth() -> Int {
guard var node = parent else {
return 0
}
var depth = 1
while let parent = node.parent {
depth = depth + 1
node = parent
}
return depth
}
How can we achieve the desired function?
func listNodeAt(_ n: Int) -> [T] {
return getElementsAt(n, node: self)
}
private func getElementsAt(_ n: Int, node: BinaryTreeNode<T>, traversingDepth: Int = 0) -> [T] {
var array = Array<T>()
if traversingDepth < n {
if let left = node.leftChild {
array = array + getElementsAt(n, node: left, traversingDepth: traversingDepth + 1)
}
if let right = node.rightChild {
array = array + getElementsAt(n, node: right, traversingDepth: traversingDepth + 1)
}
} else if traversingDepth == n {
array.append(node.value)
}
return array
}
This is one of the solution. Assuming here the self is the root node.

How to reverse the Linked List in Swift extension?

I want to reverse the Single Linked List in extension, but finally it's failed.can someone help me? thanks.
public class List<T: Equatable> {
var value: T!
var nextItem: List<T>?
public convenience init!(_ values: T...) {
self.init(Array(values))
}
init!(var _ values: Array<T>) {
if values.count == 0 {
return nil
}
value = values.removeFirst()
nextItem = List(values)
}
}
// Reverse a linked list.
extension List {
func reverse() {
}
}
I have a solution here. Please read the comments, its all evident from the code too. Also I have added a 'description' via CustomStringConvertible to the list to help debugging and printing.
public class List<T: Equatable>{
var value: T!
var nextItem: List<T>?
public convenience init!(_ values: T...) {
self.init(Array(values))
}
init!(_ values: Array<T>) {
if values.count == 0 {
return nil
}
var valuesCopy = values
value = valuesCopy.removeFirst()
nextItem = List(Array(valuesCopy))
}
}
extension List : CustomStringConvertible{
public var description: String {
var desc = String()
var listRef : List<T>? = self
while listRef != nil {
desc += "\((listRef?.value)!) "
listRef = listRef?.nextItem
}
return desc
}
}
extension List{
func reverse() -> List?{
// Iterate through each item, and reverse its link until you visit the last node in the list.
// Once you reach the end, All items except the last one would have
// their links reversed.
var nextNode : List<T>? = self.nextItem
var prevNode : List<T>? = nil
var currentNode : List<T>? = self
while nextNode != nil{
currentNode?.nextItem = prevNode
prevNode = currentNode
currentNode = nextNode
nextNode = currentNode?.nextItem
}
//Ensure the last item in the list too has its links reversed.
currentNode?.nextItem = prevNode
return currentNode
}
}
var list = List(1,2,3,5)
print(list ?? "Failed to create the list")
if let reversed = list.reverse(){
print(reversed)
}