-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathHeapSort.kt
129 lines (108 loc) · 3.87 KB
/
HeapSort.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package algorithmdesignmanualbook.sorting
import utils.assertArraysSame
import java.lang.Integer.max
import java.lang.Integer.min
import java.util.*
import kotlin.test.assertTrue
class HeapSort {
private var array = emptyArray<Int>()
private var nextIndex = 0
fun peekArray() = array.copyOf(array.size)
fun add(element: Int) {
if (array.isEmpty() || nextIndex > array.lastIndex) {
growArray()
}
array[nextIndex] = element
bubbleUp(nextIndex)
nextIndex++
}
private fun growArray() {
// Size is always index + 1
val temp = Array(nextIndex + 1) { 0 }
System.arraycopy(array, 0, temp, 0, array.size)
array = temp
}
private fun shrinkArray() {
val temp = Array(array.size - 1) { 0 }
System.arraycopy(array, 0, temp, 0, array.size - 1)
array = temp
nextIndex--
}
private fun bubbleUp(index: Int) {
var currentIndex = index
var parentIndex = parentIndexOfIndex(currentIndex)
while (currentIndex != parentIndex && array[parentIndex] > array[currentIndex]) {
swap(parentIndex, currentIndex)
currentIndex = parentIndex
parentIndex = parentIndexOfIndex(currentIndex)
}
}
private fun swap(from: Int, to: Int) {
println("Swapping index:$from-->$to; value:${array[from]}-->${array[to]}")
val temp = array[from]
array[from] = array[to]
array[to] = temp
}
private fun parentIndexOfIndex(index: Int): Int = if (index % 2 == 0) max(0, index / 2 - 1) else index / 2
private fun indexOfLeftChildOfIndex(index: Int): Int = index * 2 + 1
private fun indexOfRightChildOfIndex(index: Int): Int = index * 2 + 2
fun print() = println(Arrays.toString(array))
fun peekMinValue() = array[0]
fun deleteMin() {
// Bring right most element to the root
swap(0, array.lastIndex)
// Delete the last element
shrinkArray()
// then bubble root element down
bubbleDown()
}
private fun bubbleDown() {
var currentIndex = 0
while (currentIndex < array.size) {
val leftIndex = indexOfLeftChildOfIndex(currentIndex)
val rightIndex = indexOfRightChildOfIndex(currentIndex)
// Left index is filled first so it must be less than last index
if (leftIndex > array.lastIndex) {
break
}
val leftValue = array[leftIndex]
val rightValue = array.getOrNull(rightIndex) ?: Integer.MAX_VALUE
// WARNING: MUST compare with both left and right node and swap with the minimum
val minValue = min(leftValue, rightValue)
// Satisfactory position
if (minValue >= array[currentIndex]) {
break
}
if (minValue == leftValue) {
// swap with left
swap(leftIndex, currentIndex)
currentIndex = leftIndex
} else if (minValue == rightValue) {
// swap with right
swap(rightIndex, currentIndex)
currentIndex = rightIndex
} else {
break
}
}
}
}
fun main() {
val sort = HeapSort()
sort.add(20)
sort.add(30)
sort.add(40)
sort.add(50)
sort.add(60)
sort.print()
assertArraysSame(expected = arrayOf(20, 30, 40, 50, 60), actual = sort.peekArray())
sort.add(10)
sort.print()
assertArraysSame(expected = arrayOf(10, 30, 20, 50, 60, 40), actual = sort.peekArray())
assertTrue { sort.peekMinValue() == 10 }
sort.deleteMin()
assertArraysSame(expected = arrayOf(20, 30, 40, 50, 60), actual = sort.peekArray())
sort.deleteMin()
assertTrue { sort.peekMinValue() == 30 }
assertArraysSame(expected = arrayOf(30, 50, 40, 60), actual = sort.peekArray())
}