Computer Science/Data Structures

๐ŸŽŠBinary Heap

metamong 2024. 7. 17.

๐ŸŽŠ intro

๐ŸŽŠ Priority Queue์™€ ์—ฐ๊ฒฐ์ง€์–ด ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋Š” Binary Heap data structure์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด์ž. ์•ž์„œ ํ•™์Šตํ•œ Priority Queue๋Š” ์ผ์ข…์˜ Abstract Data Structure(ADT)๋กœ, binary heap์„ ์ถ”์ƒํ™”ํ•œ ๊ฐœ๋…์ด๋ผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, ์‹ค์ œ priority queue๋Š” binary heap์ด๋ผ ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค. priority queue์˜ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ์ตœ๋Œ€ ๋จผ์ €, ๋˜๋Š” ์ตœ์†Œ ๋จผ์ €๋ผ๋ฉด binary heap์œผ๋กœ tree structure๋ฅผ ๋งŒ๋“ค์–ด tree structure์—์„œ ์šฐ์„ ์ˆœ์œ„์— ๋งž๊ฒŒ ๊บผ๋‚ด์ค€๋‹ค. ์ตœ๋Œ€ ๋จผ์ €๋ผ๋ฉด max-heap, ์ตœ์†Œ ๋จผ์ €๋ผ๋ฉด min-heap์ด๋ผ ๋ถ€๋ฅธ๋‹ค. (์—ฌ๊ธฐ์„œ priority queue๋Š” ๋ฌด์กฐ๊ฑด binary heap์„ ์ด์šฉํ•ด์„œ ๊ตฌํ˜„์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ์•ˆ๋œ๋‹ค. ์ฃผ๋กœ binary heap์ด ๋งŽ์ด ์“ฐ์ผ ๋ฟ ๋‹ค๋ฅธ heap๋„ ์“ฐ์ธ๋‹ค.) 

 

๐ŸŽŠ ์•ž์„œ ์–ธ๊ธ‰ํ•œ Binary Heap์€ Heap Data Structure์˜ ์ผ์ข…์œผ๋กœ, binary heap์™ธ leftis, binomial, fibonacci, pairing, brodal, rank-pairing, strict fibonacci, 2-3 heap๊ณผ ๊ฐ™์€ ๋‹ค์–‘ํ•œ heap ์กด์žฌ. ์•„๋ž˜์™€ ๊ฐ™์ด ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ ๋ฐฐ์šธ Binary Heap์€ ์•„๋ž˜ ํ‘œ์™€ ๊ฐ™์ด deletion / insertion ๋ชจ๋‘ ์‹œ๊ฐ„ ๋ณต์žก๋„ O(logN)์ด๋‹ค. O(N)๋ณด๋‹ค ์ž‘์œผ๋ฏ€๋กœ ํšจ์œจ์ ์ด๋‹ค๋ผ๋Š” ๋ถ€๋ถ„์—์„œ ๋Œ€ํ‘œ ์ž๋ฃŒ๊ตฌ์กฐ๋กœ ๋งŽ์ด ์‚ฌ์šฉ.

 

๐ŸŽŠ tree structure ํ˜•ํƒœ์˜ binary heap์ด๋ผ๊ณ  ํ•˜์˜€๋Š”๋ฐ, tree์ค‘ complete binary tree structure์—์„œ ๋”ฐ์˜จ ๊ฒƒ์„ binary heap์ด๋ผ ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค. Binary Heap์„ ๋งŒ์กฑํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Complete Binary Tree Structure๋ผ๋Š” shape์„ ๋งŒ์กฑํ•ด์•ผ ํ•˜๊ณ (shape property ์ถฉ์กฑ), Heap ์„ฑ์งˆ์„ ๋งŒ์กฑํ•ด์•ผ ํ•œ๋‹ค(heap property ์ถฉ์กฑ)

๐ŸŽŠ โ‘  Shape Property → Complete Binary Tree

๐ŸŽŠ Complete Binary Tree(CBT; ์™„์ „ ์ด์ง„ ํŠธ๋ฆฌ)๋ž€, root ๋…ธ๋“œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ ์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ, ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ ์ˆœ์„œ๋Œ€๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ์ฐจ๋ก€๋Œ€๋กœ ์‚ฝ์ž…๋˜๋Š” tree๋ฅผ ๋œปํ•œ๋‹ค. 'all levels of the tree, except possibly the last one (deepest) are fully filled, and, if the last level of the tree is not complete, the nodes of that level are filled from left to right.' ๋งจ ๋งˆ์ง€๋ง‰ level์„ ์ œ์™ธํ•˜๊ณ  ๋ชจ๋“  level์ด ์ฑ„์›Œ์ ธ ์žˆ๊ณ , ๋งˆ์ง€๋ง‰ level์˜ ๊ฒฝ์šฐ ์™ผ์ชฝ๋ถ€ํ„ฐ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์ตœ๋Œ€ํ•œ ์ฑ„์›Œ์ง„ tree๋ผ ๋ณด๋ฉด ๋œ๋‹ค. ์•„๋ž˜ ์™ผ์ชฝ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด Complete Binary Tree๋ฅผ ์ฑ„์šธ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด CBT ์ •์˜์— ์˜ํ•ด ์•„๋ž˜ ์˜ค๋ฅธ์ชฝ ๊ทธ๋ฆผ์—์„œ CBT๋Š” 1, 2, 5, 6์ž„์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

๐ŸŽŠ โ‘ก Heap Property → Max-Heap & Min-Heap

๐ŸŽŠ ์ด์ œ โ‘ ์„ ํ†ตํ•ด Shape Property ์กฐ๊ฑด์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜๊ณ , ๋‘๋ฒˆ์งธ ์กฐ๊ฑด Heap Property์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž. ๋‘ property๋ฅผ ๋ชจ๋‘ ๋งŒ์กฑํ•ด์•ผ Binary Heap์ด๋ผ ํ•  ์ˆ˜ ์žˆ๋‹ค. 'Heap property: the key stored in each node is either greater than or equal to (≥) or less than or equal to (≤) the keys in the node's children, according to some total order.'

 

๐ŸŽŠ max-heap: parent key๊ฐ€ child keys๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ๊ฐ™์€ heap / min-heap: parent key๊ฐ€ child keys๋ณด๋‹ค ์ž‘๊ฑฐ๋‚˜ ๊ฐ™์€ heap. ์ฆ‰ max-heap์€ root node๊ฐ€ ๊ฐ€์žฅ ํฐ ๊ฐ’์„ ๊ฐ€์ง€๋ฉฐ(child node ๊ฐ’ ๋ณด๋‹ค ๋ชจ๋‘ ํฌ๊ฑฐ๋‚˜ ๊ฐ™์•„์•ผ ํ•œ๋‹ค), ๊ฐ€์žฅ ๊ฐ’์ด ํฐ ๋ฐ์ดํ„ฐ๊ฐ€ ์šฐ์„ ์ ์œผ๋กœ ์ œ๊ฑฐ๋œ๋‹ค. ์ฆ‰ deletion ์ง„ํ–‰ ์‹œ root node๋ถ€ํ„ฐ ์ œ๊ฑฐ๋œ๋‹ค. min-heap์€ ๊ทธ ๋ฐ˜๋Œ€. deletion ์ฐจ๋ก€๋Œ€๋กœ ์ง„ํ–‰ํ•˜๋ฉด์„œ extract๋œ ์›์†Œ๋“ค ์ฐจ๋ก€๋Œ€๋กœ ๋ฐฐ์น˜๋งŒ ํ•ด๋„ ์ž๋™์œผ๋กœ ์ •๋ ฌ ์ˆ˜ํ–‰. max-heap์˜ ๊ฒฝ์šฐ ์ตœ๋Œ“๊ฐ’์œผ๋กœ extraction ์ง„ํ–‰ํ•˜๋ฏ€๋กœ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ / min-heap์˜ ๊ฒฝ์šฐ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ ๊ฒฐ๊ณผ.

 

๐ŸŽŠ max-heap๊ณผ min-heap์€ ๋”ฐ๋ผ์„œ priority queue implementation ์‹œ element๋ฅผ insertion / ๋˜๋Š” ๊ฐ€์žฅ ์ž‘๊ฑฐ๋‚˜ ํฐ element๋ฅผ min-heap๊ณผ max-heap์—์„œ deletionํ•˜๋Š” ๋‘ operation์—์„œ ํšจ์œจ์ ์ด๊ฒŒ ๋งŽ์ด ์“ฐ์ธ๋‹ค.

 

๐ŸŽŠ ํ•ด๋‹น ์ •๋ ฌ์€ heapsort sorting algorithm(in-place algorithm)์œผ๋กœ, tree structure ๋‚ด์—์„œ ์„œ๋กœ node๋ผ๋ฆฌ ์ƒ๋Œ€์ ์œผ๋กœ ์œ„์น˜๋ฅผ ๋ฐ”๊พธ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋ฏ€๋กœ in-place ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค. (sorting ๊ณผ์ •์€ ์•„๋ž˜ ๋‚ด์šฉ ์ƒ์„ธํžˆ ์ฐธ์กฐ) / ์•„๋ž˜ ๊ทธ๋ฆผ ์™ผ์ชฝ max-heap / ์˜ค๋ฅธ์ชฝ min-heap

๐ŸŽŠ binary heap implementations

๐ŸŽŠ heap ๊ตฌํ˜„์€ linked list์™€ array ๋‘ ๊ตฌ์กฐ๋กœ ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•œ๋ฐ, linked list๋Š” ๋งŽ์€ ๋ฉ”๋ชจ๋ฆฌ ์ฐจ์ง€,์ฃผ๋กœ array๋กœ ๊ตฌํ˜„๋œ๋‹ค. array์˜ index๋ฅผ ์ด์šฉํ•ด heap binary tree์— ์Œ“๋Š” ๊ณผ์ •์„ ์•Œ์•„๋ณด์ž. binary heap์„ array๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ์— ์•ž์„œ์„œ child & parent node index๋ฅผ ๋จผ์ € ์•Œ์•„๋ณด์ž

โ‘  child & parent's node index

๐ŸŽŠ ์ƒ์œ„ node์˜ index๊ฐ€ i๋ผ๋ฉด(index 0๋ถ€ํ„ฐ ์‹œ์ž‘ ์‹œ) ํ•˜์œ„ left node์˜ index๋Š” 2i+1, ํ•˜์œ„ right node์˜ index๋Š” 2i+2์ด๋‹ค. ๋ฐ˜๋Œ€๋กœ ์ž์‹ node์˜ index๊ฐ€ x๋ผ๋ฉด paret node์˜ index๋Š” floor((x-1)/2)

๐ŸŽŠ  ์‹ค์ œ heapsort๋Š” ์œ„ 1์ฐจ์› array ๋‚ด์˜ ์›์†Œ๋ฅผ swapํ•˜๋Š” ๊ณผ์ •์œผ๋กœ 1์ฐจ์› array ํ•œ์ • ๋‚ด sortingํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ์ง„ํ–‰๋œ๋‹ค(in-place)

โ‘ก building a heap

๐ŸŽŠ ๊ทธ๋ ‡๋‹ค๋ฉด ์ฃผ์–ด์ง„ array๋ฅผ binary heap ํ˜•ํƒœ(max heap ๊ฐ€์ •)๋กœ ์ €์žฅํ•˜๋Š” ๊ณผ์ •์„ ํ•œ ๋‹จ๊ณ„์”ฉ ์ž์„ธํžˆ ์‚ดํŽด๋ณด์ž

 

โ‘  ์ฃผ์–ด์ง„ array์˜ ์ค‘๊ฐ„ ์›์†Œ๋ถ€ํ„ฐ(arr[(len(arr)-2)//2]: index 0 ๊ธฐ์ค€) ๋งจ ์•ž ์›์†Œ๊นŒ์ง€ for๋ฌธ ๋ฐ˜๋ณต๋ฌธ์œผ๋กœ ์•„๋ž˜ swapํ•˜๋Š” ๊ณผ์ •(heapify())์„ ๋Œ๋ฆฐ๋‹ค.

 

Q. ์ฃผ์–ด์ง„ array์˜ ์ „์ฒด๋ฅผ ๋Œ๋ฆฌ์ง€ ์•Š๊ณ  ์ค‘๊ฐ„ ์›์†Œ๋ถ€ํ„ฐ ๋Œ๋ฆฌ๋Š” ์ด์œ ?

A. child node๊ฐ€ ์—†๋Š” parent node๋Š” heapify ๊ณผ์ •(์•„๋ž˜๋กœ ๋ป—์–ด๋‚˜๊ฐ€๋ฉฐ swap ํ•˜๋Š” ๊ณผ์ •)์ด ํ•„์š” ์—†๊ธฐ ๋•Œ๋ฌธ. child node๊ฐ€ ์กด์žฌํ•˜๋Š” parent node๋ถ€ํ„ฐ ๋Œ๋ ค์•ผ ํ•˜๋ฏ€๋กœ ํ•ด๋‹น parent node์˜ ๊ฐœ์ˆ˜๋Š”, ์ „์ฒด index๋ฅผ N์ด๋ผ ํ•˜๋ฉด index N//2์ธ node์—์„œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•œ๋‹ค.

(์ฐธ๊ณ : child node๊ฐ€ ์กด์žฌํ•˜๋Š” node๋ฅผ non-leaf node, child node๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋…ธ๋“œ๋ฅผ leaf node. ๋”ฐ๋ผ์„œ non-leaf node๋ถ€ํ„ฐ iteration ์ง„ํ–‰)

 

Q. ์ฃผ์–ด์ง„ array์˜ ์ค‘๊ฐ„ ์›์†Œ๋ถ€ํ„ฐ ์ฒซ๋ฒˆ์งธ ์›์†Œ๊นŒ์ง€ ๊ฑฐ๊พธ๋กœ ๋Œ๋ฆฌ๋Š” ์ด์œ ?

A. subarray ์ž์ฒด๋ฅผ heap์œผ๋กœ ๋ฐ”๊พธ๊ธฐ ์œ„ํ•ด์„œ๋Š” ํ•ด๋‹น subarray ๋‚ด์˜ ๋ชจ๋“  subarray๋„ heap์„ ๋งŒ์กฑ์‹œ์ผœ์•ผ ํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์ฒซ๋ฒˆ์งธ ์›์†Œ๋ถ€ํ„ฐ ๋Œ๋ฆฌ๋Š” ์ˆœ๊ฐ„, ์ฒซ๋ฒˆ์งธ ์›์†Œ๋ฅผ ํฌํ•จํ•œ ์ „์ฒด array ๋‚ด์— ๋ชจ๋“  subarray๊ฐ€ ์ด๋ฏธ heap์ž„์„ ๋ณด์žฅํ•  ๋ฆฌ ์—†์œผ๋ฏ€๋กœ ๊ฑฐ๊พธ๋กœ ๋Œ๋ ค์„œ ์•„๋ž˜์—์„œ ์œ„๋กœ ์˜ฌ๋ผ๊ฐ€๋ฉฐ heap์„ ๋งŒ์กฑ์‹œํ‚ค๋Š” ๊ณผ์ •์ด ์˜ฌ๋ฐ”๋ฅด๋‹ค.

 

โ‘ก swapํ•˜๋Š” heapify() ๊ณผ์ •

 

(1) largest index ๊ตฌํ•˜๊ธฐ

: max heap์„ ๋งŒ๋“ ๋‹ค๊ณ  ๊ฐ€์ •ํ–ˆ์„ ๋•Œ, parent node๋ฅผ A, ๋‘ child node๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•˜๋ฉด ์™ผ์ชฝ๋ถ€ํ„ฐ B, C๋ผ๊ณ  ํ•˜์ž. max heap์ด๋ฏ€๋กœ A์˜ value >= max(B์˜ value, C์˜ value)๋ฅผ ๋ฌด์กฐ๊ฑด ๋งŒ์กฑํ•ด์•ผ ํ•œ๋‹ค. ์ด ๋•Œ ํ•ด๋‹น ๋ถ€๋“ฑ์‹์„ ๋งŒ์กฑ์‹œํ‚ค์ง€ ์•Š๋Š”, ์ฆ‰ B, C์ค‘ A์˜ value๋ณด๋‹ค ๋” ํฐ node๊ฐ€ ์กด์žฌํ•œ๋‹ค๋ฉด largest๋ผ๋Š” index๋ฅผ B ๋˜๋Š” C์˜ index๋กœ ๋ฐ”๊พผ๋‹ค. (๋งŒ์•ฝ B์™€ C ๋‘˜ ๋‹ค A์˜ value๋ณด๋‹ค value๊ฐ’์ด ํฌ๋‹ค๋ฉด C์˜ value๋ฅผ largest๋กœ ๋ฐฐ์ •)

 

(2) ๊ตฌํ•œ largest index๊ณผ ๋ณธ๋ž˜ parent_idx์™€ ๋‹ค๋ฅด๋‹ค๋ฉด?

: largest != parent_idx๋ผ๋ฉด parent node์™€ largest๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” node์™€์˜ value swap ์ง„ํ–‰. ํ•ด๋‹น swap์ดํ›„ largest๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ณธ๋ž˜ child node๋ฅผ parent node๋กœ ์ •ํ•ด ์žฌ๊ท€์ ์œผ๋กœ ์œ„ (1)๊ณผ ํ˜„์žฌ (2)์˜ ๊ณผ์ • ์žฌ๊ท€์ ์œผ๋กœ ์‹คํ–‰

 

(3) ์žฌ๊ท€์ ์œผ๋กœ ์•„๋ž˜ subtree๊นŒ์ง€ ์‹คํ–‰ํ•จ์œผ๋กœ์จ subtree๋ฅผ max-heap์œผ๋กœ ์™„์„ฑ

 

๐ŸŽŠ ex) array [33, 35, 42, 10, 7, 8, 14, 19, 48]์ด ์ฃผ์–ด์กŒ๋‹ค๊ณ  ํ•˜์ž. heapify()์˜ swap ๊ณผ์ • ๊ทธ๋ฆผ ์ผ๋ถ€ ์ฐธ์กฐ.

→ ์•„๋ž˜ ์™ผ์ชฝ ๊ทธ๋ฆผ์—์„œ last non-leaf node (index 3) 10๋ถ€ํ„ฐ reverse iteration ์ง„ํ–‰. (์ฆ‰ index 3 - 2 - 1 - 0์ˆœ์œผ๋กœ swap heapify() ์‹คํ–‰)

→ ์˜ค๋ฅธ์ชฝ ๊ทธ๋ฆผ์€ index 1์ผ ๋•Œ์˜ heapify(). index 1์ผ๋•Œ heapify()๋ฅผ ์ง„ํ–‰ํ•  ๊ฑด๋ฐ, ์ด๋Š” ๊ณง index 2๋ฅผ root node๋กœ ๊ฐ€์ง€๋Š” sub-tree์™€ index3์„ root node๋กœ ๊ฐ€์ง€๋Š” sub-tree๊ฐ€ ์ด๋ฏธ ์™„์„ฑ๋œ ์ƒํƒœ.

๊ทธ ๋‹ค์Œ ์ค„ ์™ผ์ชฝ ๊ทธ๋ฆผ์€ index 1์ผ ๋•Œ์˜ heapify() ๊ทธ๋ฆผ. parent_idx์™€ largest๊ฐ€ ๋‹ค๋ฅด๋ฏ€๋กœ swap ์ง„ํ–‰

→ ๊ทธ ๋‹ค์Œ ์ค„ ์˜ค๋ฅธ์ชฝ ๊ทธ๋ฆผ์€ index 0์ผ ๋•Œ์˜ heapify() ๊ทธ๋ฆผ. parent_idx์™€ largest๊ฐ€ ๋‹ค๋ฅธ ๊ฒฝ์šฐ๊ฐ€ 2๋ฒˆ ์žˆ์œผ๋ฏ€๋กœ swap 2๋ฒˆ ์ง„ํ–‰

∴ ์ตœ์ข… ๊ฒฐ๊ณผ heapify()์˜ ๊ฒฐ๊ณผ๋กœ [48, 35, 42, 33, 7, 8, 14, 19, 10] max heap ์™„์„ฑ

def heapify(arr, n, parent_idx):
    largest = parent_idx
    left = parent_idx*2 + 1
    right = parent_idx*2 + 2

    if left < n and arr[left] > arr[largest]:
        largest = left
    
    if right < n and arr[right] > arr[largest]:
        largest = right
    
    if largest != parent_idx: #if changed
        arr[largest], arr[parent_idx] = arr[parent_idx], arr[largest] #swap
        heapify(arr, n, largest) #if swapped, continue with the lower part

arr = [33, 35, 42, 10, 7, 8, 14, 19, 48]

for i in range((len(arr)-2)//2,-1,-1): #heapify
    heapify(arr, len(arr), i)

print(arr) #[48, 35, 42, 33, 7, 8, 14, 19, 10]

 

โ‘ข Time Complexity: heapfiy() O(N) (๊ฐ node๋ณ„ heapify()๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์‹œํ–‰)

 

(1) ์ด n๊ฐœ์˜ node๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •. ๋ฐ”๋‹ฅ๋ถ€ํ„ฐ h=0, ๊ทธ ๋‹ค์Œ ์ธต h=1๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰๋œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉด, h๋ผ๋Š” ์ธต์— ์กด์žฌํ•˜๋Š” ์ตœ๋Œ€ node ๊ฐœ์ˆ˜๋Š” n/(2^(h+1))

 

(2) last non-leaf node๋ถ€ํ„ฐ root-node๊นŒ์ง€(leaf node๋Š” child node์—†์œผ๋ฏ€๋กœ heapify() ์ง„ํ–‰ ํ•„์š” x) ๊ฐ๊ฐ heapify()๊ฐ€ ์ง„ํ–‰๋œ๋‹ค. ์ด ๋•Œ, heapify()์—์„œ swap์„ ์œ„ํ•œ comparison ํšŸ์ˆ˜๋Š” ์ตœ๋Œ€ ์‹œ์ž‘ node์˜ height๋ผ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ height h์—์„œ์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋Š” O(h) x ⌈(n/2^(h+1))

(O(h)๋Š” ์‹œ์ž‘ node์˜ height๋กœ ์ผ์ • ์ƒ์ˆ˜ c*h๋กœ ํ‘œํ˜„ ๊ฐ€๋Šฅ)

 

(3) ๊ฐ ๋ชจ๋“  ์ธต์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ตฌํ•˜๋ฉด, n๊ฐœ์˜ node์—์„œ ์ธต์˜ ๊ฐœ์ˆ˜๋Š” logn์ด๋ฏ€๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. logn์„ ∞๋กœ ๋ฐ”๊พธ๋ฉด harmonic progression์— ์˜ํ•ด์„œ sigma ๊ฐ’์€ 2๊ฐ€ ๋œ๋‹ค.

(4) c*n์ด๋ฏ€๋กœ heapify()์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋Š” O(n)

โ‘ข deletion in a heap → heapsort

๐ŸŽŠ์ด๋ฏธ ์™„์„ฑ๋œ binary heap์—์„œ ํ•œ ์›์†Œ๋ฅผ deleteํ•œ ๋‹ค๋Š” ๊ฒƒ์€, ๊ฐ€์žฅ ์ƒ์œ„์˜ root node๋ฅผ ๋นผ ์˜จ๋‹ค๋Š” ๋œป์ด๊ณ , max-heap์ผ ๊ฒฝ์šฐ ์›์†Œ์˜ ์ตœ๋Œ“๊ฐ’, min-heap์ผ ๊ฒฝ์šฐ ์›์†Œ์˜ ์ตœ์†Ÿ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋œ๋‹ค. root- node๋ฅผ ๋นผ์˜ค๊ณ  ๋‚จ์€ ์ž๋ฆฌ์—๋Š”, bottom-most right-most element๋ฅผ ๋นผ์˜จ๋‹ค. (array๊ตฌ์กฐ์ƒ index๊ฐ€ ๊ฐ€์žฅ ํฐ, ๋งจ ์˜ค๋ฅธ์ชฝ์˜ ์›์†Œ). ์ด๋ฅผ root node์— ์˜ฌ๋ ค๋†“๋Š”๋‹ค. bottom-most right-most element๋ฅผ ๋นผ์˜ค๋Š” ์ด์œ ๋Š” array์ƒ ๋งจ ์˜ค๋ฅธ์ชฝ ์›์†Œ ๋นผ๋Š” pop() ์—ฐ์‚ฐ์ด O(1) ํšจ์œจ์ ์ด๊ธฐ ๋•Œ๋ฌธ.

 

๐ŸŽŠ ex) ์•„๋ž˜์˜ max heap์—์„œ root node์ด์ž ์ „์ฒด ์›์†Œ์˜ ์ตœ๋Œ“๊ฐ’ 42๋ฅผ ๋นผ๊ณ , bottom-most right-most element 10์„ ๋งจ ์œ„์— ์˜ฌ๋ ค ๋†“๋Š”๋‹ค. ์ด ๋•Œ, ํ•ญ์ƒ max-heap ๊ตฌ์กฐ๋ฅผ ์œ ์ง€ํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ์œ„ โ‘ก ๊ณผ์ •์—์„œ ์ œ์‹œํ•œ heapify() ๊ณผ์ •๋Œ€๋กœ swap ์ง„ํ–‰.
(์ƒˆ๋กœ ๋ฐ”๋€ root-node์™€ child-node๋ฅผ ๋น„๊ต. swap์ด ์ง„ํ–‰๋˜๋ฉด, ์ดํ›„ ์•„๋ž˜ ๋ถ€๋ถ„๊นŒ์ง€ ๋Œ€์†Œ ๊ด€๊ณ„๊ฐ€ max-heap ๊ตฌ์กฐ์— ๋งž์ง€ ์•Š์œผ๋ฉด ๊ณ„์†ํ•ด์„œ swap ์ง„ํ–‰)

๐ŸŽŠ  update๋œ max-heap์„ array ํ˜•ํƒœ๋กœ ํ‘œํ˜„ํ•˜๋ฉด [35, 33, 14, 19, 7, 8, 10]์ด ๋œ๋‹ค. ์ด์™€ ๊ฐ™์ด ๊ณ„์†ํ•ด์„œ root-node deletion์„ ์ง„ํ–‰ํ•˜๋ฉด ์ œ์ผ ํฐ ์ˆ˜๋ถ€ํ„ฐ ์ฐจ๋ก€๋Œ€๋กœ delete๋œ๋‹ค. ๋”ฐ๋ผ์„œ, delete๋œ ์›์†Œ๋ฅผ ์ฐจ๋ก€๋Œ€๋กœ ๋ชจ์œผ๋ฉด, sort๋œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜จ๋‹ค. ์ด sorting์„ heapsort(increasing-order)๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

def max_heap(arr, n, parent_idx):
    largest = parent_idx
    left = parent_idx*2 + 1
    right = parent_idx*2 + 2

    if left < n and arr[left] > arr[largest]:
        largest = left
    
    if right < n and arr[right] > arr[largest]:
        largest = right
    
    if largest != parent_idx: #if changed
        arr[largest], arr[parent_idx] = arr[parent_idx], arr[largest] #swap
        max_heap(arr, n, largest) #if swapped, continue with the lower part

def heapsort(arr):
    
    n = len(arr)

    for i in range((n-1)//2,-1,-1): #(1) building a max heap O(N)
        max_heap(arr, n, i)

    for i in range(n-1,0,-1): #heapsort (until last single element remained)
        arr[i], arr[0] = arr[0], arr[i] #(2) swap with the last and the first(max) element O(1)
        max_heap(arr,i,0) #(3) after swapped, heapify (start with the first element) O(logN)

arr = [33, 35, 42, 10, 7, 8, 14, 19, 48]
heapsort(arr)
print(arr) #[7, 8, 10, 14, 19, 33, 35, 42, 48]

 

โ‘  ์ฃผ์–ด์ง„ array๋ฅผ max heap์œผ๋กœ ๋งŒ๋“ค๊ธฐ: heapify (O(N))

 

โ‘ก max heap์—์„œ root node ๋นผ๊ณ  root node ์ž๋ฆฌ์— bottom-most right-most element ๋„ฃ๊ธฐ (O(1))

 

โ‘ข bottom-most right-most element ์ž๋ฆฌ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€ tree heapify (O(logN))

(*max_heap ๋‘๋ฒˆ์งธ ์ธ์ž i๊ฐ€ node ์ตœ๋Œ“๊ฐ’ ๋ฒˆํ˜ธ์ด๋ฏ€๋กœ sub-tree ๋ฒ”์œ„ ์ œํ•œ ์•Œ ์ˆ˜ ์žˆ์Œ)

 

โ‘ฃ ์œ„ โ‘ก์™€ โ‘ข๊ณผ์ • ๋ฐ˜๋ณต. ๋ฐ˜๋ณตํ•œ ๊ฒฐ๊ณผ heapsort๋กœ ์˜ค๋ฆ„์ฐจ์ˆœ ๋˜๋Š” ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ ์™„์„ฑ. ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” O(N + N*(O(1) + O(logN))) = O(N + N + Nlog(N)) = O(2N + NlogN) = O(NlogN))

 

ex) ์•„๋ž˜ ์˜ˆ์‹œ์—์„œ โ‘  ๊ณผ์ •์œผ๋กœ ์™„์„ฑ๋œ max heap์—์„œ max_value๋ฅผ bottom-most right-most element ์ž๋ฆฌ์™€ swap. ๊ทธ ๊ฒฐ๊ณผ 10์„ root node์— ๋„ฃ๋Š”๋‹ค(O(1)) ๊ทธ ๋‹ค์Œ, root node 10๋ถ€ํ„ฐ heapify ์ง„ํ–‰(O(logn)) (์•„๋ž˜ ์˜ค๋ฅธ์ชฝ ๊ทธ๋ฆผ). ๊ทธ ๊ฒฐ๊ณผ ๊ทธ ๋‹ค์Œ max value 42๋ฅผ 19์™€ swap ์ง„ํ–‰. ๋‚จ์€ node์—์„œ ๊ณ„์† ๊ฐ™์€ ๊ณผ์ • ๋ฐ˜๋ณต.

โ‘ฃ insertion in a heap

๐ŸŽŠ ์ด๋ฏธ ์™„์„ฑ๋œ heap์—์„œ ๋งจ ๋งˆ์ง€๋ง‰์— ์ƒˆ๋กœ์šด ์›์†Œ๋ฅผ insertionํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋•Œ, max-heap์˜ ์„ฑ์งˆ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋ถ€๋ชจ ๋…ธ๋“œ ์›์†Œ์™€ ๊ณ„์† ๋น„๊ตํ•˜๋ฉฐ ์ตœ๋Œ€ root node ์ƒ์œ„๊นŒ์ง€ swap ์ง„ํ–‰. (ํ•˜๋‹จ ๊ทธ๋ฆผ ์ฐธ์กฐ) / ๋งจ ๋งˆ์ง€๋ง‰์— insertion ํ•˜๋Š” ์ด์œ ๋Š”, sub-tree max-heap property๋ฅผ ๊ณ„์† ๋งŒ์กฑ์‹œํ‚ค๊ธฐ ์œ„ํ•จ. (ํ•˜๋‹จ ๊ทธ๋ฆผ 51์„ ๋„ฃ์—ˆ์„ ๊ฒฝ์šฐ ์ƒ์œ„ node ๊นŒ์ง€ 3๋ฒˆ swap)

๐ŸŽŠ ์ฝ”๋“œ๋กœ ๊ตฌํ˜„ ํ–ˆ์„ ๋•Œ(index 0 ์‹œ์ž‘ ๊ธฐ์ค€), child node์˜ index๊ฐ€ i๋ผ๋ฉด, parent node์˜ index๋Š” i//2์ด๋‹ค. index๋กœ parent์™€ child ๋น„๊ตํ•˜๋ฉด์„œ ์ƒ์œ„๊นŒ์ง€ swap ์ง„ํ–‰.

def insert_key(arr,key):
    arr.append(key)
    size=len(arr)
    i=size

    while(i>=1 and arr[i/2] < arr[i]):
        arr[i],arr[i/2] = arr[i/2],arr[i] #swap
        i = (i/2)
    print(arr)

 

๐ŸŽŠ ๋”ฐ๋ผ์„œ 1 node insertion ๊ณผ์ •์€ O(logn) (swap)

โ‘ค extract max(or min) from heap

๐ŸŽŠ  ์ง€๊ธˆ max-heap์„ ๋‹ค๋ฃจ๊ณ  ์žˆ์œผ๋ฏ€๋กœ, heap์˜ ์›์†Œ ์ค‘ ์ตœ๋Œ“๊ฐ’์€ ๊ฐ€์žฅ ์ƒ์œ„ ๋…ธ๋“œ์— ์žˆ๋Š” ๊ฐ’์ด๋‹ค. ๋”ฐ๋ผ์„œ ๋งจ ์œ„์˜ ๋…ธ๋“œ๋ฅผ ๋นผ๊ณ , ๊ทธ ์ž๋ฆฌ์— ๊ฐ€์žฅ ๋์— ์žˆ๋Š” ์›์†Œ๋ฅผ ๊ฐ–๋‹ค ์ค€๋‹ค. (ํ•˜๋‹จ ๊ทธ๋ฆผ ์ฐธ์กฐ). ๋‹ค๋งŒ max heap ์„ฑ์งˆ์„ ๊ณ„์† ์œ ์ง€ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๊ฐ€์žฅ ๋์— ์žˆ๋Š” ์›์†Œ๊ฐ€ root- node๊ฐ€ ๋œ ์ดํ›„ heapify() ์œ„ ๊ณผ์ • ๋™์ผํ•˜๊ฒŒ ์ง„ํ–‰. ์‹œ๊ฐ„๋ณต์žก๋„๋Š” O(1) + O(logn)์œผ๋กœ O(logn)

 

def delete_max(arr):
    size=len(arr)
    if size < 1:
        print('Error')
    
    max_root = arr[0]
    arr[0] = arr[size]
    size=size-1

    A=max_heapify(arr[:size],1)
    return max_root

๐ŸŽŠBinary Heap Time Complexity 


heap youtube

binary heap wiki 

 

'Computer Science > Data Structures' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

โžก๏ธ Linked List  (0) 2024.09.26
๐ŸŒ‰ Monotonic Stack  (0) 2024.09.23
๐ŸฅชArray & Linked List Intro  (2) 2024.01.08
๐ŸŒณ Binary Tree ๐ŸŒณ  (1) 2023.12.19
๐Ÿ“š Map  (0) 2023.08.03

๋Œ“๊ธ€