Skip to content

Commit c5b3ac9

Browse files
committed
Add Huffman coding
1 parent 464077a commit c5b3ac9

21 files changed

+1219
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//: Playground - noun: a place where people can play
2+
3+
import Foundation
4+
5+
let s1 = "so much words wow many compression"
6+
if let originalData = s1.dataUsingEncoding(NSUTF8StringEncoding) {
7+
print(originalData.length)
8+
9+
let huffman1 = Huffman()
10+
let compressedData = huffman1.compressData(originalData)
11+
print(compressedData.length)
12+
13+
let frequencyTable = huffman1.frequencyTable()
14+
//print(frequencyTable)
15+
16+
let huffman2 = Huffman()
17+
let decompressedData = huffman2.decompressData(compressedData, frequencyTable: frequencyTable)
18+
print(decompressedData.length)
19+
20+
let s2 = String(data: decompressedData, encoding: NSUTF8StringEncoding)!
21+
print(s2)
22+
assert(s1 == s2)
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
//
2+
// Heap.swift
3+
// Written for the Swift Algorithm Club by Kevin Randrup and Matthijs Hollemans
4+
//
5+
6+
public struct Heap<T> {
7+
/** The array that stores the heap's nodes. */
8+
var elements = [T]()
9+
10+
/** Determines whether this is a max-heap (>) or min-heap (<). */
11+
private var isOrderedBefore: (T, T) -> Bool
12+
13+
/**
14+
* Creates an empty heap.
15+
* The sort function determines whether this is a min-heap or max-heap.
16+
* For integers, > makes a max-heap, < makes a min-heap.
17+
*/
18+
public init(sort: (T, T) -> Bool) {
19+
self.isOrderedBefore = sort
20+
}
21+
22+
/**
23+
* Creates a heap from an array. The order of the array does not matter;
24+
* the elements are inserted into the heap in the order determined by the
25+
* sort function.
26+
*/
27+
public init(array: [T], sort: (T, T) -> Bool) {
28+
self.isOrderedBefore = sort
29+
buildHeap(array)
30+
}
31+
32+
/*
33+
// This version has O(n log n) performance.
34+
private mutating func buildHeap(array: [T]) {
35+
elements.reserveCapacity(array.count)
36+
for value in array {
37+
insert(value)
38+
}
39+
}
40+
*/
41+
42+
/**
43+
* Converts an array to a max-heap or min-heap in a bottom-up manner.
44+
* Performance: This runs pretty much in O(n).
45+
*/
46+
private mutating func buildHeap(array: [T]) {
47+
elements = array
48+
for i in (elements.count/2 - 1).stride(through: 0, by: -1) {
49+
shiftDown(index: i, heapSize: elements.count)
50+
}
51+
}
52+
53+
public var isEmpty: Bool {
54+
return elements.isEmpty
55+
}
56+
57+
public var count: Int {
58+
return elements.count
59+
}
60+
61+
/**
62+
* Returns the index of the parent of the element at index i.
63+
* The element at index 0 is the root of the tree and has no parent.
64+
*/
65+
@inline(__always) func indexOfParent(i: Int) -> Int {
66+
return (i - 1) / 2
67+
}
68+
69+
/**
70+
* Returns the index of the left child of the element at index i.
71+
* Note that this index can be greater than the heap size, in which case
72+
* there is no left child.
73+
*/
74+
@inline(__always) func indexOfLeftChild(i: Int) -> Int {
75+
return 2*i + 1
76+
}
77+
78+
/**
79+
* Returns the index of the right child of the element at index i.
80+
* Note that this index can be greater than the heap size, in which case
81+
* there is no right child.
82+
*/
83+
@inline(__always) func indexOfRightChild(i: Int) -> Int {
84+
return 2*i + 2
85+
}
86+
87+
/**
88+
* Returns the maximum value in the heap (for a max-heap) or the minimum
89+
* value (for a min-heap).
90+
*/
91+
public func peek() -> T? {
92+
return elements.first
93+
}
94+
95+
/**
96+
* Adds a new value to the heap. This reorders the heap so that the max-heap
97+
* or min-heap property still holds. Performance: O(log n).
98+
*/
99+
public mutating func insert(value: T) {
100+
elements.append(value)
101+
shiftUp(index: elements.count - 1)
102+
}
103+
104+
public mutating func insert<S : SequenceType where S.Generator.Element == T>(sequence: S) {
105+
for value in sequence {
106+
insert(value)
107+
}
108+
}
109+
110+
/**
111+
* Allows you to change an element. In a max-heap, the new element should be
112+
* larger than the old one; in a min-heap it should be smaller.
113+
*/
114+
public mutating func replace(index i: Int, value: T) {
115+
assert(isOrderedBefore(value, elements[i]))
116+
elements[i] = value
117+
shiftUp(index: i)
118+
}
119+
120+
/**
121+
* Removes the root node from the heap. For a max-heap, this is the maximum
122+
* value; for a min-heap it is the minimum value. Performance: O(log n).
123+
*/
124+
public mutating func remove() -> T? {
125+
if elements.isEmpty {
126+
return nil
127+
} else if elements.count == 1 {
128+
return elements.removeLast()
129+
} else {
130+
// Use the last node to replace the first one, then fix the heap by
131+
// shifting this new first node into its proper position.
132+
let value = elements[0]
133+
elements[0] = elements.removeLast()
134+
shiftDown()
135+
return value
136+
}
137+
}
138+
139+
/**
140+
* Removes an arbitrary node from the heap. Performance: O(log n). You need
141+
* to know the node's index, which may actually take O(n) steps to find.
142+
*/
143+
public mutating func removeAtIndex(i: Int) -> T? {
144+
let size = elements.count - 1
145+
if i != size {
146+
swap(&elements[i], &elements[size])
147+
shiftDown(index: i, heapSize: size)
148+
shiftUp(index: i)
149+
}
150+
return elements.removeLast()
151+
}
152+
153+
/**
154+
* Takes a child node and looks at its parents; if a parent is not larger
155+
* (max-heap) or not smaller (min-heap) than the child, we exchange them.
156+
*/
157+
mutating func shiftUp(index index: Int) {
158+
var childIndex = index
159+
let child = elements[childIndex]
160+
var parentIndex = indexOfParent(childIndex)
161+
162+
while childIndex > 0 && isOrderedBefore(child, elements[parentIndex]) {
163+
elements[childIndex] = elements[parentIndex]
164+
childIndex = parentIndex
165+
parentIndex = indexOfParent(childIndex)
166+
}
167+
168+
elements[childIndex] = child
169+
}
170+
171+
mutating func shiftDown() {
172+
shiftDown(index: 0, heapSize: elements.count)
173+
}
174+
175+
/**
176+
* Looks at a parent node and makes sure it is still larger (max-heap) or
177+
* smaller (min-heap) than its childeren.
178+
*/
179+
mutating func shiftDown(index index: Int, heapSize: Int) {
180+
var parentIndex = index
181+
182+
while true {
183+
let leftChildIndex = indexOfLeftChild(parentIndex)
184+
let rightChildIndex = leftChildIndex + 1
185+
186+
// Figure out which comes first if we order them by the sort function:
187+
// the parent, the left child, or the right child. If the parent comes
188+
// first, we're done. If not, that element is out-of-place and we make
189+
// it "float down" the tree until the heap property is restored.
190+
var first = parentIndex
191+
if leftChildIndex < heapSize && isOrderedBefore(elements[leftChildIndex], elements[first]) {
192+
first = leftChildIndex
193+
}
194+
if rightChildIndex < heapSize && isOrderedBefore(elements[rightChildIndex], elements[first]) {
195+
first = rightChildIndex
196+
}
197+
if first == parentIndex { return }
198+
199+
swap(&elements[parentIndex], &elements[first])
200+
parentIndex = first
201+
}
202+
}
203+
}
204+
205+
// MARK: - Searching
206+
207+
extension Heap where T: Equatable {
208+
/**
209+
* Searches the heap for the given element. Performance: O(n).
210+
*/
211+
public func indexOf(element: T) -> Int? {
212+
return indexOf(element, 0)
213+
}
214+
215+
private func indexOf(element: T, _ i: Int) -> Int? {
216+
if i >= count { return nil }
217+
if isOrderedBefore(element, elements[i]) { return nil }
218+
if element == elements[i] { return i }
219+
if let j = indexOf(element, indexOfLeftChild(i)) { return j }
220+
if let j = indexOf(element, indexOfRightChild(i)) { return j }
221+
return nil
222+
}
223+
}

0 commit comments

Comments
 (0)