Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save SwiftArchitect/41998492c31a1dc96c4739b2f71f0f7c to your computer and use it in GitHub Desktop.
Save SwiftArchitect/41998492c31a1dc96c4739b2f71f0f7c to your computer and use it in GitHub Desktop.
Swift Xcode more implementation of InterviewCake _Delete Linked List Node_ in generally O(1) time and O(1), with references side-effects. ⚠️ Spoiler alert: this is an improved answer to the https://www.interviewcake.com/question/swift/delete-node question, so no peeking!
//
// LinkedListNode+Extensions.swift
//
// Copyright © 2018 Xavier Schott
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import Foundation
// Logging
extension LinkedListNode : CustomStringConvertible {
var description: String {
return (value as? CustomStringConvertible)?.description ?? ""
}
func log() {
print(self)
}
}
// Comparing nodes
extension LinkedListNode : Equatable {
static func == (lhs: LinkedListNode, rhs: LinkedListNode) -> Bool {
return lhs.value == rhs.value
}
}
// LinkedListNode as presented in the exercise, untouched
import Foundation
class LinkedListNode<Value:Equatable> {
var value: Value
var next: LinkedListNode?
init(_ value: Value) {
self.value = value
}
}
//
// NodeManipulator.swift
//
// Copyright © 2018 Xavier Schott
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import Foundation
class NodeManipulator<Element:Equatable> where Element:CustomStringConvertible {
enum NodeManipulatorError: Error {
case NodeNotFound
}
var root:LinkedListNode<Element>?
init (_ list: LinkedListNode<Element>) {
root = list
}
// No side effect, O(n)
func deleteNodeSafely(node: LinkedListNode<Element>) throws {
var i:LinkedListNode<Element>? = root
var parent:LinkedListNode<Element>?
while i != nil {
if node == i { // Found it
parent?.next = node.next // Remove it
if node == root { // Reconnect root
root = node.next
}
return
}
parent = i
i = i?.next
}
throw NodeManipulatorError.NodeNotFound
}
// Side effects on direct references, O(1) except for last node
func deleteNode(node: LinkedListNode<Element>) throws {
if let skip = node.next {
node.value = skip.value
node.next = skip.next
} else {
try deleteNodeSafely(node: node)
}
}
func log() {
var node:LinkedListNode<Element>? = root
while node != nil {
node?.log()
node = node?.next
}
}
}
//
// NodeManipulatorTests.swift
//
// Copyright © 2018 Xavier Schott
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import XCTest
class NodeManipulatorTests: XCTestCase {
func testDeleteNode() {
let a = LinkedListNode("A")
let b = LinkedListNode("B")
let c = LinkedListNode("C")
a.next = b
b.next = c
let manipulator = NodeManipulator(a)
do {
try manipulator.deleteNode(node: b)
manipulator.log() // Will print "A", "C"
} catch {
XCTAssert(false)
}
XCTAssert(true) // Not an actual test
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment