내부노드에 key를 저장하고 외부노드에는 key가 없는 이진트리
다음을 만족해야 한다.
힙은 last node를 관리한다.
[최대힙 예시] [최소힙 예시]
10 1
/ \ / \
7 8 3 5
/ \ / \ / \ / \
1 3 5 X 10 X X X
** 5는 last node ** 10은 last node
** X는 외부 노드
삽입/삭제 설명에서 힙은 최소힙이라고 가정한다.
Alg insertItem(k)
input 키 k, 노드 last
output none
1. advanceLast()
2. z ← last # z는 advance로 지정된 새로운 lastnode다.
3. set node z to k
4. expandExternal(z)
5. upHeap(z)
6. return
------------------
Alg upHeap(v)
input node v
output none
1. if(isRoot(v))
return
2. if(key(v)≥key(parent(v)) # 최소힙 속성을 만족하는지 확인
return
3. swapElements(v, parent(v))
4. upHeap(parent(v))
------------------
Alg expandExternal(z)
input external node z
output none
1. l ← getNode()
r ← getNode()
2. l.left ← ø # l, r의 자식은 없음
l.right ← ø
r.left ← ø
r.right ← ø
3. l.parent ← z # l, r의 부모는 z
r.parent ← z
4. z.left ← l # z의 자식은 l, r
z.right ← r
5. return
------------------
Alg advanceLast()
input lastnode last
output 전진할 위치의 노드
1. z ← last
if(isRoot(z))
return z.left
2. while(z = (z.parent).right)
z ← z.parent
3. while(z = (z.parent).left)
z ← z.sibling
4. while(isInternal(z))
z ← z.left
5. return z
최소힙으로 가정했기에 removeMin()은 root노드를 삭제한다.
Alg removeMin()
input node last
output key
1. k ← key(root())
2. w ← last # last노드 값을 root로 보낸 뒤 last노드 후퇴
set root to key(w)
retreatLast()
3. z ← w.right # last는 후퇴했지만 이전 last는 여전히 내부노드이다.
reduceExternal(z) 외부노드로 만들어서 정리해야 한다.
4. downHeap(root())
5. return k
---------------------
Alg downHeap(v)
input node v (부트리가 모두 힙인 노드)
output 힙순서를 만족하는 힙
1. if(isExternal(v.left) & isExternal(v.right))
return
2. smaller ← v.left
if(isInternal(v.right))
if(key(v.right) < key(smaller))
smaller ← v.right
3. if(key(v) ≤ key(smaller))
return
4. swapElement(v, smaller)
5. downHeap(smaller)
---------------------
Alg reduceExternal(z)
input external node z
output z의 부모를 대체할 노드
1. w ← z.parent
zs ← z.sibling
2. if(isRoot(w))
root ← zs
zs.parent ← ø
else
g ← w.parent
zs.parent ← g
if(w = g.left)
g.left ← zs
else
g.right ← zs
3. putnode(z)
putnode(w)
4. return zs
---------------------
Alg retreatLast()
input lastnode last
output 후진할 노드의 위치
1. z ← last
2. while(z = (z.parent).left)
z ← z.parent
3. while(z = (z.parent).right)
z ← z.sibling
4. while(isInternal(z))
z ← z.right
배열의 첨자 i에 대해
10
/ \
5 6
/ \ / \
1 2 3 X
0 1 2 3 4 5 6 index
+---+---+---+---+---+---+---+
| | 10| 5 | 6 | 1 | 2 | 3 | key
+---+---+---+---+---+---+---+
여기서는 '최대 힙'을 구현한다.
(루트는 가장 큰 키, removeMin대신 removeMax)
Alg heapSort(L)
input 무순리스트 L
output 정렬된 리스트 L
1. H ← 비어있는 힙
2. while(!L.isEmpty())
k ← L.removeFirst()
H.insertItem(k)
3. while(!H.isEmpty())
k ← H.removeMax()
L.addFirst(k)
4. return
입력으로 주어진 무순리스트 L이 배열일 때 제자리 정렬할 수 있다.
heapSort
알고리즘의 제 2의 공간 H가 필요없어져 공간 사용을 줄일 수 있다.
만약 L이 n개의 원소를 갖고 있다면 배열크기는 n+1이다.
(0번 인덱스는 사용하지 않기 때문에, 인덱스 0~n-1이 아닌 1~n을 사용)
Alg inplaceHeapSort(A)
input n개 키를 가진 배열 A
output 정렬된 배열 A
1. buildHeap(A)
2. for i ← n downto 2
A[1] ←→ A[i]
downHeap(1, i-1)
3. return
--------------------------
Alg buildHeap(A)
input n개 키를 가진 배열 A
output 사이즈 n의 힙 A
for i ← 1 to n
insertItem(A, i)
return
--------------------------
Alg insertItem(A, i)
input 부분적으로 힙인 배열 A, index i
output i번 인덱스까지 힙인 배열 A
1. upHeap(A, i)
2. return
--------------------------
Alg upHeap(A, i)
1. if(i = 1) # root
return
2. if(A[i] <= A[i/2]) # 자신의 키값 <= 부모의 키값 이면
return
3. A[i] ←→ A[i/2]
4. upHeap(A, i/2) *** modified (20.Oct.2023)
--------------------------
Alg downHeap(i, last)
input 크기가 last인 최대 힙 A의 인덱스 i, last 인덱스
output none
1. left ← 2i
right ← 2i+1
2. if(left > last)
return
3. greater ← left
if(right <= last)
if(A[right] > A[greater])
greater ← right
4. if(A[i] >= A[greater])
return
5. A[i] ←→ A[greater]
6. downHeap(greater, last)
위에서 계속해서 수행한 insertItem
을 사용한 힙 생성은 '삽입식 힙 생성' 이라고 한다.
그 대신 상향식 힙 생성 방법을 사용하면 heapSort
알고리즘의 힙 생성 시간을 단축할 수 있다.
힙의 키값이 모두 주어진 경우에만 사용할 수 있다.
Alg buildHeap(L)
input n개 키를 저장하는 리스트 L
output 리스트L의 키를 저장한 힙 T
1. T ← convertToCompleteBinaryTree(L)
2. rBuildHeap(T.root())
3. return
---------------------------
Alg rBuildHeap(v)
input node v
output root v를 갖는 힙
1. if(isInternal(v))
rBuildHeap(v.left)
rBuildHeap(v.right)
downHeap(v)
2. return
Alg buildHeap(A)
input n개 키를 가진 배열 A
output 사이즈가 n인 힙 A
1. for i ← ⌊ n/2 ⌋ downto 1
downHeap(i, n)
2. return
안녕하세요! 제자리 정렬에서 Alg upheap에서 upheap(A,i-1)가 아니라 upheap(A,i/2) 아닌가요???