Skip to content

Instantly share code, notes, and snippets.

@yossan
Last active July 27, 2018 23:04
Show Gist options
  • Save yossan/b02d8568191cbb6de001490aebc9e4ea to your computer and use it in GitHub Desktop.
Save yossan/b02d8568191cbb6de001490aebc9e4ea to your computer and use it in GitHub Desktop.
Implementing Linked List by using class or enum.
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)
}
}
}
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