Skip to content

Commit

Permalink
BinaryHeap
Browse files Browse the repository at this point in the history
  • Loading branch information
alezai committed Apr 22, 2016
1 parent 927aaea commit 5d35211
Show file tree
Hide file tree
Showing 9 changed files with 263 additions and 0 deletions.
19 changes: 19 additions & 0 deletions BinaryHeap/BinaryHeap.playground/Contents.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//: Playground - noun: a place where people can play
var heap = BinaryHeap<Int>.init(array: [7, 1, 5, 2, 9])

heap.minimum()

heap.deleteMin()
heap.deleteMin()
heap.deleteMin()

heap.minimum()

heap.insert(4)
heap.insert(3)

heap.debugDescription
heap.removeAtIndex(1)
heap.debugDescription

heap.removeAll()
119 changes: 119 additions & 0 deletions BinaryHeap/BinaryHeap.playground/Sources/BinaryHeap.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
BinaryHeap - Min
*/

public struct BinaryHeap<T: Comparable> {
private var elements = [T]()

public init(array: [T]) {
buildHeap(array)
}

private mutating func percolateUpAtIndex(index: Int) {
assert(index < elements.count)
let element = elements[index]
var i = index
var child = i
while i != 0 && elements[(i - 1) / 2] > element {
elements[i] = elements[(i - 1) / 2]
child = i
i = (i - 1) / 2
}
if i == 0 {
if elements[0] > element {
elements[child] = elements[0]
}else {
i = child
}
}
elements[i] = element
}

private mutating func percolateDownAtIndex(index: Int, lastElementIndex: Int) {
assert(index < elements.count)
let element = elements[index]
let lastElement = elements[lastElementIndex]
var i = index

while i * 2 + 1 < elements.count {
var child = 2 * i + 1
if child != elements.count - 1 && elements[child + 1] < elements[child] {
child += 1
}
if elements[child] < lastElement{
elements[i] = elements[child]
}else {
break
}
i = child
}
elements[i] = lastElement
elements[lastElementIndex] = element
}
}

//MARK: - Basic Operations
extension BinaryHeap {
private mutating func buildHeap(array: [T]) {
for element in array {
insert(element)
}
}

public mutating func insert(element: T) {
elements.append(element)
percolateUpAtIndex(elements.count - 1)
}

public mutating func deleteMin() {
assert(elements.count > 0)
percolateDownAtIndex(0, lastElementIndex: elements.count - 1)
elements.removeLast()
}

public func minimum() -> T? {
return elements.first
}

public mutating func removeAtIndex(index: Int) {
assert(index < elements.count)
elements[index] = minimum()!
percolateUpAtIndex(index)
deleteMin()
}

public mutating func removeAll() {
elements.removeAll()
}
}

//MARK: - Debug
extension BinaryHeap: CustomStringConvertible {
public var description: String {
if elements.count > 0 {
return descriptionAtIndex(0)
}else {
return "nil"
}
}

private func descriptionAtIndex(index: Int) -> String {
var s = ""
let left = 2 * index + 1
if left < elements.count {
s += "(\(descriptionAtIndex(left)))<- "
}
s += "\(elements[index])"
let right = left + 1
if right < elements.count {
s += " ->(\(descriptionAtIndex(right)))"
}
return s
}
}

extension BinaryHeap: CustomDebugStringConvertible {
public var debugDescription: String {
return elements.description
}
}
4 changes: 4 additions & 0 deletions BinaryHeap/BinaryHeap.playground/contents.xcplayground
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='osx'>
<timeline fileName='timeline.xctimeline'/>
</playground>
Binary file added BinaryHeap/Image/BinaryHeap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added BinaryHeap/Image/CompleteBinaryTree.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added BinaryHeap/Image/percolateDown.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added BinaryHeap/Image/percolateUp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
116 changes: 116 additions & 0 deletions BinaryHeap/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#

## 二叉堆

### 结构性质

二叉堆是一颗完全二叉树

![CompleteBinaryTree](Image/CompleteBinaryTree.png)

容易得出结论:

* 一颗高为h的完全二叉树,有2^h到2^(h+1) - 1个节点
* 对于位置i,左儿子在2i,右儿子在2i+1,父亲在i/2

### 堆序性质

任意节点值小于它的所有后裔

![BinaryHeap](Image/BinaryHeap.png)

### 堆操作的两个关键方法

#### 上滤

![percolateUp](Image/percolateUp.png)

```swift
private mutating func percolateUpAtIndex(index: Int) {
assert(index < elements.count)
let element = elements[index]
var i = index
var child = i
while i != 0 && elements[(i - 1) / 2] > element {
elements[i] = elements[(i - 1) / 2]
child = i
i = (i - 1) / 2
}
if i == 0 {
if elements[0] > element {
elements[child] = elements[0]
}else {
i = child
}
}
elements[i] = element
}
```



#### 下滤 ![percolateDown](Image/percolateDown.png)

```swift
private mutating func percolateDownAtIndex(index: Int, lastElementIndex: Int) {
assert(index < elements.count)
let element = elements[index]
let lastElement = elements[lastElementIndex]
var i = index

while i * 2 + 1 < elements.count {
var child = 2 * i + 1
if child != elements.count - 1 && elements[child + 1] < elements[child] {
child += 1
}
if elements[child] < lastElement{
elements[i] = elements[child]
}else {
break
}
i = child
}
elements[i] = lastElement
elements[lastElementIndex] = element
}
```



### 基本操作

#### 插入

在数组末尾插入,然后对其进行上滤操作

```swift
public mutating func insert(element: T) {
elements.append(element)
percolateUpAtIndex(elements.count - 1)
}
```

#### 建堆

依序执行插入即可

```swift
private mutating func buildHeap(array: [T]) {
for element in array {
insert(element)
}
}
```

#### 删除最小元

将数组第一个元素替换为数组的最后一个元素,对第一个元素进行下滤操作,最后删除数组最后一个元素即可

```swift
public mutating func deleteMin() {
assert(elements.count > 0)
percolateDownAtIndex(0, lastElementIndex: elements.count - 1)
elements.removeLast()
}
```

5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@
## 散列表

- [HashTable](HashTable/) key-value-coding

##

* [BinaryHeap](BinaryHeap/)

0 comments on commit 5d35211

Please sign in to comment.