Skip to content

Instantly share code, notes, and snippets.

@rnapier
Last active August 29, 2015 14:13
Show Gist options
  • Save rnapier/7e3887ab248c43f0b44d to your computer and use it in GitHub Desktop.
Save rnapier/7e3887ab248c43f0b44d to your computer and use it in GitHub Desktop.
Mutable version of addlist (see https://gist.github.com/rnapier/7a552b7f8f089b0d91f6)
/*
Adds two linked lists together e.g. 1->2->3 + 4->5->6 = 5->7->9
Each element is between 0 and 9
This version uses a mutable data structure, which is trickier to use correctly,
but may work better for enormous lists.
It avoids recursion, which increases the number of vars required.
*/
final class Node: Printable, SequenceType { // Struct would be nicer here, but then we'd have to use boxing on next.
var data: Int
var next: Node?
init(data: Int, next: Node?) {
self.data = data
self.next = next
}
func lastNode() -> Node {
var lastNode = self
while (true) {
if let next = lastNode.next {
lastNode = next
} else {
return lastNode
}
}
}
func append(node: Node) {
self.lastNode().next = node
}
func toArray() -> [Int] {
var result = [Int]()
for n in self {
result.append(n)
}
return result
}
// It may seem frustrating that the compiler forces you to have Node? here, but
// it's actually exactly what you want. Because an empty list is nil, you really
// can very seldom consider a concrete Node. It's almost always going to be a
// Node? So any caller is going to want that.
func reverse() {
let values = self.toArray()
var node: Node? = self
for value in self.toArray().reverse() {
node?.data = value
node = node?.next
}
}
func copy() -> Node? {
return Node(values: self.toArray())
}
///
/// All the rest of this is just convenience stuff to make it easier to use
///
init?<G: GeneratorType where G.Element == Int>(var generator: G) {
if let data = generator.next() {
self.data = data
self.next = Node(generator: generator)
} else {
self.data = 0
self.next = nil
return nil
}
}
convenience init?<S: SequenceType where S.Generator.Element == Int>(values: S) {
self.init(generator: values.generate())
}
var description: String {
if let next = self.next {
return "\(self.data) -> \(next)"
} else {
return "\(self.data)"
}
}
// This just lets us use "for...in" on Nodes, which is handy
typealias Generator = GeneratorOf<Int>
func generate() -> Generator {
var next:Node? = self
return GeneratorOf {
let current = next?.data
next = next?.next
return current
}
}
}
// This is just a helper for addLists
private func addReversedLists(var list1: Node?, var list2: Node?, carry: Int) -> Node? {
var result: Node?
var lastNode: Node?
var data: Int
var carry = 0
while (list1 != nil || list2 != nil) {
let value = (list1?.data ?? 0) + (list2?.data ?? 0) + carry
(data, carry) = (value < 10) ? (value, 0) : (value - 10, 1)
let newNode = Node(data: data, next: nil)
if (lastNode != nil) {
lastNode?.next = newNode
lastNode = newNode
} else {
result = newNode
lastNode = newNode
}
list1 = list1?.next
list2 = list2?.next
}
if carry == 1 {
lastNode?.next = Node(data: 1, next: nil)
}
return result
}
func addLists(list1: Node?, list2: Node?) -> Node? {
let rev1 = list1?.copy()
rev1?.reverse()
let rev2 = list2?.copy()
rev2?.reverse()
let sum = addReversedLists(rev1, rev2, 0)
sum?.reverse()
return sum
}
let list1 = Node(values: [8, 2, 3])
let list2 = Node(values: [4, 5, 9])
let sum = addLists(list1, list2)
println(list1)
println(list2)
println(sum)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment