Last active
July 27, 2018 23:04
-
-
Save yossan/b02d8568191cbb6de001490aebc9e4ea to your computer and use it in GitHub Desktop.
Implementing Linked List by using class or enum.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class List<T> { | |
var head: Node<T>? | |
var last: Node<T>? | |
class Node<T> { | |
let value: T | |
var next: Node<T>? = nil | |
init(_ value: T) { | |
self.value = value | |
} | |
} | |
func append(_ newValue: T) { | |
let newNode = Node(newValue) | |
if self.head == nil { | |
self.head = newNode | |
self.last = self.head | |
} else { | |
self.last!.next = newNode | |
self.last = self.last!.next | |
} | |
} | |
func insert(_ newValue: T, at index: Int) { | |
assert(index >= 0, "index must be greater than zero") | |
let newNode = Node(newValue) | |
if index == 0 { | |
let oldHead = self.head | |
self.head = newNode | |
newNode.next = oldHead | |
if self.last == nil { | |
self.last = self.head | |
} | |
} else { | |
var node = self.head | |
for _ in 1..<index { | |
node = node?.next | |
if node == nil { | |
break | |
} | |
} | |
assert(node != nil, "index is out of bounds") | |
let temp = node?.next | |
node?.next = newNode | |
newNode.next = temp | |
if self.last === node { | |
self.last = newNode | |
} | |
} | |
} | |
func remove(at idx: Int) { | |
assert(idx >= 0, "index must be greater than 0") | |
if self.head == nil { | |
return | |
} else if idx == 0 { | |
let prevHead = self.head | |
let next = self.head!.next | |
self.head = next | |
if self.last === prevHead { | |
self.last = self.head | |
} | |
} else { | |
var prev = self.head | |
var node = self.head?.next | |
for _ in 1..<idx { | |
if node == nil || node?.next == nil { | |
prev = nil | |
node = nil | |
break | |
} | |
prev = node! | |
node = node!.next | |
} | |
// delete node | |
prev?.next = node?.next | |
if self.last === node { | |
self.last = node?.next | |
} | |
} | |
} | |
func toArray() -> [T] { | |
if self.head == nil { | |
return [] | |
} else { | |
var node = self.head! | |
var array: [T] = [node.value] | |
while let next = node.next { | |
array.append(next.value) | |
node = next | |
} | |
return array | |
} | |
} | |
} | |
// MARK: sample | |
do { | |
let list = List<Int>() | |
list.append(1) | |
list.append(2) | |
list.append(3) | |
list.append(4) | |
list.append(5) | |
list.insert(6, at: 5) | |
list.append(7) | |
print(list.toArray()) | |
list.remove(at: 0) | |
list.remove(at: 5) | |
print(list.toArray()) | |
} | |
// MARK: calculate execution time | |
import Foundation | |
do { | |
func time(_ count: Int, _ execute: (Int) -> ()) { | |
let start = CFAbsoluteTimeGetCurrent() | |
for i in 0..<count { | |
execute(i) | |
} | |
let time = CFAbsoluteTimeGetCurrent() - start | |
print(time) | |
} | |
let list = List<Int>() | |
time(10000) { (i) in | |
list.append(i) | |
} | |
time(10000/2) { (i) in | |
if i % 2 == 0 { | |
list.remove(at: 10000/2) | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enum List<T> { | |
case empty | |
indirect case node(T, List<T>) | |
mutating func append(_ newElement: T) { | |
switch self { | |
case .empty: | |
self = .node(newElement, .empty) | |
case .node(let value, let tail): | |
var tail = tail | |
tail.append(newElement) | |
self = .node(value, tail) | |
} | |
} | |
func appending(_ newElement: T) -> List<T> { | |
switch self { | |
case .empty: | |
return .node(newElement, .empty) | |
case .node(let value, let tail): | |
return .node(value, tail.appending(newElement)) | |
} | |
} | |
mutating func insert(_ newElement: T, at index: Int) { | |
switch self { | |
case .empty: | |
assert(index == 0, "index is out of bounds") | |
self = .node(newElement, .empty) | |
case .node(let value, let tail): | |
if index == 0 { | |
let oldHead = .node(value, tail) as List<T> | |
self = .node(newElement, oldHead) | |
} else { | |
var tail = tail | |
tail.insert(newElement, at: index - 1) | |
self = .node(value, tail) | |
} | |
} | |
} | |
func inserting(_ newElement: T, at index: Int) -> List<T> { | |
switch self { | |
case .empty: | |
return .node(newElement, .empty) | |
case .node(let value, let tail): | |
if index == 0 { | |
return .node(newElement, .node(value, tail)) | |
} else { | |
return .node(value, tail.inserting(newElement, at: index-1)) | |
} | |
} | |
} | |
mutating func remove(at idx: Int) { | |
switch self { | |
case .empty: | |
self = .empty | |
case .node(let value, let tail): | |
if idx == 0 { | |
self = tail | |
} else { | |
var tail = tail | |
tail.remove(at: idx-1) | |
self = .node(value, tail) | |
} | |
} | |
} | |
func removing(at idx: Int) -> List<T> { | |
switch self { | |
case .empty: | |
return .empty | |
case .node(let value, let tail): | |
if idx == 0 { | |
return tail | |
} else { | |
return .node(value, tail.removing(at: idx-1)) | |
} | |
} | |
} | |
func toArray() -> [T] { | |
func helper(_ list: List<T>, _ accumulator: [T]) -> [T] { | |
switch list { | |
case .empty: | |
return accumulator | |
case .node(let value, let tail): | |
var accumulator = accumulator | |
accumulator.append(value) | |
return helper(tail, accumulator) | |
} | |
} | |
return helper(self, []) | |
} | |
} | |
// MARK: sampl | |
do { | |
var list: List<Int> = .empty | |
list = list.appending(0) | |
list = list.appending(1) | |
list = list.appending(2) | |
list = list.appending(3) | |
list = list.inserting(4, at: 0) | |
list = list.inserting(5, at: 1) | |
list = list.inserting(6, at: 6) | |
print(list.toArray()) | |
list = list.removing(at: 3) | |
print(list.toArray()) | |
} | |
// MARK: calculates execution time | |
import Foundation | |
do { | |
func time(_ count: Int, _ execute: (Int) -> ()) { | |
let start = CFAbsoluteTimeGetCurrent() | |
for i in 0..<count { | |
execute(i) | |
} | |
let time = CFAbsoluteTimeGetCurrent() - start | |
print(time) | |
} | |
// Too late | |
var list: List<Int> = .empty | |
time(10000) { (i) in | |
list = list.appending(i) | |
} | |
time(10000/2) { (i) in | |
if i % 2 == 0 { | |
list = list.removing(at: 10000/2) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment