ํฌ์ŠคํŠธ

CS โ€” list sort

CS โ€” list sort

๐Ÿ“• 05/06 โ€” std::list::sort vs std::sort (์™œ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๊ฐ€ ๋”ฐ๋กœ ์žˆ๋Š”๊ฐ€)

๋ชจ์˜๋ฉด์ ‘ ์ฃผ์ œ: โ€œstd::list::sort()๊ฐ€ std::sort() ๋Œ€์‹  ๋”ฐ๋กœ ์กด์žฌํ•˜๋Š” ์ด์œ ์— ๋Œ€ํ•ด์„œ ์„ค๋ช…ํ•ด ์ฃผ์„ธ์š”โ€ iterator ์นดํ…Œ๊ณ ๋ฆฌ โ†’ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์„ ํƒ โ†’ ๋…ธ๋“œ ์žฌ์—ฐ๊ฒฐ vs ๋ฐ์ดํ„ฐ ์ด๋™ โ†’ stable ์—ฌ๋ถ€ โ†’ forward_listยทset/map::find ํŒจํ„ด๊นŒ์ง€


ํ•™์Šต ์˜์—ญ ์ „ํ™˜์  โ€” ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ ์ž๋ฃŒ๊ตฌ์กฐ์˜ ๊ฒฐํ•ฉ

17๋ฒˆ์—์„œ std::find vs std::binary_search๋กœ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํ•จ์ˆ˜์˜ ๋ถ„์—… ์„ค๊ณ„๋ฅผ ๋ดค๋‹ค๋ฉด, 18๋ฒˆ์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ ์ž๋ฃŒ๊ตฌ์กฐ๊ฐ€ ๋งŒ๋‚˜๋Š” ์ง€์ ์ž…๋‹ˆ๋‹ค. std::sort๋Š” RandomAccessIterator๋ฅผ ์š”๊ตฌํ•˜๋Š” ์ผ๋ฐ˜ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๊ณ , std::list::sort๋Š” ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ํŠน์„ฑ์— ๋งž์ถ˜ ๋ฉค๋ฒ„ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

1
2
3
4
17๋ฒˆ  std::find vs binary_search          โ€” ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํ•จ์ˆ˜ (์„ ํ˜• vs ์ด๋ถ„)
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
18๋ฒˆ  std::list::sort vs std::sort โ˜…      โ€” ๋ฉค๋ฒ„ ํ•จ์ˆ˜ vs ์•Œ๊ณ ๋ฆฌ์ฆ˜ (์™œ ๋”ฐ๋กœ?)
์ดํ›„  custom comparator / partial_sort    โ€” ์ •๋ ฌ family ํ™•์žฅ

์ด ์ฃผ์ œ๋Š” 17๋ฒˆ์˜ 9-1 iterator ์นดํ…Œ๊ณ ๋ฆฌ(InputIterator โ†’ ForwardIterator โ†’ BidirectionalIterator โ†’ RandomAccessIterator)๋ฅผ ๊ทธ๋Œ€๋กœ ์ด์–ด๋ฐ›์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  set/map์—์„œ ๋ฉค๋ฒ„ ํ•จ์ˆ˜ find()๋ฅผ ์จ์•ผ ํ•˜๋Š” ์ด์œ (15๋ฒˆ~17๋ฒˆ์—์„œ ๋ณธ ๊ทธ ์ปจ๋ฒค์…˜)์™€๋„ ๊ฐ™์€ ๋งฅ๋ฝ์ž…๋‹ˆ๋‹ค โ€” ์ž๋ฃŒ๊ตฌ์กฐ์˜ ํŠน์„ฑ์„ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ํ™œ์šฉํ•  ์ˆ˜ ์—†์„ ๋•Œ, ๋ฉค๋ฒ„ ํ•จ์ˆ˜๊ฐ€ ๋”ฐ๋กœ ์กด์žฌํ•œ๋‹ค.


๋ชจ์˜๋ฉด์ ‘ ๋‹ต๋ณ€

std::sort๋Š” <algorithm> ํ—ค๋”์˜ ์ผ๋ฐ˜ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๊ณ , std::list::sort๋Š” std::list์˜ ๋ฉค๋ฒ„ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ๋‘˜์ด ๋”ฐ๋กœ ์กด์žฌํ•˜๋Š” ์ด์œ ๋Š” ํฌ๊ฒŒ ์„ธ ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค.

์ฒซ์งธ, iterator ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. std::sort๋Š” RandomAccessIterator๋ฅผ ์š”๊ตฌํ•ฉ๋‹ˆ๋‹ค. ์ค‘๊ฐ„์— it + n ๊ฐ™์€ ์ ํ”„๋‚˜ it[i] ์ธ๋ฑ์‹ฑ์ด ๊ฐ€๋Šฅํ•ด์•ผ quicksort์˜ partition์ด ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ std::list::iterator๋Š” BidirectionalIterator๊นŒ์ง€๋งŒ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค โ€” ++it, --it์€ ๋˜์ง€๋งŒ it + n์€ ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ std::sort(list.begin(), list.end())๋Š” ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋‚ฉ๋‹ˆ๋‹ค. ์ด๊ฒŒ ๊ฐ€์žฅ ์ง์ ‘์ ์ธ ์ด์œ ์ž…๋‹ˆ๋‹ค.

๋‘˜์งธ, ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ž์ฒด๊ฐ€ ๋‹ฌ๋ผ์•ผ ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค. std::sort๋Š” ๋ณดํ†ต introsort๋กœ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค โ€” quicksort๋กœ ์‹œ์ž‘ํ•ด์„œ ์žฌ๊ท€ ๊นŠ์ด๊ฐ€ ๊นŠ์–ด์ง€๋ฉด heapsort๋กœ ํด๋ฐฑํ•˜๊ณ , ์ž‘์€ ๊ตฌ๊ฐ„์€ insertion sort๋กœ ๋งˆ๋ฌด๋ฆฌํ•˜๋Š” ํ•˜์ด๋ธŒ๋ฆฌ๋“œ์ž…๋‹ˆ๋‹ค. ๋ฌด์ž‘์œ„ ์ ‘๊ทผ์œผ๋กœ partition์„ ๋น ๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ „์ œ ์œ„์—์„œ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด std::list::sort๋Š” ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort) ๊ธฐ๋ฐ˜์ž…๋‹ˆ๋‹ค. ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋Š” ํฌ์ธํ„ฐ ์žฌ์—ฐ๊ฒฐ๋งŒ์œผ๋กœ ๋‘ ์ •๋ ฌ ๋ฆฌ์ŠคํŠธ๋ฅผ ํ•ฉ์น  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ๊ณ , ๋ฐ์ดํ„ฐ ์ž์ฒด๋ฅผ ์˜ฎ๊ธธ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์…‹์งธ, ๊ทธ ๊ฒฐ๊ณผ ๋น„์šฉ ๊ตฌ์กฐ๊ฐ€ ์™„์ „ํžˆ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค. ๋‘˜ ๋‹ค ์‹œ๊ฐ„๋ณต์žก๋„๋Š” O(n log n)์ด์ง€๋งŒ, std::list::sort๋Š” ๋น„๊ต ์™ธ ๋ฐ์ดํ„ฐ ์ด๋™ ๋น„์šฉ์ด 0์ž…๋‹ˆ๋‹ค โ€” ๋…ธ๋“œ์˜ prev/next ํฌ์ธํ„ฐ๋งŒ swapํ•˜๋‹ˆ๊นŒ์š”. std::sort๋Š” partition ๊ณผ์ •์—์„œ ์›์†Œ ์ž์ฒด๋ฅผ swapํ•ฉ๋‹ˆ๋‹ค. ํฐ ๊ฐ์ฒด๋ฅผ ๋‹ด์€ ์ปจํ…Œ์ด๋„ˆ๋ผ๋ฉด ์ด ์ฐจ์ด๊ฐ€ ์‹ค์ธก ์„ฑ๋Šฅ์— ํฐ ์˜ํ–ฅ์„ ์ค๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  std::list::sort๋Š” stable sort์ด๊ณ  ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๋„ O(1)(in-place merge)์ž…๋‹ˆ๋‹ค.

์ด๊ฒŒ STL ์ „๋ฐ˜์˜ ์ผ๊ด€๋œ ์„ค๊ณ„์ž…๋‹ˆ๋‹ค. set์ด๋‚˜ map์—์„œ std::find ๋Œ€์‹  ๋ฉค๋ฒ„ find()๋ฅผ ์“ฐ๋Š” ์ด์œ ์™€ ๋˜‘๊ฐ™์Šต๋‹ˆ๋‹ค โ€” ์ž๋ฃŒ๊ตฌ์กฐ์˜ ํŠน์„ฑ์„ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ํ™œ์šฉํ•  ์ˆ˜ ์—†์„ ๋•Œ, ๋ฉค๋ฒ„ ํ•จ์ˆ˜๊ฐ€ ๋”ฐ๋กœ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. forward_list::sort๋„ ๊ฐ™์€ ์ด์œ ๋กœ ๋”ฐ๋กœ ์žˆ๊ณ , ์ด๋Ÿฐ ํŒจํ„ด์ด STL์˜ โ€œ๋ฉค๋ฒ„ vs ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ถ„์—…โ€ ์ปจ๋ฒค์…˜์ž…๋‹ˆ๋‹ค.


ํ•ต์‹ฌ ๊ฐœ๋…

๋ถ„๋ฅ˜ํ‚ค์›Œ๋“œํ•œ ์ค„ ์ •์˜
ํ•จ์ˆ˜ ์ •์˜std::sort<algorithm> ํ—ค๋”, RandomAccessIterator ์š”๊ตฌ, introsort
ย std::list::sortstd::list ๋ฉค๋ฒ„ ํ•จ์ˆ˜, BidirectionalIterator๋กœ OK, ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)
ย std::forward_list::sortstd::forward_list ๋ฉค๋ฒ„ ํ•จ์ˆ˜, ForwardIterator๋กœ OK, ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)
iterator ์นดํ…Œ๊ณ ๋ฆฌRandomAccessIteratorit + n, it[i] ๊ฐ€๋Šฅ (vectorยทdequeยทarray)
ย BidirectionalIterator++it, --it๋งŒ ๊ฐ€๋Šฅ (listยทsetยทmap)
ย ForwardIterator++it๋งŒ ๊ฐ€๋Šฅ (forward_list)
์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜introsortquicksort + heapsort + insertion sort ํ•˜์ด๋ธŒ๋ฆฌ๋“œ. std::sort ๊ตฌํ˜„
ย ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)๋‘ ์ •๋ ฌ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ณ‘ํ•ฉ. list::sort ๊ธฐ๋ฐ˜ โ€” ํฌ์ธํ„ฐ ์žฌ์—ฐ๊ฒฐ๋งŒ
ย partition (quicksort)pivot ๊ธฐ์ค€ ์ขŒ/์šฐ ๋ถ„ํ• . ๋ฌด์ž‘์œ„ ์ ‘๊ทผ ํ•„์ˆ˜
์‹œ๊ฐ„๋ณต์žก๋„O(n log n)๋‘˜ ๋‹ค ๋™์ผ. ์ด๋ก ๊ฐ’์€ ๊ฐ™์Œ
ย ๋ฐ์ดํ„ฐ ์ด๋™ ๋น„์šฉstd::sort โ€” swap ๋‹ค์ˆ˜ / list::sort โ€” 0 (ํฌ์ธํ„ฐ๋งŒ)
์•ˆ์ •์„ฑstable sort๋™๋“ฑ ์›์†Œ์˜ ์ƒ๋Œ€ ์ˆœ์„œ ์œ ์ง€. list::sort๋Š” stable
ย unstablestd::sort๋Š” ๋น„์•ˆ์ •. ์•ˆ์ •์„ฑ ํ•„์š”ํ•˜๋ฉด std::stable_sort
์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌO(1) in-placelist::sort๋Š” ๋…ธ๋“œ ์žฌ์—ฐ๊ฒฐ๋งŒ โ€” ์ถ”๊ฐ€ ํ• ๋‹น X
ย O(log n) ์Šคํƒstd::sort (์žฌ๊ท€ ๊นŠ์ด)
๋น„๊ต ํ•จ์ˆ˜strict weak ordering๋‘˜ ๋‹ค < ๋˜๋Š” ์‚ฌ์šฉ์ž ๋น„๊ต์ž ์š”๊ตฌ
์ปดํŒŒ์ผ ์—๋Ÿฌstd::sort(list) ์‹œ๋„error: no match for 'operator-' ๋“ฑ โ€” RandomAccess ๋ถ€์žฌ
๊ด€๋ จ ์•Œ๊ณ ๋ฆฌ์ฆ˜std::stable_sort์•ˆ์ • ์ •๋ ฌ. ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ O(n) ๋˜๋Š” O(n logยฒ n)
ย std::partial_sort์ƒ์œ„ k๊ฐœ๋งŒ ์ •๋ ฌ. heap ๊ธฐ๋ฐ˜ O(n log k)
ย std::nth_elementk๋ฒˆ์งธ ์›์†Œ๋งŒ ์ œ์ž๋ฆฌ์—. O(n) ํ‰๊ท 
๋ฉค๋ฒ„ vs ์•Œ๊ณ ๋ฆฌ์ฆ˜set/map::findํŠธ๋ฆฌ O(log n) โ€” ์•Œ๊ณ ๋ฆฌ์ฆ˜ std::find๋Š” O(n)์ด๋ผ ์†ํ•ด
ย unordered_map::findํ•ด์‹œ O(1) ํ‰๊ท 
ย list::sort๋…ธ๋“œ ์žฌ์—ฐ๊ฒฐ๋กœ O(n log n) โ€” ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์ปดํŒŒ์ผ X
ย forward_list::sort๋‹จ๋ฐฉํ–ฅ์ด๋ผ ๋”๋”์šฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ถˆ๊ฐ€
์–ธ๋ฆฌ์–ผAlgo::Sortstd::sort ๋Œ€์‘. TArray ๋“ฑ RandomAccess ์ปจํ…Œ์ด๋„ˆ์šฉ
ย TArray::Sort๋ฉค๋ฒ„ ํ•จ์ˆ˜. introsort ๊ธฐ๋ฐ˜
ย TArray::StableSort์•ˆ์ • ์ •๋ ฌ ๋ฉค๋ฒ„ ํ•จ์ˆ˜
ย TLinkedListํ—ฌํผ ์ˆ˜์ค€. ์ •๋ ฌ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋Š” ๋”ฐ๋กœ ์—†์Œ (์ˆ˜๋™ ๊ตฌํ˜„ ํ•„์š”)

๋ชฉ์ฐจ

  1. ํ•ต์‹ฌ ์š”์•ฝ ์นด๋“œ
  2. ์ปดํŒŒ์ผ ์—๋Ÿฌ๋ถ€ํ„ฐ โ€” ์™œ std::sort(list)๋Š” ์•ˆ ๋˜๋‚˜
  3. iterator ์นดํ…Œ๊ณ ๋ฆฌ ๋ณต๊ธฐ โ€” 17๋ฒˆ 9-1๊ณผ์˜ ์—ฐ๊ฒฐ
  4. ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ฐจ์ด โ€” introsort vs ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)
  5. ๋…ธ๋“œ ์žฌ์—ฐ๊ฒฐ โ€” ๋ฐ์ดํ„ฐ ์ด๋™ ๋น„์šฉ 0์˜ ์˜๋ฏธ
  6. stable ์—ฌ๋ถ€ / ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ๋น„๊ต
  7. forward_list::sort โ€” ๊ฐ™์€ ์ด์œ ๋กœ ๋˜ ๋”ฐ๋กœ
  8. ๋ฉค๋ฒ„ vs ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ปจ๋ฒค์…˜ โ€” set/map::find์™€ ๊ฐ™์€ ํŒจํ„ด
  9. ๊ด€๋ จ ์ •๋ ฌ family โ€” stable_sort / partial_sort / nth_element
  10. ์–ธ๋ฆฌ์–ผ์—์„œ์˜ ์ •๋ ฌ โ€” Algo::Sort / TArray::Sort / TLinkedList
  11. ๊ผฌ๋ฆฌ์งˆ๋ฌธ ์˜ˆ์ƒ ๊ฒฝ๋กœ

1. ํ•ต์‹ฌ ์š”์•ฝ ์นด๋“œ

30์ดˆ ๋‹ต๋ณ€

1
2
3
4
5
6
7
8
9
10
std::sort        = <algorithm>, RandomAccessIterator ์š”๊ตฌ, introsort, unstable, swap
std::list::sort  = list ๋ฉค๋ฒ„ ํ•จ์ˆ˜, BidirectionalIterator๋กœ OK, ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort), stable, ํฌ์ธํ„ฐ ์žฌ์—ฐ๊ฒฐ

์ด์œ  3๊ฐ€์ง€:
  โ‘  iterator ์นดํ…Œ๊ณ ๋ฆฌ ์ฐจ์ด โ€” list::iterator๋Š” RandomAccess ์•„๋‹˜ โ†’ ์ปดํŒŒ์ผ ์—๋Ÿฌ
  โ‘ก ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๋‹ค๋ฆ„ โ€” quicksort partition์€ ๋ฌด์ž‘์œ„ ์ ‘๊ทผ ํ•„์ˆ˜, list์—” ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)๊ฐ€ ์ตœ์ 
  โ‘ข ๋น„์šฉ ๊ตฌ์กฐ โ€” list::sort๋Š” ๋…ธ๋“œ ํฌ์ธํ„ฐ๋งŒ ์žฌ์—ฐ๊ฒฐ, ๋ฐ์ดํ„ฐ ์ด๋™ 0

๊ฐ™์€ ํŒจํ„ด: set/map::find vs std::find, forward_list::sort
โ†’ "์ž๋ฃŒ๊ตฌ์กฐ ํŠน์„ฑ์„ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๋ชป ์‚ด๋ฆด ๋•Œ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๊ฐ€ ๋”ฐ๋กœ ์กด์žฌํ•œ๋‹ค"

๊ผฌ๋ฆฌ์งˆ๋ฌธ ์—ฐ๊ฒฐ ๋งต

1
2
3
4
5
6
7
8
9
10
11
12
std::list::sort vs std::sort
โ”œโ”€โ”€ ์™œ std::sort(list)๋Š” ์ปดํŒŒ์ผ ์—๋Ÿฌ? โ†’ list iterator๋Š” BidirectionalIterator
โ”‚   โ””โ”€โ”€ 17๋ฒˆ 9-1 iterator ์นดํ…Œ๊ณ ๋ฆฌ (Random Access ํ•„์š”)
โ”œโ”€โ”€ ์™œ list์—” ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)๊ฐ€ ์ตœ์ ? โ†’ ํฌ์ธํ„ฐ ์žฌ์—ฐ๊ฒฐ๋กœ in-place merge๊ฐ€ ์ž์—ฐ์Šค๋Ÿฌ์›€
โ”‚   โ””โ”€โ”€ quicksort partition์€ ๋ฌด์ž‘์œ„ ์ ‘๊ทผ ํ•„์š”
โ”œโ”€โ”€ ๋‘˜ ๋‹ค O(n log n)์ธ๋ฐ ๋ญ๊ฐ€ ๋‹ค๋ฆ„? โ†’ ๋ฐ์ดํ„ฐ ์ด๋™ ๋น„์šฉ (swap vs ํฌ์ธํ„ฐ)
โ”œโ”€โ”€ stable ์—ฌ๋ถ€? โ†’ list::sort๋Š” stable / std::sort๋Š” unstable
โ”‚   โ””โ”€โ”€ ์•ˆ์ • ์ •๋ ฌ ํ•„์š”ํ•˜๋ฉด std::stable_sort
โ”œโ”€โ”€ forward_list๋Š”? โ†’ forward_list::sort ๋”ฐ๋กœ ์กด์žฌ (ForwardIterator๋ผ ๋” ์ œํ•œ์ )
โ”œโ”€โ”€ ๊ฐ™์€ ํŒจํ„ด? โ†’ set/map::find, unordered_map::find (๋ฉค๋ฒ„ vs ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ปจ๋ฒค์…˜)
โ””โ”€โ”€ ์ •๋ ฌ family โ†’ stable_sort / partial_sort / nth_element
    โ””โ”€โ”€ 13๋ฒˆ vector vs list, 16๋ฒˆ STL ์ปจํ…Œ์ด๋„ˆ ์ •๋ฆฌ๋กœ ํšŒ๊ท€

2. ์ปดํŒŒ์ผ ์—๋Ÿฌ๋ถ€ํ„ฐ โ€” ์™œ std::sort(list)๋Š” ์•ˆ ๋˜๋‚˜

ํ•ต์‹ฌ ํ•œ ๋ฌธ์žฅ

std::sort๋Š” RandomAccessIterator๋ฅผ ์š”๊ตฌํ•˜๋Š”๋ฐ std::list::iterator๋Š” BidirectionalIterator๋ผ์„œ, ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ ๊ฑฐ๋ถ€๋ฉ๋‹ˆ๋‹ค.

์‹œ๋„ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋‚˜

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <algorithm>
#include <list>

int main() {
    std::list<int> lst = {3, 1, 4, 1, 5, 9, 2, 6};

    std::sort(lst.begin(), lst.end());   // โ˜… ์ปดํŒŒ์ผ ์—๋Ÿฌ
    // GCC ๋ฉ”์‹œ์ง€ (์š”์ง€):
    // error: no match for 'operator-' (operand types are
    //   'std::_List_iterator<int>' and 'std::_List_iterator<int>')
    //
    // โ†’ std::sort ๋‚ด๋ถ€์—์„œ (last - first)๋กœ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ์„ ์‹œ๋„ํ•˜๋Š”๋ฐ,
    //   list iterator๋Š” - ์—ฐ์‚ฐ์ž๊ฐ€ ์ •์˜๋ผ ์žˆ์ง€ ์•Š์Œ.
}

โ†’ std::sort ๊ตฌํ˜„ ์–ด๋””์„ ๊ฐ€ mid = first + (last - first) / 2 ๊ฐ™์€ ๋ฌด์ž‘์œ„ ์ ํ”„๋ฅผ ํ•ฉ๋‹ˆ๋‹ค. list iterator๋Š” ๊ทธ ์—ฐ์‚ฐ์„ ์ง€์›ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ํ…œํ”Œ๋ฆฟ ์ธ์Šคํ„ด์Šคํ™” ๋‹จ๊ณ„์—์„œ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

์ •๋‹ต โ€” ๋ฉค๋ฒ„ ํ•จ์ˆ˜ ์‚ฌ์šฉ

1
2
3
4
std::list<int> lst = {3, 1, 4, 1, 5, 9, 2, 6};
lst.sort();                              // โ˜… OK โ€” ์˜ค๋ฆ„์ฐจ์ˆœ
lst.sort(std::greater<int>());           // ๋‚ด๋ฆผ์ฐจ์ˆœ (๋น„๊ต์ž)
lst.sort([](int a, int b){ return a > b; });   // ๋žŒ๋‹ค๋„ ๊ฐ€๋Šฅ

โ†’ ์ธ์ž ์—†์ด ํ˜ธ์ถœํ•˜๋ฉด < ๊ธฐ๋ณธ, ๋น„๊ต์ž ์ธ์ž๋กœ strict weak ordering์„ ๋งŒ์กฑํ•˜๋Š” ํ•จ์ˆ˜ ๊ฐ์ฒด๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ™์€ ํ•จ์ˆ˜๋ช…์˜ ๋‹ค๋ฅธ ์ผ€์ด์Šค โ€” vector / deque / array

1
2
3
4
5
6
7
8
9
std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};
std::sort(v.begin(), v.end());   // OK โ€” RandomAccessIterator
// vector์—๋Š” ๋ฉค๋ฒ„ sort()๊ฐ€ ์—†์Œ โ€” ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ์ถฉ๋ถ„ํ•˜๋‹ˆ๊นŒ

std::deque<int> dq = {3, 1, 4};
std::sort(dq.begin(), dq.end()); // OK โ€” deque๋„ RandomAccess

std::array<int, 4> ar = {3, 1, 4, 1};
std::sort(ar.begin(), ar.end()); // OK

โ†’ RandomAccess๋ฅผ ์ง€์›ํ•˜๋Š” ์ปจํ…Œ์ด๋„ˆ์—๋Š” ๋ฉค๋ฒ„ sort๊ฐ€ ์—†๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์€ list/forward_list์—๋งŒ ๋ฉค๋ฒ„ sort๊ฐ€ ๋”ฐ๋กœ ์žˆ๋‹ค๋Š” ๋น„๋Œ€์นญ์ด ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํ•จ์ˆ˜๋กœ ์ถฉ๋ถ„ํ•˜๋ฉด ๋ฉค๋ฒ„๋ฅผ ์•ˆ ๋งŒ๋“œ๋Š” ๊ฒŒ STL ์ปจ๋ฒค์…˜์ž…๋‹ˆ๋‹ค.


3. iterator ์นดํ…Œ๊ณ ๋ฆฌ ๋ณต๊ธฐ โ€” 17๋ฒˆ 9-1๊ณผ์˜ ์—ฐ๊ฒฐ

ํ•ต์‹ฌ ํ•œ ๋ฌธ์žฅ

17๋ฒˆ์—์„œ ์ •๋ฆฌํ•œ iterator ์นดํ…Œ๊ณ ๋ฆฌ(Input โ†’ Forward โ†’ Bidirectional โ†’ RandomAccess)๊ฐ€ ๊ทธ๋Œ€๋กœ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์„ ํƒ์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค โ€” list๊ฐ€ ํ•œ ๋‹จ๊ณ„ ๋ถ€์กฑํ•˜๋‹ค๋Š” ์‚ฌ์‹ค์ด ๋ชจ๋“  ์ฐจ์ด์˜ ์ถœ๋ฐœ์ ์ž…๋‹ˆ๋‹ค.

์นดํ…Œ๊ณ ๋ฆฌ ํ‘œ (17๋ฒˆ 9-1 ์žฌํ™œ์šฉ)

์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€๋Šฅ ์—ฐ์‚ฐ๋Œ€ํ‘œ ์ปจํ…Œ์ด๋„ˆsort ๊ฐ€๋Šฅ?
Input++it, *it(์ฝ๊ธฐ 1ํšŒ)istream_iteratorX
Forward+ ์—ฌ๋Ÿฌ ๋ฒˆ ์ฝ๊ธฐforward_list๋ฉค๋ฒ„ sort() ๋งŒ
Bidirectional+ --it ์—ญ๋ฐฉํ–ฅlist, set, map๋ฉค๋ฒ„ sort() (list๋งŒ)
RandomAccess+ it + n, it[n], it < it2vector, deque, arraystd::sort OK

BidirectionalIterator ์ž์„ธํžˆ โ€” โ€œํ•œ ์นธ์”ฉ ์•žยท๋’คโ€๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์˜๋ฏธ

โ€œlist::iterator๋Š” BidirectionalIterator๋‹คโ€๋ผ๋Š” ๋ง์€ ์•žยท๋’ค ์–‘๋ฐฉํ–ฅ์œผ๋กœ ํ•œ ์นธ์”ฉ๋งŒ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค. ์ ํ”„(it+5)๋‚˜ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ(it2-it1)์€ ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

์ง€์›ยท๋น„์ง€์› ์—ฐ์‚ฐ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
std::list<int> lst = {1, 2, 3, 4, 5};
auto it = lst.begin();

// โœ… ๊ฐ€๋Šฅ (Bidirectional ๋ณด์žฅ)
++it;        // ์•ž์œผ๋กœ 1์นธ    O(1)
--it;        // ๋’ค๋กœ 1์นธ      O(1)  โ† Forward์™€ ๋‹ค๋ฅธ ์ 
*it;         // ์—ญ์ฐธ์กฐ ์ฝ๊ธฐ/์“ฐ๊ธฐ
it == it2;   // ๋™๋“ฑ ๋น„๊ต
it != it2;   // ๋น„๋™๋“ฑ ๋น„๊ต

// โŒ ๋ถˆ๊ฐ€๋Šฅ (RandomAccess๋งŒ ๊ฐ€๋Šฅ)
it + 5;      // ์ปดํŒŒ์ผ ์—๋Ÿฌ โ€” ์ ํ”„
it - it2;    // ์ปดํŒŒ์ผ ์—๋Ÿฌ โ€” ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ
it[3];       // ์ปดํŒŒ์ผ ์—๋Ÿฌ โ€” ์ธ๋ฑ์‹ฑ
it < it2;    // ์ปดํŒŒ์ผ ์—๋Ÿฌ โ€” ์ˆœ์„œ ๋น„๊ต

โ€œ์™œโ€ ์–‘๋ฐฉํ–ฅ๊นŒ์ง€๋งŒ ๊ฐ€๋Šฅํ•œ๊ฐ€ โ€” list ๋…ธ๋“œ ๊ตฌ์กฐ ๋•Œ๋ฌธ

1
2
3
4
5
list ๋…ธ๋“œ:  [prev | data | next] โ†โ†’ [prev | data | next] โ†โ†’ ...

++it  โ†’ ํ˜„์žฌ ๋…ธ๋“œ์˜ next ๋”ฐ๋ผ๊ฐ€๊ธฐ   O(1)  (ํฌ์ธํ„ฐ ํ•œ ๋ฒˆ)
--it  โ†’ ํ˜„์žฌ ๋…ธ๋“œ์˜ prev ๋”ฐ๋ผ๊ฐ€๊ธฐ   O(1)  (Bidirectional์˜ ํ•ต์‹ฌ โ€” Forward์— ์—†๋Š” ๋Šฅ๋ ฅ)
it+5  โ†’ next๋ฅผ 5๋ฒˆ ๋”ฐ๋ผ๊ฐ€์•ผ ํ•จ      O(n)  โ† STL์ด ์˜๋„์ ์œผ๋กœ ๋ง‰์Œ

โ†’ ๋…ธ๋“œ๋Š” ๋ฉ”๋ชจ๋ฆฌ์— ๋ถ„์‚ฐ๋˜์–ด ์žˆ์–ด์„œ 5๋ฒˆ์งธ ๋…ธ๋“œ์˜ ์ฃผ์†Œ๋ฅผ ํ•œ ๋ฒˆ์— ๊ณ„์‚ฐํ•  ์ˆ˜๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋ฌด์ž‘์œ„ ์ ‘๊ทผ์„ ํ‰๋‚ด๋‚ด๋ ค๋ฉด next๋ฅผ 5๋ฒˆ ๋”ฐ๋ผ๊ฐ€์•ผ ํ•˜๊ณ  ๊ทธ๊ฑด O(n)์ž…๋‹ˆ๋‹ค. STL์€ โ€œ๋А๋ฆฐ ์—ฐ์‚ฐ์€ ์•„์˜ˆ ํ‘œํ˜„ํ•  ์ˆ˜ ์—†๊ฒŒ ํ•˜๋ผโ€๋Š” ์ฒ ํ•™์ด๋ผ ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ ๋ง‰์Šต๋‹ˆ๋‹ค.

์นดํ…Œ๊ณ ๋ฆฌ ๊ณ„์ธต โ€” ์ƒ์œ„๋Š” ํ•˜์œ„์˜ ๋ชจ๋“  ๋Šฅ๋ ฅ์„ ํฌํ•จ

1
2
3
4
5
6
RandomAccess  โŠƒ  Bidirectional  โŠƒ  Forward  โŠƒ  Input

RandomAccess  โ†’ ++ -- it+n it[n] *it ๋‹ค ๊ฐ€๋Šฅ
Bidirectional โ†’ ++ -- *it       (it+n ์—†์Œ)
Forward       โ†’ ++ *it          (-- ๋„ ์—†์Œ)
Input         โ†’ ++ *it          (1ํšŒ ์ฝ๊ธฐ๋งŒ)

โ†’ Bidirectional์ด Forward์˜ ์ƒ์œ„์ด๋ฏ€๋กœ, ForwardIterator๋ฅผ ์š”๊ตฌํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜(std::find, std::count ๋“ฑ)์€ list iterator๋กœ๋„ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋Œ€๋กœ RandomAccess๋ฅผ ์š”๊ตฌํ•˜๋Š” std::sort๋Š” list iterator๋กœ ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

์™œ RandomAccess๊ฐ€ ํ•„์š”ํ•œ๊ฐ€ โ€” quicksort ์‹œ๊ฐ

quicksort์˜ ํ•ต์‹ฌ์€ partition์ž…๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
[3, 1, 4, 1, 5, 9, 2, 6]
       pivot = 4
       โ†“
์ขŒ(< 4) | ์šฐ(โ‰ฅ 4) ๋กœ ๋ถ„ํ• 
[3, 1, 1, 2] | [4, 5, 9, 6]

๋ถ„ํ•  ๊ณผ์ •:
  โ‘  pivot ์„ ํƒ โ€” ๋ณดํ†ต mid = first + (last-first)/2  โ† ๋ฌด์ž‘์œ„ ์ ‘๊ทผ
  โ‘ก ์–‘ ๋์—์„œ ์‹œ์ž‘ํ•ด left++, right-- ํ•˜๋ฉฐ swap     โ† --it๋„ ํ•„์š”
  โ‘ข ์žฌ๊ท€ ํ˜ธ์ถœ ์‹œ leftยทright ๋ถ€๋ถ„ ๊ตฌ๊ฐ„ ์ธ๋ฑ์‹ฑ       โ† it + n

โ†’ list iterator๋กœ๋Š” โ‘ก ์˜ ์–‘ ๋์—์„œ ๋งŒ๋‚˜๊ธฐ๊นŒ์ง€์˜ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ์ด O(n)์ด๊ณ , โ‘  ์˜ mid ์ ํ”„๋„ O(n)์ด์–ด์„œ ์ด๋ก  ์‹œ๊ฐ„๋ณต์žก๋„๋ถ€ํ„ฐ ๊นจ์ง‘๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ quicksort๋Š” list์— ๋ถ€์ ํ•ฉ.

partition ๊ณผ์ • ์ž์„ธํžˆ โ€” quicksort์˜ ์‹ฌ์žฅ

partition์€ โ€œpivot ๊ธฐ์ค€์œผ๋กœ ์ขŒ์šฐ๋ฅผ ๋‚˜๋ˆ„๋Š” ํ•œ ๋‹จ๊ณ„โ€œ์ž…๋‹ˆ๋‹ค. quicksort ์ „์ฒด ๋น„์šฉ์˜ ๋Œ€๋ถ€๋ถ„์ด partition์—์„œ ๋ฐœ์ƒํ•˜๊ณ , ์•ˆ์ •์„ฑยท์‹œ๊ฐ„๋ณต์žก๋„๊ฐ€ ๋ชจ๋‘ partition ๋ฐฉ์‹์— ์ขŒ์šฐ๋ฉ๋‹ˆ๋‹ค.

Lomuto partition (๋‹จ์ˆœํ•œ ๋ฒ„์ „, ๊ต๊ณผ์„œ์šฉ)

1
2
3
4
5
6
7
8
9
10
11
12
int partition(arr, lo, hi) {
    int pivot = arr[hi];      // ๋ณดํ†ต ๋งˆ์ง€๋ง‰ ์›์†Œ๋ฅผ pivot์œผ๋กœ
    int i = lo - 1;            // i: 'pivot๋ณด๋‹ค ์ž‘์€ ์›์†Œ๋“ค์˜ ๋'
    for (int j = lo; j < hi; ++j) {
        if (arr[j] < pivot) {
            ++i;
            swap(arr[i], arr[j]);
        }
    }
    swap(arr[i+1], arr[hi]);   // pivot์„ ๊ฐ€์šด๋ฐ๋กœ
    return i + 1;              // pivot์˜ ์ตœ์ข… ์œ„์น˜
}

์‹œ๊ฐํ™”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
์ดˆ๊ธฐ:  [3, 1, 4, 1, 5, 9, 2, 6]    pivot = 6 (๋งˆ์ง€๋ง‰)
       i = -1, j = 0

j=0: 3<6 โ†’ i=0, swap(a[0],a[0])  [3, 1, 4, 1, 5, 9, 2, 6]
j=1: 1<6 โ†’ i=1, swap(a[1],a[1])  [3, 1, 4, 1, 5, 9, 2, 6]
j=2: 4<6 โ†’ i=2, swap(a[2],a[2])  [3, 1, 4, 1, 5, 9, 2, 6]
j=3: 1<6 โ†’ i=3, swap(a[3],a[3])  [3, 1, 4, 1, 5, 9, 2, 6]
j=4: 5<6 โ†’ i=4, swap(a[4],a[4])  [3, 1, 4, 1, 5, 9, 2, 6]
j=5: 9<6 โ†’ ์•„๋‹ˆ์˜ค (i ๊ทธ๋Œ€๋กœ)
j=6: 2<6 โ†’ i=5, swap(a[5],a[6])  [3, 1, 4, 1, 5, 2, 9, 6]

๋งˆ์ง€๋ง‰ swap(a[6],a[7]):            [3, 1, 4, 1, 5, 2, 6, 9]
                                                  โ†‘ pivot ์ž๋ฆฌ ํ™•์ •

์ขŒ์ธก [3, 1, 4, 1, 5, 2] (๋ชจ๋‘ < 6)  |  ์šฐ์ธก [9] (> 6)

โ†’ partition ํ•œ ๋ฒˆ์ด๋ฉด pivot์˜ ์ตœ์ข… ์œ„์น˜๊ฐ€ ํ™•์ •๋˜๊ณ , ์ขŒยท์šฐ๋Š” ๋…๋ฆฝ์ ์œผ๋กœ ์ •๋ ฌํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค (์žฌ๊ท€).

Hoare partition (์‹ค์ œ introsort๊ฐ€ ์“ฐ๋Š” ๋ฒ„์ „)

1
2
3
4
5
6
7
์–‘ ๋์—์„œ ์‹œ์ž‘ํ•ด ์•ˆ์ชฝ์œผ๋กœ ์ขํ˜€์˜ค๋ฉฐ swap.
์ขŒ์ธก ์ธ๋ฑ์Šค โ†’: pivot๋ณด๋‹ค ํฐ ๊ฒƒ ๋งŒ๋‚  ๋•Œ๊นŒ์ง€
์šฐ์ธก ์ธ๋ฑ์Šค โ†: pivot๋ณด๋‹ค ์ž‘์€ ๊ฒƒ ๋งŒ๋‚  ๋•Œ๊นŒ์ง€
๋‘˜์ด ๋งŒ๋‚˜๋ฉด ์ข…๋ฃŒ, ๋‘ ๊ตฌ๊ฐ„์„ ์žฌ๊ท€.

์žฅ์ : swap ํšŸ์ˆ˜๊ฐ€ Lomuto์˜ ์•ฝ 1/3
๋‹จ์ : pivot์ด ์ •ํ™•ํ•œ ์ž๋ฆฌ์— ์•ˆ ๊ฐ€๊ณ  partition ๊ฒฝ๊ณ„๋งŒ ๋ฐ˜ํ™˜ (๊ทธ๋ž˜๋„ ์ •๋ ฌ์€ ๋จ)

pivot ์„ ํƒ โ€” median-of-three

1
2
3
4
5
6
๋‚˜์œ pivot โ†’ quicksort๊ฐ€ O(nยฒ)๋กœ ๋–จ์–ด์ง
            (์˜ˆ: ์ด๋ฏธ ์ •๋ ฌ๋œ ์ž…๋ ฅ + '์ฒซ ์›์†Œ'๋ฅผ pivot์œผ๋กœ ์žก๋Š” ๋ฐฉ์‹)

introsort์˜ ๋ฐฉ์–ด ์žฅ์น˜:
  โ‘  median-of-three: ์ฒซยท์ค‘๊ฐ„ยท๋ ์„ธ ์›์†Œ ์ค‘ ์ค‘๊ฐ„๊ฐ’์„ pivot์œผ๋กœ
  โ‘ก ์žฌ๊ท€ ๊นŠ์ด 2*logโ‚‚(n) ์ดˆ๊ณผ ์‹œ heapsort ํด๋ฐฑ โ†’ ์ตœ์•…๋„ O(n log n) ๋ณด์žฅ

์™œ partition์€ RandomAccess๊ฐ€ ํ•„์ˆ˜์ธ๊ฐ€ โ€” ํ•œ ๋ฒˆ ๋” ์ •๋ฆฌ

1
2
3
4
5
6
7
์ค‘๊ฐ„๊ฐ’ ์„ ํƒ:  mid = first + (last - first) / 2     โ† it + n
์–‘ ๋ swap:   swap(*lo, *hi--), ++lo               โ† ์–‘๋ฐฉํ–ฅ + ์ธ๋ฑ์Šค
์žฌ๊ท€ ํ˜ธ์ถœ:    partition(arr, lo, mid-1)             โ† ๋ถ€๋ถ„ ๊ตฌ๊ฐ„ ์ธ๋ฑ์‹ฑ

์ด ์—ฐ์‚ฐ๋“ค์ด ๋ชจ๋‘ O(1)์ด์–ด์•ผ partition ํ•œ ๋ฒˆ์ด O(n)์œผ๋กœ ๋๋‚จ.
list iterator๋Š” it+n์ด O(n) โ†’ partition ํ•œ ๋ฒˆ์ด O(nยฒ) โ†’ quicksort ์ž์ฒด๊ฐ€ O(nยณ)
โ†’ ๊ทธ๋ž˜์„œ list์—” quicksort/introsort ์ž์ฒด๊ฐ€ ๋ถ€์ ํ•ฉ.

์™œ ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)๊ฐ€ list์— ์ตœ์ ์ธ๊ฐ€ โ€” ์ง๊ด€

๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)์˜ ๋‘ ์ •๋ ฌ ๋ฆฌ์ŠคํŠธ ๋ณ‘ํ•ฉ(merge) ๋‹จ๊ณ„๋Š”:

1
2
3
4
5
6
7
A: 1 โ†’ 3 โ†’ 5
B: 2 โ†’ 4 โ†’ 6
       โ†“ merge
๊ฒฐ๊ณผ: 1 โ†’ 2 โ†’ 3 โ†’ 4 โ†’ 5 โ†’ 6

์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฉด โ†’ ๋…ธ๋“œ์˜ next ํฌ์ธํ„ฐ๋งŒ ๊ณจ๋ผ์„œ ์—ฐ๊ฒฐ (๋ฐ์ดํ„ฐ ์ด๋™ ์—†์Œ)
๋ฐฐ์—ด์ด๋ฉด      โ†’ ์ƒˆ ๋ฐฐ์—ด์— ๋ณต์‚ฌํ•ด์•ผ ํ•จ (์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ O(n))

โ†’ merge๊ฐ€ list์—์„œ๋Š” in-place๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ๊ตฌ์กฐ ์ž์ฒด๊ฐ€ ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)์— ์ตœ์ ํ™”๋ผ ์žˆ๋‹ค๊ณ  ๋ด๋„ ๋ฉ๋‹ˆ๋‹ค.


4. ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ฐจ์ด โ€” introsort vs ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)

std::sort โ€” introsort (1997, Musser)

์„ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋‹จ๊ณ„๋ณ„๋กœ ํด๋ฐฑํ•˜๋Š” ํ•˜์ด๋ธŒ๋ฆฌ๋“œ. C++ ํ‘œ์ค€์ด ๋ช…์‹œ์ ์œผ๋กœ introsort๋ฅผ ์š”๊ตฌํ•˜์ง„ ์•Š์ง€๋งŒ, ๋Œ€๋ถ€๋ถ„์˜ ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(libstdc++, libc++, MSVC)๊ฐ€ ์ฑ„ํƒ.

1
2
3
4
5
6
7
์ž…๋ ฅ โ†’ ์žฌ๊ท€ ๊นŠ์ด ์ถ”์ 
  โ”œโ”€โ”€ ๊นŠ์ด < 2*logโ‚‚(n) AND ๊ตฌ๊ฐ„ ํฌ๊ธฐ > 16
  โ”‚     โ””โ”€โ”€ quicksort (median-of-three pivot)
  โ”œโ”€โ”€ ๊นŠ์ด โ‰ฅ 2*logโ‚‚(n)  โ† worst case ์ง„์ž…
  โ”‚     โ””โ”€โ”€ heapsort ๋กœ ํด๋ฐฑ (๋ณด์žฅ๋œ O(n log n))
  โ””โ”€โ”€ ์ž‘์€ ๊ตฌ๊ฐ„ (โ‰ค 16)
        โ””โ”€โ”€ insertion sort ๋กœ ๋งˆ๋ฌด๋ฆฌ (์บ์‹œ ์นœํ™”์ )
  • ์‹œ๊ฐ„๋ณต์žก๋„: ํ‰๊ท  O(n log n), ์ตœ์•…๋„ O(n log n) (heapsort ํด๋ฐฑ ๋•๋ถ„)
  • ๊ณต๊ฐ„๋ณต์žก๋„: O(log n) (์žฌ๊ท€ ์Šคํƒ)
  • stable: No โ€” quicksort partition์ด ๋™๋“ฑ ์›์†Œ ์ˆœ์„œ๋ฅผ ๊นธ
  • ์š”๊ตฌ: RandomAccessIterator

insertion sort ์ž์„ธํžˆ โ€” introsort๊ฐ€ ์ž‘์€ ๊ตฌ๊ฐ„์—์„œ ๋งˆ๋ฌด๋ฆฌ๋กœ ์“ฐ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜

์นด๋“œ ๊ฒŒ์ž„์—์„œ ์†์— ๋“  ์นด๋“œ๋ฅผ ์ •๋ ฌํ•˜๋Š” ๋ฐฉ์‹๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํ•œ ์žฅ์”ฉ ๋ฝ‘์•„ ์ด๋ฏธ ์ •๋ ฌ๋œ ๋ถ€๋ถ„์˜ ์•Œ๋งž์€ ์ž๋ฆฌ์— ๋ผ์›Œ ๋„ฃ์Šต๋‹ˆ๋‹ค.

๋™์ž‘ ์‹œ๊ฐํ™”

1
2
3
4
5
6
7
8
9
10
11
์ž…๋ ฅ: [5, 2, 4, 6, 1, 3]
       โ””โ”€ | ์™ผ์ชฝ์ด ์ •๋ ฌ๋œ prefix, ์˜ค๋ฅธ์ชฝ์ด ๋ฏธ์ •๋ ฌ

step 1: [5 | 2, 4, 6, 1, 3]      โ† ์ฒซ ์›์†Œ๋Š” ์ž์ฒด๋กœ ์ •๋ ฌ
step 2: [2, 5 | 4, 6, 1, 3]      โ† 2๋ฅผ 5 ์•ž์œผ๋กœ ์ด๋™
step 3: [2, 4, 5 | 6, 1, 3]      โ† 4๋ฅผ 5 ์•ž์œผ๋กœ ์ด๋™
step 4: [2, 4, 5, 6 | 1, 3]      โ† 6์€ ๊ทธ๋Œ€๋กœ
step 5: [1, 2, 4, 5, 6 | 3]      โ† 1์„ ๋งจ ์•ž๊นŒ์ง€ ์ด๋™
step 6: [1, 2, 3, 4, 5, 6]       โ† 3์„ 4 ์•ž์œผ๋กœ ์ด๋™

ํ•ต์‹ฌ: | ์™ผ์ชฝ prefix๋Š” ํ•ญ์ƒ ์ •๋ ฌ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ, ์˜ค๋ฅธ์ชฝ ์›์†Œ๋ฅผ ํ•˜๋‚˜์”ฉ ๋ผ์›€.

์˜์‚ฌ์ฝ”๋“œ

1
2
3
4
5
6
7
8
9
for (int i = 1; i < n; ++i) {
    auto key = arr[i];
    int j = i - 1;
    while (j >= 0 && arr[j] > key) {   // ํฐ ์›์†Œ๋“ค์„ ํ•œ ์นธ์”ฉ ์šฐ์ธก์œผ๋กœ ๋ฐ€๊ธฐ
        arr[j + 1] = arr[j];
        --j;
    }
    arr[j + 1] = key;                   // ๋นˆ ์ž๋ฆฌ์— key ์‚ฝ์ž…
}

๋ณต์žก๋„์™€ ํŠน์„ฑ

ํ•ญ๋ชฉ๊ฐ’๋ฉ”๋ชจ
ํ‰๊ท  ์‹œ๊ฐ„O(nยฒ)๋ผ์›Œ ๋„ฃ์„ ๋•Œ๋งˆ๋‹ค ํ‰๊ท  n/2๋ฒˆ ๋น„๊ตยท์ด๋™
์ตœ์•… ์‹œ๊ฐ„O(nยฒ)์—ญ์ˆœ ์ž…๋ ฅ
์ตœ์„  ์‹œ๊ฐ„O(n)์ด๋ฏธ ์ •๋ ฌ๋œ ์ž…๋ ฅ โ€” ๋น„๊ต๋งŒ n-1๋ฒˆ
๊ณต๊ฐ„O(1)in-place
stableYes> ๋น„๊ต๋งŒ ์“ฐ๋ฉด ๋™๋“ฑ ์›์†Œ๊ฐ€ ์ž๊ธฐ ์ž๋ฆฌ์— ๋ฉˆ์ถค

introsort๊ฐ€ ์ž‘์€ ๊ตฌ๊ฐ„์—์„œ insertion sort๋ฅผ ์“ฐ๋Š” ์ด์œ 

1
2
3
4
5
6
7
๊ตฌ๊ฐ„ ํฌ๊ธฐ โ‰ค 16 ์ด๋ฉด quicksort ์žฌ๊ท€ ๋Œ€์‹  insertion sort ํ˜ธ์ถœ

์ด์œ :
  โ‘  ์žฌ๊ท€ ์˜ค๋ฒ„ํ—ค๋“œ ์ œ๊ฑฐ โ€” ์ž‘์€ ๊ตฌ๊ฐ„์—” ํ•จ์ˆ˜ ํ˜ธ์ถœ ๋น„์šฉ์ด ๋” ํผ
  โ‘ก ์บ์‹œ ์นœํ™” โ€” 16๊ฐœ ์ •๋„๋ฉด L1 ์บ์‹œ์— ๊ทธ๋Œ€๋กœ ๋“ค์–ด๊ฐ
  โ‘ข ๊ฑฐ์˜ ์ •๋ ฌ๋œ ๋ฐ์ดํ„ฐ์— ๊ฐ•ํ•จ โ€” quicksort partition์„ ๊ฑฐ์นœ ์ž‘์€ ๊ตฌ๊ฐ„์€
     ์ด๋ฏธ ๋ถ€๋ถ„์ ์œผ๋กœ ์ •๋ ฌ๋์„ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Œ โ†’ insertion sort์˜ best case์— ๊ทผ์ ‘

โ†’ insertion sort๋Š” ์ž‘์€ ๋ฐ์ดํ„ฐ + ๊ฑฐ์˜ ์ •๋ ฌ๋œ ๋ฐ์ดํ„ฐ์—์„œ quicksort๋ณด๋‹ค ๋น ๋ฆ…๋‹ˆ๋‹ค. ์ด ๋‘ ์กฐ๊ฑด์ด introsort ๋ง‰๋ฐ”์ง€์— ํ•ญ์ƒ ๋งŒ์กฑ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋งˆ๋ฌด๋ฆฌ์šฉ์œผ๋กœ ์“ฐ์ž…๋‹ˆ๋‹ค.

std::list::sort โ€” ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)

์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ ์ „์šฉ in-place ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort). ํ‘œ์ค€์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ช…์‹œํ•˜์ง€ ์•Š์ง€๋งŒ, ๋ฐ˜๋“œ์‹œ stable + O(n log n) ์„ ์š”๊ตฌ. ์‚ฌ์‹ค์ƒ ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)๊ฐ€ ์ •๋‹ต.

1
2
3
4
5
list::sort(๋ฒ”์œ„)
  โ‘  ๋ฆฌ์ŠคํŠธ๋ฅผ ์ ˆ๋ฐ˜์œผ๋กœ ๋ถ„ํ•  (slow/fast ํฌ์ธํ„ฐ ๋˜๋Š” ๋…ธ๋“œ ์นด์šดํŠธ)
  โ‘ก ๊ฐ ์ ˆ๋ฐ˜์„ ์žฌ๊ท€ ์ •๋ ฌ
  โ‘ข merge โ€” ๋‘ ์ •๋ ฌ ๋ฆฌ์ŠคํŠธ์˜ head๋ฅผ ๋น„๊ตํ•˜๋ฉฐ ์ž‘์€ ์ชฝ ๋…ธ๋“œ๋ฅผ ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ ๋์— ์—ฐ๊ฒฐ
            (ํฌ์ธํ„ฐ ์žฌ๋ฐฐ์น˜๋งŒ, ๋ฐ์ดํ„ฐ ์ด๋™ X)
  • ์‹œ๊ฐ„๋ณต์žก๋„: O(n log n) ๋ณด์žฅ (worstยทaverageยทbest ๋™์ผ)
  • ๊ณต๊ฐ„๋ณต์žก๋„: O(1) โ€” in-place (๋…ธ๋“œ ์žฌ์—ฐ๊ฒฐ๋งŒ)
  • stable: Yes โ€” merge ๋‹จ๊ณ„์—์„œ ๋™๋“ฑ ์›์†Œ๋ฉด ์™ผ์ชฝ(์•ž์ชฝ)์„ ๋จผ์ € ์„ ํƒ
  • ์š”๊ตฌ: BidirectionalIterator (์‚ฌ์‹ค์€ ForwardIterator๋กœ๋„ ์ถฉ๋ถ„)

๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort) ์ž์„ธํžˆ โ€” ๋ถ„ํ•  ์ •๋ณต์˜ ๊ต๊ณผ์„œ ์‚ฌ๋ก€

๋ณ‘ํ•ฉ ์ •๋ ฌ์€ โ€œ๋‚˜๋ˆ ์„œ ๊ฐ๊ฐ ์ •๋ ฌํ•œ ๋’ค ํ•ฉ์นœ๋‹คโ€œ๋Š” ๋ถ„ํ•  ์ •๋ณต(divide and conquer) ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. list::sort์˜ ๊ธฐ๋ณธ ๊ตฌํ˜„์ด๋ฉฐ, std::stable_sort๋„ ์‚ฌ์‹ค์ƒ ๊ฐ™์€ ๊ณ„์—ด์ž…๋‹ˆ๋‹ค.

3๋‹จ๊ณ„ โ€” ๋ถ„ํ• (Divide) / ์ •๋ณต(Conquer) / ๊ฒฐํ•ฉ(Merge)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
์ž…๋ ฅ: [3, 1, 4, 1, 5, 9, 2, 6]

[1] ๋ถ„ํ•  (Divide)
    ์ ˆ๋ฐ˜์œผ๋กœ ์ชผ๊ฐฌ:  [3, 1, 4, 1] | [5, 9, 2, 6]
    ๋” ์ชผ๊ฐฌ:       [3, 1] [4, 1] | [5, 9] [2, 6]
    1๊ฐœ๊นŒ์ง€:       [3][1] [4][1] | [5][9] [2][6]

[2] ์ •๋ณต (Conquer)
    1๊ฐœ์งœ๋ฆฌ๋Š” ์ž์ฒด๋กœ ์ •๋ ฌ๋œ ์ƒํƒœ (base case)

[3] ๊ฒฐํ•ฉ (Merge โ€” ํ•ต์‹ฌ)
    [1, 3] [1, 4]  | [5, 9] [2, 6]    โ† ๋‘ ์ •๋ ฌ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋น„๊ตํ•˜๋ฉฐ ๋จธ์ง€
    [1, 1, 3, 4]   | [2, 5, 6, 9]
    [1, 1, 2, 3, 4, 5, 6, 9]            โ† ์ตœ์ข…

merge ๋‹จ๊ณ„๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋‚˜ (stable์˜ ๋น„๋ฐ€)

1
2
3
4
5
6
7
8
9
10
A: [1, 3]      a ํฌ์ธํ„ฐ: โ†’ 1
B: [1, 4]      b ํฌ์ธํ„ฐ: โ†’ 1
๊ฒฐ๊ณผ: []

step 1: *a=1, *b=1 โ†’ ๋™๋“ฑ โ†’ '<'๋งŒ ๋น„๊ตํ•˜๋ฏ€๋กœ b๊ฐ€ a๋ณด๋‹ค ์ž‘์ง€ ์•Š์Œ โ†’ a๋ฅผ ๋จผ์ € ์„ ํƒ
                                                                    โ˜… stability ํ•ต์‹ฌ
        ๊ฒฐ๊ณผ: [1(A)], aโ†’3
step 2: *a=3, *b=1 โ†’ b ์ž‘์Œ โ†’ b ์„ ํƒ, ๊ฒฐ๊ณผ: [1(A), 1(B)], bโ†’4
step 3: *a=3, *b=4 โ†’ a ์ž‘์Œ โ†’ a ์„ ํƒ, ๊ฒฐ๊ณผ: [1(A), 1(B), 3], a ๋
step 4: B์˜ ๋‚จ์€ ๋ถ€๋ถ„ [4] ์ด์–ด๋ถ™์ž„ โ†’ [1(A), 1(B), 3, 4]

โ†’ ์ฝ”๋“œ ํ•œ ์ค„(if (*b < *a)๋กœ b๋ฅผ ๋จผ์ € ์„ ํƒ)์—์„œ <๋งŒ ์“ฐ๊ณ  <=๋ฅผ ์“ฐ์ง€ ์•Š์œผ๋ฉด ๋™๋“ฑ ์›์†Œ์ผ ๋•Œ a(์™ผ์ชฝ ์‹œํ€€์Šค)๊ฐ€ ํ•ญ์ƒ ๋จผ์ € ๋‚˜์˜ค๊ฒŒ ๋˜์–ด ์•ˆ์ •์„ฑ์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ณด์กด๋ฉ๋‹ˆ๋‹ค.

์‹œ๊ฐ„๋ณต์žก๋„ ๋ถ„์„ (๋งˆ์Šคํ„ฐ ์ •๋ฆฌ)

1
2
3
4
5
6
7
8
T(n) = 2 * T(n/2) + O(n)
       โ””โ”€ ๋‘ ์ ˆ๋ฐ˜ โ”€โ”˜   โ”” merge ํ•œ ๋ฒˆ โ”˜

๊นŠ์ด = logโ‚‚ n  (์ ˆ๋ฐ˜์”ฉ ์ชผ๊ฐœ๋‹ˆ๊นŒ)
๊ฐ ๊นŠ์ด์˜ ์ž‘์—…๋Ÿ‰ = O(n)  (๊ทธ ๊นŠ์ด์˜ ๋ชจ๋“  ๋จธ์ง€๋ฅผ ํ•ฉ์น˜๋ฉด n๊ฐœ ๋น„๊ต)
โ†’ ์ด ๋น„์šฉ = O(n log n)

worst = average = best = O(n log n)  โ† quicksort์™€ ๋‹ฌ๋ฆฌ ์ž…๋ ฅ ๋ชจ์–‘์— ๋ฌด๊ด€

๋‘ ๊ฐ€์ง€ ๊ตฌํ˜„ ๋ฐฉ์‹ โ€” top-down vs bottom-up

๋ฐฉ์‹๋™์ž‘ํŠน์ง•
Top-down (์žฌ๊ท€)ํฐ ๋ฒ”์œ„๋ฅผ ์ ˆ๋ฐ˜์œผ๋กœ ์ชผ๊ฐœ๋ฉฐ ์žฌ๊ท€ ํ˜ธ์ถœ์ง๊ด€์ . O(log n) ์Šคํƒ ์‚ฌ์šฉ
Bottom-up (๋ฐ˜๋ณต)1๊ฐœ์”ฉ ์ง์ง€์–ด ๋จธ์ง€ โ†’ 2๊ฐœ์”ฉ โ†’ 4๊ฐœ์”ฉ โ€ฆ์Šคํƒ ์—†์ด ๋ฐ˜๋ณต๋ฌธ. ์บ์‹œ ์นœํ™”์ 

โ†’ std::list::sort๋Š” ๋ณดํ†ต bottom-up ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค (libstdc++ ๋“ฑ). ์žฌ๊ท€ ์Šคํƒ์„ ์•ˆ ์จ์„œ O(1) ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋ณด์žฅํ•˜๊ธฐ ์ข‹๊ณ , ๋จธ์ง€ ๋‹จ์œ„๋ฅผ 1, 2, 4, 8, 16 โ€ฆ ์œผ๋กœ ํ‚ค์›Œ๊ฐ€๋ฉฐ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์™œ list์— ์ž์—ฐ์Šค๋Ÿฌ์šด๊ฐ€ โ€” ๊ฒฐ์ •ํƒ€

1
2
3
4
5
๋ฐฐ์—ด ๋จธ์ง€: ๋‘ ์ •๋ ฌ๋œ ๋ถ€๋ถ„์„ ๋จธ์ง€ํ•˜๋ ค๋ฉด ๊ฒฐ๊ณผ ๋‹ด์„ ์ƒˆ ๋ฐฐ์—ด ํ•„์š” (O(n) ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ)
           in-place๋กœ๋„ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๋งค์šฐ ๋ณต์žก (Knuth, Pratt ๋“ฑ)

list ๋จธ์ง€: ๋‘ ์ •๋ ฌ๋œ ๋ฆฌ์ŠคํŠธ์˜ ๋…ธ๋“œ next ํฌ์ธํ„ฐ๋งŒ ๋‹ค์‹œ ์ž‡๊ธฐ
           โ†’ ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ O(1), ๋ฐ์ดํ„ฐ ์ด๋™ 0, ์•ˆ์ •์„ฑ ์ž์—ฐ์Šค๋Ÿฌ์›€

โ†’ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ์ž๋ฃŒ๊ตฌ์กฐ ์ž์ฒด๊ฐ€ ๋ณ‘ํ•ฉ ์ •๋ ฌ์˜ ๋จธ์ง€ ๋‹จ๊ณ„์™€ ์™„๋ฒฝํžˆ ๋งž๋ฌผ๋ฆฝ๋‹ˆ๋‹ค. ์ด๊ฒŒ std::list๊ฐ€ sort ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋กœ ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)์„ ์ฑ„ํƒํ•œ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค.

๋‹จ์  โ€” ์บ์‹œ ์นœํ™”์„ฑ

1
2
3
4
5
6
๋ฐฐ์—ด + ๋ณ‘ํ•ฉ ์ •๋ ฌ: ๋ฐ์ดํ„ฐ๊ฐ€ ์—ฐ์†๋œ ๋ฉ”๋ชจ๋ฆฌ โ†’ ์บ์‹œ ํžˆํŠธ์œจ ๋†’์Œ
list + ๋ณ‘ํ•ฉ ์ •๋ ฌ: ๋…ธ๋“œ๊ฐ€ ํž™ ๊ณณ๊ณณ์— ๋ถ„์‚ฐ โ†’ ์บ์‹œ ๋ฏธ์Šค ๋นˆ๋ฐœ

๊ทธ๋ž˜์„œ vector + std::sort(introsort)๊ฐ€ list + list::sort๋ณด๋‹ค ๋ณดํ†ต 5~10๋ฐฐ ๋น ๋ฆ„.
list::sort๋Š” ์–ด๋””๊นŒ์ง€๋‚˜ "list๋ฅผ ์จ์•ผ๋งŒ ํ•˜๋Š” ์ƒํ™ฉ์—์„œ์˜ ์ตœ์„ "์ด์ง€,
list๊ฐ€ vector๋ณด๋‹ค ์ •๋ ฌ์—์„œ ๋น ๋ฅด๋‹ค๋Š” ์˜๋ฏธ๊ฐ€ ์ ˆ๋Œ€ ์•„๋‹˜.

โ†’ 13๋ฒˆ์—์„œ ๋ณธ โ€œlist๊ฐ€ ์ •๋‹นํ™”๋˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜คโ€(ํฐ ๊ฐ์ฒด + ์žฆ์€ splice + iterator ์•ˆ์ •์„ฑ)์— ๋“ค์–ด๋งž์„ ๋•Œ๋งŒ list::sort์˜ ์ด์ ์ด ๋ฐœํ˜„๋ฉ๋‹ˆ๋‹ค.

๋น„๊ต ํ‘œ

ํ•ญ๋ชฉstd::sort (introsort)std::list::sort (๋ณ‘ํ•ฉ ์ •๋ ฌ / merge sort)
์•Œ๊ณ ๋ฆฌ์ฆ˜quicksort + heapsort + insertion sort๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)
์‹œ๊ฐ„๋ณต์žก๋„ (ํ‰๊ท )O(n log n)O(n log n)
์‹œ๊ฐ„๋ณต์žก๋„ (์ตœ์•…)O(n log n) (heapsort ํด๋ฐฑ)O(n log n)
๊ณต๊ฐ„๋ณต์žก๋„O(log n) ์žฌ๊ท€O(1) in-place
์•ˆ์ •์„ฑUnstableStable
๋ฐ์ดํ„ฐ ์ด๋™swap ๋‹ค์ˆ˜ (๊ฐ์ฒด ๋ณต์‚ฌยท์ด๋™)0 (๋…ธ๋“œ ํฌ์ธํ„ฐ ์žฌ์—ฐ๊ฒฐ)
์บ์‹œ ์นœํ™”์„ฑ๋งค์šฐ ๋†’์Œ (์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ)๋‚ฎ์Œ (๋…ธ๋“œ ๋ถ„์‚ฐ)
๋น„๊ต ํ•จ์ˆ˜strict weak orderingstrict weak ordering
iterator ์š”๊ตฌRandomAccessBidirectional

โ†’ ์ด๋ก  ๋ณต์žก๋„๋Š” ๊ฐ™์ง€๋งŒ, ๋ฐ์ดํ„ฐ ์ด๋™ ๋น„์šฉ๊ณผ ์บ์‹œ ์นœํ™”์„ฑ์—์„œ ๋‘˜์€ ์ •๋ฐ˜๋Œ€ ํŠน์„ฑ์„ ๋ณด์ž…๋‹ˆ๋‹ค.


5. ๋…ธ๋“œ ์žฌ์—ฐ๊ฒฐ โ€” ๋ฐ์ดํ„ฐ ์ด๋™ ๋น„์šฉ 0์˜ ์˜๋ฏธ

ํ•ต์‹ฌ ํ•œ ๋ฌธ์žฅ

std::list::sort๋Š” ๋…ธ๋“œ ์ž์ฒด๋ฅผ ์˜ฎ๊ธฐ์ง€ ์•Š๊ณ  prev/next ํฌ์ธํ„ฐ๋งŒ ์žฌ์—ฐ๊ฒฐํ•ด์„œ ์ •๋ ฌํ•ฉ๋‹ˆ๋‹ค. ํฐ ๊ฐ์ฒด๋ฅผ ๋‹ด๊ณ  ์žˆ์„์ˆ˜๋ก ์ด ์ฐจ์ด๊ฐ€ ์‹ค์ธก ์„ฑ๋Šฅ์„ ๊ฐ€๋ฆ…๋‹ˆ๋‹ค.

์‹œ๊ฐํ™” โ€” merge ํ•œ ๋‹จ๊ณ„

1
2
3
4
5
6
7
8
9
10
11
12
13
์ดˆ๊ธฐ (๋‘ ์ •๋ ฌ ๋ฆฌ์ŠคํŠธ)
A: [1] โ†โ†’ [3] โ†โ†’ [5]
B: [2] โ†โ†’ [4] โ†โ†’ [6]

merge ์ง„ํ–‰ (ํฌ์ธํ„ฐ๋งŒ ์žฌ๋ฐฐ์น˜)
            โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
[1] โ”€โ”€nextโ”€โ”€โ”˜                โ–ผ
            โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€[2]โ”€โ”€nextโ”€โ†’ ...
[3] โ”€โ”€nextโ”€โ”€โ”˜
                            (๊ฐ์ฒด 1, 3, 5, 2, 4, 6 ์˜ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๋Š” ๊ทธ๋Œ€๋กœ!)

๊ฒฐ๊ณผ (๋‹จ์ผ ์ •๋ ฌ ๋ฆฌ์ŠคํŠธ)
[1] โ†โ†’ [2] โ†โ†’ [3] โ†โ†’ [4] โ†โ†’ [5] โ†โ†’ [6]

โ†’ ๋…ธ๋“œ ์ž์ฒด๋Š” ์ฒ˜์Œ ํ• ๋‹น๋œ ์ž๋ฆฌ์— ๊ทธ๋Œ€๋กœ, ๋‹จ์ง€ next/prev๊ฐ€ ๋‹ค๋ฅธ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ๋ฐ”๋€ ๊ฒƒ๋ฟ์ž…๋‹ˆ๋‹ค. ๊ฐ์ฒด ๋ณต์‚ฌ ์ƒ์„ฑ์ž๋‚˜ ์ด๋™ ์ƒ์„ฑ์ž๋Š” ํ•œ ๋ฒˆ๋„ ํ˜ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

vector + std::sort ์™€์˜ ๋น„๊ต

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct LargeObject {
    char data[1024];
    bool operator<(const LargeObject& o) const { /* ... */ }
};

// vector ์ผ€์ด์Šค
std::vector<LargeObject> v(10000);
std::sort(v.begin(), v.end());
// โ†’ partitionยทmerge ๋‹จ๊ณ„๋งˆ๋‹ค 1024๋ฐ”์ดํŠธ ๊ฐ์ฒด๋ฅผ swap (memcpy ๋‹ค์ˆ˜)
// โ†’ ์‹ค์ธก: ๋ฐ์ดํ„ฐ ์ด๋™ ๋น„์šฉ์ด ๋น„๊ต ๋น„์šฉ๋ณด๋‹ค ํ›จ์”ฌ ํผ

// list ์ผ€์ด์Šค
std::list<LargeObject> lst(10000);
lst.sort();
// โ†’ ๋…ธ๋“œ ํฌ์ธํ„ฐ(8๋ฐ”์ดํŠธ ร— 2)๋งŒ ์žฌ๋ฐฐ์น˜
// โ†’ ๊ฐ์ฒด ์ž์ฒด์˜ 1024๋ฐ”์ดํŠธ๋Š” ํ•œ ๋ฒˆ๋„ ์•ˆ ์˜ฎ๊น€

โ†’ ์ด๊ฒŒ list๊ฐ€ ์ •๋‹นํ™”๋˜๋Š” ๊ฑฐ์˜ ์œ ์ผํ•œ ์‹ค์šฉ์  ์‹œ๋‚˜๋ฆฌ์˜ค์ž…๋‹ˆ๋‹ค (13๋ฒˆ 6์žฅ ์ฐธ๊ณ ). โ€œํฐ ๊ฐ์ฒด + ์žฆ์€ ์ •๋ ฌยทsplice + iterator ์•ˆ์ •์„ฑโ€์ด ๋™์‹œ์— ๋งŒ์กฑ๋ผ์•ผ ํ•˜์ง€๋งŒ, ๋งค์šฐ ๋“œ๋ฌผ๊ธด ํ•ฉ๋‹ˆ๋‹ค.

iterator ์•ˆ์ •์„ฑ (๋ค)

list::sort๋Š” iterator๋ฅผ ๋ฌดํšจํ™”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์žฌ๋ฐฐ์น˜ ํ›„์—๋„ ๋…ธ๋“œ ์ž์ฒด๊ฐ€ ๊ทธ๋Œ€๋กœ ์‚ด์•„์žˆ์œผ๋‹ˆ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋˜ iterator๋Š” ์—ฌ์ „ํžˆ ๊ฐ™์€ ๊ฐ’์„ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค (์œ„์น˜๋Š” ๋ฐ”๋€Œ์—ˆ์ง€๋งŒ).

1
2
3
4
5
std::list<int> lst = {3, 1, 4, 1, 5};
auto it = std::next(lst.begin());   // ๋‘ ๋ฒˆ์งธ ์›์†Œ = 1
lst.sort();
// lst = {1, 1, 3, 4, 5}
*it;   // ์—ฌ์ „ํžˆ 1 (๋…ธ๋“œ๋Š” ์‚ด์•„์žˆ์Œ)

โ†’ vector์˜€๋‹ค๋ฉด std::sort ํ›„ iterator๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฐ’์ด ์™„์ „ํžˆ ๋‹ฌ๋ผ์ง€๊ฑฐ๋‚˜ ๋ฌดํšจํ™”๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


6. stable ์—ฌ๋ถ€ / ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ๋น„๊ต

stable์ด ๋ญ”์ง€ ํ’€์–ด์„œ โ€” โ€œ๋™๋“ฑ ์›์†Œ์˜ ์ƒ๋Œ€ ์ˆœ์„œ ์œ ์ง€โ€์˜ ์ง„์งœ ์˜๋ฏธ

ํ•œ ์ค„๋กœ: ์ •๋ ฌ ํ‚ค๋Š” ๊ฐ™์€๋ฐ ๋‹ค๋ฅธ ์ •๋ณด๋Š” ๋‹ค๋ฅธ ๋‘ ์›์†Œ๊ฐ€, ์ž…๋ ฅ์—์„œ ์–ด๋А ์ชฝ์ด ์•ž์ด์—ˆ๋Š”์ง€๋ฅผ ์ •๋ ฌ ํ›„์—๋„ ๊ทธ๋Œ€๋กœ ๋ณด์กดํ•˜๋Š” ๊ฒƒ.

โ€œ๋™๋“ฑโ€์ด ํ—ท๊ฐˆ๋ฆฌ๋Š” ์ด์œ 

โ€œ๋™๋“ฑ ์›์†Œโ€๋ผ๋Š” ๋ง์ด โ€œ์™„์ „ํžˆ ๋˜‘๊ฐ™์€ ์›์†Œโ€์ฒ˜๋Ÿผ ๋“ค๋ฆฌ์ง€๋งŒ, ์ •ํ™•ํžˆ๋Š” ์ •๋ ฌ ๋น„๊ต ํ•จ์ˆ˜๊ฐ€ ๋‘˜ ์‚ฌ์ด์— ์šฐ์—ด์„ ๊ฐ€๋ฆฌ์ง€ ๋ชปํ•˜๋Š” ์›์†Œ์ž…๋‹ˆ๋‹ค. ์ •๋ ฌ ํ‚ค๋งŒ ๊ฐ™๊ณ  ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ(์ด๋ฆ„ยท๋‚ ์งœ ๋“ฑ)๋Š” ์–ผ๋งˆ๋“ ์ง€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1
2
3
struct Employee { std::string name; int dept; };
// ๋ถ€์„œ(dept)๋กœ๋งŒ ์ •๋ ฌํ•˜๋ฉด โ€” ๋ถ€์„œ๊ฐ€ ๊ฐ™์€ ๋‘ ์‚ฌ์›์€ cmp ์ž…์žฅ์—์„  "๋™๋“ฑ"
// (์ด๋ฆ„์ด ๋‹ฌ๋ผ๋„ cmp๋Š” ์‹ ๊ฒฝ X)

์‚ฌ๋ก€๋กœ ๋ณด๋Š” stable vs unstable

1
2
3
4
5
6
7
8
9
10
11
์ž…๋ ฅ: [Alice/ํŒ€1, Bob/ํŒ€2, Charlie/ํŒ€1, Dave/ํŒ€2, Eve/ํŒ€1]
       (ํŒ€ ๋ฒˆํ˜ธ๋กœ๋งŒ ์ •๋ ฌ)

stable ๊ฒฐ๊ณผ (๋ณด์žฅ):
[Alice/ํŒ€1, Charlie/ํŒ€1, Eve/ํŒ€1, Bob/ํŒ€2, Dave/ํŒ€2]
  โ†’ ํŒ€1 ์•ˆ: Alice โ†’ Charlie โ†’ Eve  (์ž…๋ ฅ ์ˆœ์„œ ๊ทธ๋Œ€๋กœ)
  โ†’ ํŒ€2 ์•ˆ: Bob โ†’ Dave             (์ž…๋ ฅ ์ˆœ์„œ ๊ทธ๋Œ€๋กœ)

unstable ๊ฒฐ๊ณผ (์˜ˆ์‹œ 1๊ฐ€์ง€):
[Eve/ํŒ€1, Alice/ํŒ€1, Charlie/ํŒ€1, Dave/ํŒ€2, Bob/ํŒ€2]
  โ†’ ํŒ€1 ์•ˆ ์ˆœ์„œ๊ฐ€ ๋’ค์„ž์ž„ (๋ณด์žฅ์ด ์—†์„ ๋ฟ, ์šฐ์—ฐํžˆ ์œ ์ง€๋  ์ˆ˜๋„ ์žˆ์Œ)

โ†’ unstable์ด๋ผ๊ณ  ํ•ด์„œ ํ•ญ์ƒ ์ˆœ์„œ๊ฐ€ ๊นจ์ง€๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ, ๋ณด์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค. ๊ฐ™์€ ์ž…๋ ฅ + ๊ฐ™์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋ฉด ๊ฒฐ๊ณผ๊ฐ€ ๊ฐ™์„ ์ˆ˜ ์žˆ์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” ์˜์กดํ•˜๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

์™œ ์‹ค๋ฌด์—์„œ ์ค‘์š”ํ•œ๊ฐ€ โ€” ๋‹ค๋‹จ๊ณ„ ์ •๋ ฌ

1
2
3
4
5
6
7
8
์š”๊ตฌ: "์‚ฌ์›์„ ๋ถ€์„œ๋ณ„๋กœ, ๊ฐ™์€ ๋ถ€์„œ ์•ˆ์—์„  ์ž…์‚ฌ์ผ ์ˆœ์„œ๋กœ ์ •๋ ฌ"

ํ•ด๊ฒฐ์ฑ… (stable_sort ํ™œ์šฉ):
  โ‘  ๋จผ์ € ์ž…์‚ฌ์ผ๋กœ ์ •๋ ฌ (sort ๋˜๋Š” stable_sort ์•„๋ฌด๊ฑฐ๋‚˜)
  โ‘ก ๊ทธ ๋‹ค์Œ ๋ถ€์„œ๋กœ stable_sort
  โ†’ โ‘ก๊ฐ€ stable์ด๋ฉด โ‘ ์—์„œ ๋งŒ๋“  ์ž…์‚ฌ์ผ ์ˆœ์„œ๊ฐ€ ๊ฐ™์€ ๋ถ€์„œ ์•ˆ์—์„œ ์œ ์ง€๋จ

๋งŒ์•ฝ โ‘ก๋ฅผ unstable sort๋กœ ํ•˜๋ฉด โ‘ ์˜ ์ •๋ ฌ์ด ๋ฌด์˜๋ฏธํ•ด์ง.

โ†’ ๋‹ค๋‹จ๊ณ„ ์ •๋ ฌยท์™ธ๋ถ€์—์„œ ๋ฏธ๋ฆฌ ๋งŒ๋“  ์ˆœ์„œ ๋ณด์กด ๊ฐ™์€ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ stable ์—ฌ๋ถ€๊ฐ€ ์ •๋‹ต์„ ๊ฐ€๋ฆ…๋‹ˆ๋‹ค.

stable์˜ ํ˜•์‹ ์ •์˜

๋™๋“ฑํ•œ ์›์†Œ(!(a < b) && !(b < a)์ธ ์›์†Œ)๋“ค์˜ ์ƒ๋Œ€์  ์ˆœ์„œ๋ฅผ ์ž…๋ ฅ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๋Š” ์ •๋ ฌ.

1
2
3
4
5
6
7
8
9
10
11
std::vector<std::pair<int, char>> v = {
    {1, 'a'}, {2, 'b'}, {1, 'c'}, {2, 'd'}, {1, 'e'}
};
auto cmp = [](const auto& x, const auto& y){ return x.first < y.first; };

std::sort(v.begin(), v.end(), cmp);
// ๊ฐ€๋Šฅ ๊ฒฐ๊ณผ 1: (1,a) (1,c) (1,e) (2,b) (2,d)   โ† ์šด ์ข‹๊ฒŒ ์œ ์ง€
// ๊ฐ€๋Šฅ ๊ฒฐ๊ณผ 2: (1,e) (1,a) (1,c) (2,d) (2,b)   โ† ์ˆœ์„œ ๊นจ์ง โ€” ๋ณด์žฅ X

std::stable_sort(v.begin(), v.end(), cmp);
// ํ•ญ์ƒ: (1,a) (1,c) (1,e) (2,b) (2,d)         โ† ๋ณด์žฅ

list::sort๋Š” ์™œ stable ๋ณด์žฅ์ธ๊ฐ€

๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)์˜ merge ๋‹จ๊ณ„์—์„œ ๋‘ ๋ถ€๋ถ„์ด ๋™๋“ฑํ•  ๋•Œ ์™ผ์ชฝ(์•ž)์„ ๋จผ์ € ์„ ํƒํ•˜๋„๋ก ๊ตฌํ˜„ํ•˜๋ฉด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ stable์ด ๋ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
// merge ์˜์‚ฌ์ฝ”๋“œ
while (a != A.end() && b != B.end()) {
    if (*b < *a) take_from(b);   // โ† b๊ฐ€ *์—„๊ฒฉํžˆ* ์ž‘์„ ๋•Œ๋งŒ b๋ฅผ ๋จผ์ €
    else         take_from(a);   // ๋™๋“ฑํ•˜๋ฉด a (์™ผ์ชฝ)๋ฅผ ๋จผ์ € โ†’ stability ์œ ์ง€
}

ํ‘œ์ค€์€ std::list::sort์— stable ๋ณด์žฅ์„ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค. std::sort๋Š” stable์„ ๋ณด์žฅํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ stable์ด ํ•„์š”ํ•˜๋ฉด std::stable_sort๋ฅผ ์จ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ๋น„๊ต

ํ•จ์ˆ˜์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๋น„๊ณ 
std::sortO(log n)์žฌ๊ท€ ์Šคํƒ
std::list::sortO(1)in-place ๋…ธ๋“œ ์žฌ์—ฐ๊ฒฐ
std::stable_sortO(n) ๋˜๋Š” O(n logยฒ n)์ถ”๊ฐ€ ๋ฒ„ํผ ํ™•๋ณด ๊ฐ€๋Šฅ ์‹œ O(n), ์‹คํŒจ ์‹œ O(n logยฒ n) ์‹œ๊ฐ„

โ†’ std::stable_sort๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋ชป ์žก์œผ๋ฉด ์‹œ๊ฐ„๋ณต์žก๋„๊ฐ€ O(n logยฒ n)๋กœ ๋–จ์–ด์ง‘๋‹ˆ๋‹ค (in-place ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)). ๋ฐ˜๋ฉด list::sort๋Š” ๋…ธ๋“œ ์žฌ์—ฐ๊ฒฐ์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ in-place๋ผ ํ•ญ์ƒ O(n log n) + O(1).

๋น„๊ต ์ •๋ฆฌ

ํ•ญ๋ชฉstd::sortstd::list::sortstd::stable_sort
stableNoYesYes
์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌO(log n)O(1)O(n) ๋˜๋Š” O(n logยฒ n) ์‹œ๊ฐ„
์‹œ๊ฐ„ (๋ณด์žฅ)O(n log n)O(n log n)O(n log n) ๋˜๋Š” O(n logยฒ n)

7. forward_list::sort โ€” ๊ฐ™์€ ์ด์œ ๋กœ ๋˜ ๋”ฐ๋กœ

ํ•ต์‹ฌ ํ•œ ๋ฌธ์žฅ

std::forward_list(๋‹จ๋ฐฉํ–ฅ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ)๋Š” ForwardIterator๋งŒ ์ง€์›ํ•ด์„œ std::sort๋Š” ๋ฌผ๋ก  BidirectionalIterator๊ฐ€ ํ•„์š”ํ•œ ์ผ๋ถ€ ์•Œ๊ณ ๋ฆฌ์ฆ˜๋„ ๋ชป ์”๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ forward_list::sort๋„ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋กœ ๋”ฐ๋กœ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹œ๊ทธ๋‹ˆ์ฒ˜

1
2
3
4
5
template <class Compare>
void forward_list<T>::sort(Compare comp);

template <>
void forward_list<T>::sort();   // ๊ธฐ๋ณธ < ๋น„๊ต

์นดํ…Œ๊ณ ๋ฆฌ ๋น„๊ต

์ปจํ…Œ์ด๋„ˆiterator๋ฉค๋ฒ„ sort์•Œ๊ณ ๋ฆฌ์ฆ˜ sort
vector, deque, arrayRandomAccess์—†์Œ (๋ถˆํ•„์š”)std::sort OK
listBidirectionallist::sort์ปดํŒŒ์ผ ์—๋Ÿฌ
forward_listForwardforward_list::sort์ปดํŒŒ์ผ ์—๋Ÿฌ

forward_list๋งŒ์˜ ์ถ”๊ฐ€ ์ œ์•ฝ

  • --it ์•ˆ ๋จ โ†’ ๋์—์„œ๋ถ€ํ„ฐ ์—ญ๋ฐฉํ–ฅ ์ˆœํšŒ ๋ถˆ๊ฐ€
  • size() ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋„ ์—†์Œ (O(1) ๋ณด์žฅ ๋ถˆ๊ฐ€๋ผ ์˜๋„์ ์œผ๋กœ ์ œ๊ฑฐ)
  • ๊ทธ๋ž˜์„œ ์ •๋ ฌ ๊ตฌํ˜„์€ ๋…ธ๋“œ ์นด์šดํŠธ๋ฅผ ์ง์ ‘ ์„ธ๊ฑฐ๋‚˜ bottom-up ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort) ์‚ฌ์šฉ

โ†’ ๋‹จ๋ฐฉํ–ฅ์ด๋ผ ๋”๋”์šฑ ์™ธ๋ถ€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์†๋Œˆ ์ˆ˜๊ฐ€ ์—†๋Š” ์ž๋ฃŒ๊ตฌ์กฐ์ด๊ณ , ๋ฉค๋ฒ„ ํ•จ์ˆ˜๊ฐ€ ๋”ฐ๋กœ ์žˆ์–ด์•ผ ํ•˜๋Š” ๋‹น์œ„์„ฑ์ด ๋” ๊ฐ•ํ•ฉ๋‹ˆ๋‹ค.

๊ฐ™์€ ํŒจํ„ด์˜ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋“ค

1
2
3
4
5
list::sort()       / forward_list::sort()       โ€” ์ •๋ ฌ
list::merge(other) / forward_list::merge(other) โ€” ์ •๋ ฌ๋œ ๋ฆฌ์ŠคํŠธ ๋ณ‘ํ•ฉ (๋…ธ๋“œ ์ด์ „)
list::splice(...)  / forward_list::splice_after(...)  โ€” ๋…ธ๋“œ ์ด์ „
list::unique()     / forward_list::unique()     โ€” ์ธ์ ‘ ์ค‘๋ณต ์ œ๊ฑฐ
list::reverse()    / forward_list::reverse()    โ€” ์—ญ์ˆœํ™”

โ†’ ๋ชจ๋‘ ๋…ธ๋“œ ํฌ์ธํ„ฐ ์žฌ์—ฐ๊ฒฐ๋กœ O(?) ๋น„์šฉ์„ ์ค„์ผ ์ˆ˜ ์žˆ๋Š” ์—ฐ์‚ฐ๋“ค. ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ๊ตฌํ˜„ํ•˜๋ฉด ๋ฐ์ดํ„ฐ ์ด๋™์ด ๋ฐœ์ƒํ•˜์ง€๋งŒ, ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋Š” ํฌ์ธํ„ฐ๋งŒ ๋งŒ์ง‘๋‹ˆ๋‹ค.


8. ๋ฉค๋ฒ„ vs ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ปจ๋ฒค์…˜ โ€” set/map::find์™€ ๊ฐ™์€ ํŒจํ„ด

ํ•ต์‹ฌ ํ•œ ๋ฌธ์žฅ

โ€œ์ž๋ฃŒ๊ตฌ์กฐ์˜ ํŠน์„ฑ์„ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ํ™œ์šฉํ•  ์ˆ˜ ์—†์„ ๋•Œ, ๋ฉค๋ฒ„ ํ•จ์ˆ˜๊ฐ€ ๋”ฐ๋กœ ์กด์žฌํ•œ๋‹คโ€ โ€” ์ด๊ฒŒ STL ์ „์ฒด์— ์ผ๊ด€๋˜๊ฒŒ ํ๋ฅด๋Š” ์„ค๊ณ„ ์›์น™์ž…๋‹ˆ๋‹ค.

๊ฐ™์€ ์ปจ๋ฒค์…˜์˜ ์‚ฌ๋ก€ ๋ชจ์Œ

์ž๋ฃŒ๊ตฌ์กฐ๋ฉค๋ฒ„ ํ•จ์ˆ˜์•Œ๊ณ ๋ฆฌ์ฆ˜ ํ•จ์ˆ˜์ด์œ 
std::set / std::mapfind() O(log n)std::find O(n)RB-Tree ๊ตฌ์กฐ ํ™œ์šฉ
std::unordered_mapfind() O(1) ํ‰๊ท std::find O(n)ํ•ด์‹œ ๋ฒ„ํ‚ท ์ ํ”„
std::listsort() O(n log n) stablestd::sort ์ปดํŒŒ์ผ ์—๋Ÿฌ๋…ธ๋“œ ์žฌ์—ฐ๊ฒฐ + iterator ์นดํ…Œ๊ณ ๋ฆฌ
std::forward_listsort() O(n log n) stablestd::sort ์ปดํŒŒ์ผ ์—๋Ÿฌ๋‹จ๋ฐฉํ–ฅ + ๋…ธ๋“œ ์žฌ์—ฐ๊ฒฐ
std::listmerge(), splice(), unique(), reverse()์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋ฐ์ดํ„ฐ ์ด๋™๋…ธ๋“œ ์žฌ์—ฐ๊ฒฐ
std::set / std::maplower_bound(), upper_bound(), equal_range()์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ฒ„์ „ ์กด์žฌํ•˜๋‚˜ ๋ฉค๋ฒ„๊ฐ€ ๋” ๋น ๋ฆ„ํŠธ๋ฆฌ ๊ตฌ์กฐ ํ™œ์šฉ
std::set / std::mapcount() O(log n)std::count O(n)ํŠธ๋ฆฌ ๊ตฌ์กฐ ํ™œ์šฉ

ํ•œ ์ค„๋กœ

1
2
๋ฉค๋ฒ„ ํ•จ์ˆ˜๊ฐ€ ์žˆ๋‹ค๋ฉด ๊ฑฐ์˜ ํ•ญ์ƒ ๊ทธ๊ฒŒ ๋” ๋น ๋ฅด๊ฑฐ๋‚˜, ๋” ์•ˆ์ „ํ•˜๊ฑฐ๋‚˜, ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์•„์˜ˆ ๋ชป ์“ฐ๋Š” ์ผ€์ด์Šค๋‹ค.
                                                          โ”€ STL ๋ฉค๋ฒ„ vs ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ปจ๋ฒค์…˜

๊ฒฐ์ • ํ๋ฆ„

1
2
3
4
5
6
7
8
9
์ด ์ปจํ…Œ์ด๋„ˆ์— sort/find/count/equal_range ๋“ฑ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๊ฐ€ ์žˆ๋‚˜?
        โ”‚
   โ”Œโ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”
   ์˜ˆ         ์•„๋‹ˆ์˜ค
   โ”‚           โ”‚
๋ฉค๋ฒ„ ํ•จ์ˆ˜      ์•Œ๊ณ ๋ฆฌ์ฆ˜ ํ•จ์ˆ˜ ์‚ฌ์šฉ
์‚ฌ์šฉ (โ˜…)     (vectorยทdequeยทarray ๊ฐ™์€ RandomAccess)
   โ”‚
"์ž๋ฃŒ๊ตฌ์กฐ ํŠน์„ฑ์„ ์‚ด๋ ค ๋” ๋น ๋ฅด๊ฑฐ๋‚˜, ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์ปดํŒŒ์ผ๋„ ์•ˆ ๋จ"

9. ๊ด€๋ จ ์ •๋ ฌ family โ€” stable_sort / partial_sort / nth_element

๋น„๊ต ํ‘œ

ํ•จ์ˆ˜์‹œ๊ฐ„๋ณต์žก๋„์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌstable์šฉ๋„
std::sortO(n log n)O(log n)No์ผ๋ฐ˜ ์ •๋ ฌ
std::stable_sortO(n log n) ๋˜๋Š” O(n logยฒ n)O(n) ์‹œ๋„Yes์•ˆ์ • ์ •๋ ฌ ํ•„์š”
std::partial_sortO(n log k)O(1)No์ƒ์œ„ k๊ฐœ๋งŒ ์ •๋ ฌ
std::nth_elementO(n) ํ‰๊ท O(1)Nok๋ฒˆ์งธ ์›์†Œ๋งŒ ์ œ์ž๋ฆฌ์—
std::sort_heapO(n log n)O(1)Noheap โ†’ ์ •๋ ฌ ๋ณ€ํ™˜
std::list::sortO(n log n)O(1)Yeslist ์ „์šฉ in-place merge
std::forward_list::sortO(n log n)O(1)Yesforward_list ์ „์šฉ

ํ•ต์‹ฌ ์ฝ”๋“œ ์˜ˆ์‹œ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};

// (1) ์ผ๋ฐ˜ ์ •๋ ฌ โ€” ๊ฐ€์žฅ ์ž์ฃผ ์”€
std::sort(v.begin(), v.end());
// {1, 1, 2, 3, 4, 5, 6, 9}

// (2) ์•ˆ์ • ์ •๋ ฌ โ€” ๋™๋“ฑ ์›์†Œ ์ˆœ์„œ ์œ ์ง€ ํ•„์š”
std::stable_sort(v.begin(), v.end());

// (3) ์ƒ์œ„ 3๊ฐœ๋งŒ ์ •๋ ฌ (์ „์ฒด ์ •๋ ฌ์€ ์•ˆ ํ•จ)
std::partial_sort(v.begin(), v.begin() + 3, v.end());
// {1, 1, 2, ...๋’ค๋Š” ์ •๋ ฌ ์•ˆ ๋จ...}

// (4) k๋ฒˆ์งธ ์›์†Œ(์ค‘์•™๊ฐ’ ๋“ฑ) ๋งŒ ์ œ์ž๋ฆฌ์—
std::nth_element(v.begin(), v.begin() + v.size()/2, v.end());
// ์ค‘์•™๊ฐ’์ด v[n/2]์— ์œ„์น˜, ์ขŒ์ธก์€ ๋” ์ž‘๊ฑฐ๋‚˜ ๊ฐ™์Œ, ์šฐ์ธก์€ ๋” ํฌ๊ฑฐ๋‚˜ ๊ฐ™์Œ โ€” ํ‰๊ท  O(n)

โ†’ ์ƒ์œ„ k๊ฐœ๋งŒ ํ•„์š”ํ•˜๋ฉด partial_sort, k๋ฒˆ์งธ ์›์†Œ๋งŒ ํ•„์š”ํ•˜๋ฉด nth_element. ์ „์ฒด ์ •๋ ฌ๋ณด๋‹ค ๋น ๋ฆ…๋‹ˆ๋‹ค.

์•ˆ์ •์„ฑ์ด ์ค‘์š”ํ•œ ์ผ€์ด์Šค

1
2
3
4
5
6
7
struct Employee { std::string name; int dept; };
std::vector<Employee> emps = { ... };

// ๋ถ€์„œ๋ณ„๋กœ ์ •๋ ฌํ•˜๋˜ ๊ฐ™์€ ๋ถ€์„œ ์•ˆ์—์„  ์ž…๋ ฅ ์ˆœ์„œ ์œ ์ง€ํ•˜๊ณ  ์‹ถ๋‹ค
std::stable_sort(emps.begin(), emps.end(),
    [](const auto& a, const auto& b){ return a.dept < b.dept; });
// ๊ฐ™์€ dept ์•ˆ์—์„  ์›๋ž˜ ์ž…๋ ฅ ์ˆœ์„œ๋Œ€๋กœ (์ด๋ฆ„์ˆœ ๋“ฑ)

โ†’ std::sort์˜€๋‹ค๋ฉด ๊ฐ™์€ ๋ถ€์„œ ์•ˆ์—์„œ ์ž„์˜์˜ ์ˆœ์„œ๊ฐ€ ๋˜์–ด๋ฒ„๋ฆฝ๋‹ˆ๋‹ค.


10. ์–ธ๋ฆฌ์–ผ์—์„œ์˜ ์ •๋ ฌ โ€” Algo::Sort / TArray::Sort / TLinkedList

๋Œ€์‘ ํ‘œ

std::Unreal Algo:: / ๋ฉค๋ฒ„๋น„๊ณ 
std::sortAlgo::Sort(Range)introsort ๊ธฐ๋ฐ˜
std::sortTArray::Sort() (๋ฉค๋ฒ„)์•ˆ์ •์„ฑ ๋ณด์žฅ X
std::stable_sortAlgo::StableSort(Range)์•ˆ์ • ์ •๋ ฌ
std::stable_sortTArray::StableSort() (๋ฉค๋ฒ„)์•ˆ์ • ์ •๋ ฌ
std::partial_sort(์ง์ ‘ ๋Œ€์‘ ์—†์Œ)Algo::HeapSort + ์ž๋ฅด๊ธฐ ๋“ฑ ์กฐํ•ฉ
std::nth_element(์ง์ ‘ ๋Œ€์‘ ์—†์Œ)์ˆ˜๋™ ๊ตฌํ˜„
std::list::sort(๋Œ€์‘ ์—†์Œ)TLinkedList์— sort ๋ฉค๋ฒ„ ํ•จ์ˆ˜ X โ€” ์ˆ˜๋™ ๊ตฌํ˜„

์ฝ”๋“œ ์˜ˆ์‹œ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "Algo/Sort.h"
#include "Algo/StableSort.h"

TArray<int32> Arr = {3, 1, 4, 1, 5, 9, 2, 6};

// (1) ๋ฉค๋ฒ„ ํ•จ์ˆ˜ โ€” ๊ฐ€์žฅ ์ผ๋ฐ˜์ 
Arr.Sort();                                  // ๊ธฐ๋ณธ < ์˜ค๋ฆ„์ฐจ์ˆœ
Arr.Sort([](int32 A, int32 B){ return A > B; });  // ๋‚ด๋ฆผ์ฐจ์ˆœ ๋žŒ๋‹ค

// (2) Algo::Sort โ€” std::sort ๋Œ€์‘
Algo::Sort(Arr);
Algo::Sort(Arr, [](int32 A, int32 B){ return A < B; });

// (3) ์•ˆ์ • ์ •๋ ฌ
Arr.StableSort();
Algo::StableSort(Arr);

TLinkedList โ€” std::list ๋Œ€์‘์ด 1๊ธ‰์ด ์•„๋‹Œ ์ด์œ 

1
2
3
4
// ์–ธ๋ฆฌ์–ผ์˜ TLinkedList๋Š” ์˜๋„์ ์œผ๋กœ ๊ฐ€๋ฒผ์šด ํ—ฌํผ ์ˆ˜์ค€
TLinkedList<int32> List;
// โ†’ Sort() ๋ฉค๋ฒ„ ํ•จ์ˆ˜ ์—†์Œ
// โ†’ ์ •๋ ฌ์ด ํ•„์š”ํ•˜๋‹ค๋ฉด TArray<int32>๋กœ ์˜ฎ๊ธฐ๊ฑฐ๋‚˜ ์ˆ˜๋™ ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)

โ†’ ์–ธ๋ฆฌ์–ผ์ด cache ์นœํ™”์  ์ž๋ฃŒ๊ตฌ์กฐ(TArray)๋ฅผ 1๊ธ‰์œผ๋กœ ๋‘๊ณ  ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ถ€์ˆ˜์ ์œผ๋กœ ๋‹ค๋ฃจ๋Š” ์ฒ ํ•™(13๋ฒˆ 7์žฅ ์ฐธ๊ณ )์ด ์ •๋ ฌ์—์„œ๋„ ๊ทธ๋Œ€๋กœ ๋“œ๋Ÿฌ๋‚ฉ๋‹ˆ๋‹ค. ๊ฒŒ์ž„ ์—”์ง„์€ ๋งค ํ”„๋ ˆ์ž„ ์บ์‹œ ํšจ์œจ์ด ์ค‘์š”ํ•œ๋ฐ list ๋…ธ๋“œ ๋ถ„์‚ฐ์€ ์ ํ•ฉํ•˜์ง€ ์•Š์œผ๋‹ˆ๊นŒ์š”.

์ฐจ์ด์  ์š”์•ฝ

  • ์–ธ๋ฆฌ์–ผ์€ std::list::sort ๊ฐ™์€ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ ์ „์šฉ ์ •๋ ฌ์„ ์ง€์›ํ•˜์ง€ ์•Š์Œ โ€” ์ •๋ ฌ์ด ํ•„์š”ํ•œ ์ปฌ๋ ‰์…˜์€ TArray ์‚ฌ์šฉ
  • Sort() ๋ฉค๋ฒ„ ํ•จ์ˆ˜์™€ Algo::Sort() ๋‘˜ ๋‹ค ์กด์žฌํ•˜์ง€๋งŒ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๊ฐ€ ์ปจ๋ฒค์…˜
  • TArray::Sort()๋Š” stable์ด ์•„๋‹˜, ์•ˆ์ • ์ •๋ ฌ์ด ํ•„์š”ํ•˜๋ฉด ๋ช…์‹œ์ ์œผ๋กœ StableSort()

11. ๊ผฌ๋ฆฌ์งˆ๋ฌธ ์˜ˆ์ƒ ๊ฒฝ๋กœ

Q1. โ€œ์™œ std::sort๋Š” RandomAccessIterator๋ฅผ ์š”๊ตฌํ•˜๋‚˜์š”? ๊ทธ๋ƒฅ ๋‹ค ๋ฐ›๊ฒŒ ๋งŒ๋“ค๋ฉด ์•ˆ ๋˜๋‚˜์š”?โ€

introsort์˜ ํ•ต์‹ฌ์ธ quicksort partition์ด ๋ฌด์ž‘์œ„ ์ ‘๊ทผ์— ์˜์กดํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. mid pivot ์„ ํƒ, ์–‘ ๋์—์„œ ๋งŒ๋‚˜๋Š” swap, ์žฌ๊ท€ ๋ถ„ํ•  ์‹œ ๋ถ€๋ถ„ ๊ตฌ๊ฐ„ ์ธ๋ฑ์‹ฑ์ด ๋ชจ๋‘ it + n์ด๋‚˜ it - it ๊ฐ™์€ random access ์—ฐ์‚ฐ์„ ์”๋‹ˆ๋‹ค. ForwardIterator๋กœ ๋งŒ๋“ค๋ฉด ์ด ์—ฐ์‚ฐ๋“ค์ด O(n)์ด ๋˜์–ด quicksort ์ž์ฒด๊ฐ€ O(nยฒ) ์œผ๋กœ ๋–จ์–ด์ง‘๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ RandomAccess ์ปจํ…Œ์ด๋„ˆ์šฉ ๋น ๋ฅธ ์ •๋ ฌ์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ, ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์šฉ ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)์€ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋กœ ๋ถ„๋ฆฌํ•œ ๊ฒŒ STL์˜ ์„ค๊ณ„์ž…๋‹ˆ๋‹ค.

Q2. โ€œlist::sort๋Š” ์™œ ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)์„ ์“ฐ๋‚˜์š”? quicksort๋‚˜ heapsort๋Š” ์•ˆ ๋˜๋‚˜์š”?โ€

์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ๊ตฌ์กฐ์™€ ๊ฐ€์žฅ ์ž˜ ๋งž๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋‘ ์ •๋ ฌ ๋ฆฌ์ŠคํŠธ์˜ merge๊ฐ€ ํฌ์ธํ„ฐ ์žฌ์—ฐ๊ฒฐ๋งŒ์œผ๋กœ O(n) in-place๋กœ ๋๋‚ฉ๋‹ˆ๋‹ค. quicksort๋Š” partition์— ๋ฌด์ž‘์œ„ ์ ‘๊ทผ์ด ํ•„์š”ํ•ด list์—์„  ๋น„ํšจ์œจ์ ์ด๊ณ , heapsort๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ฌด์ž‘์œ„ ์ ‘๊ทผ ๊ธฐ๋ฐ˜ ์ž๋ฃŒ๊ตฌ์กฐ(heap)๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)๋Š” ์ˆœ์ฐจ ์ ‘๊ทผ๋งŒ์œผ๋กœ ๋™์ž‘ํ•˜๊ณ  ์•ˆ์ •์„ฑ๋„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋”ฐ๋ผ์˜ต๋‹ˆ๋‹ค. ๋”ํ•ด์„œ ํ‘œ์ค€์€ list::sort์— stable + O(n log n) ๋ณด์žฅ์„ ์š”๊ตฌํ•˜๋Š”๋ฐ ์ด๊ฑธ ๋งŒ์กฑํ•˜๋Š” ๊ฒŒ ์‚ฌ์‹ค์ƒ ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)์ž…๋‹ˆ๋‹ค.

Q3. โ€œ๋‘˜ ๋‹ค O(n log n)์ธ๋ฐ ์‹ค์ œ๋กœ ์–ด๋–ค ์ฐจ์ด๊ฐ€ ์žˆ๋‚˜์š”?โ€

์ด๋ก  ๋ณต์žก๋„๋Š” ๊ฐ™์ง€๋งŒ ์‹ค์ธก ๋น„์šฉ ๊ตฌ์กฐ๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ์ฒซ์งธ, ๋ฐ์ดํ„ฐ ์ด๋™ ๋น„์šฉ์ž…๋‹ˆ๋‹ค. std::sort๋Š” partitionยทmerge ๊ณผ์ •์—์„œ ๊ฐ์ฒด ์ž์ฒด๋ฅผ swapํ•ฉ๋‹ˆ๋‹ค. ํฐ ๊ฐ์ฒด๋ฅผ ๋‹ด์€ ์ปจํ…Œ์ด๋„ˆ๋ผ๋ฉด ๋งค swap๋งˆ๋‹ค memcpy๋‚˜ move ์ƒ์„ฑ์ž๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. list::sort๋Š” prev/next ํฌ์ธํ„ฐ ๋‘ ๊ฐœ๋งŒ ์žฌ๋ฐฐ์น˜ํ•˜๋‹ˆ ๊ฐ์ฒด๋Š” ํ•œ ๋ฒˆ๋„ ์•ˆ ์˜ฎ๊น๋‹ˆ๋‹ค. ๋‘˜์งธ, ์บ์‹œ ์นœํ™”์„ฑ์€ ์ •๋ฐ˜๋Œ€๋กœ vector๊ฐ€ ์••๋„์ ์ž…๋‹ˆ๋‹ค. ์…‹์งธ, iterator ์•ˆ์ •์„ฑ์€ list๊ฐ€ ์šฐ์œ„์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํฐ ๊ฐ์ฒด + ์ž์ฃผ ์ •๋ ฌ + ์•ˆ์ •์„ฑ ํ•„์š” ์ผ€์ด์Šค์—์„  list๊ฐ€, ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ์—” vector + sort๊ฐ€ ์ •๋‹ต์ž…๋‹ˆ๋‹ค.

Q4. โ€œlist::sort๋Š” stable์ธ๋ฐ std::sort๋Š” unstable์ธ ์ด์œ ๋Š”?โ€

์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ฐจ์ด์ž…๋‹ˆ๋‹ค. ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)๋Š” ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ stable์ž…๋‹ˆ๋‹ค โ€” merge ๋‹จ๊ณ„์—์„œ ๋™๋“ฑํ•œ ์›์†Œ๋ฉด ์™ผ์ชฝ(์•ž์ชฝ) ๊ฒƒ์„ ๋จผ์ € ์„ ํƒํ•˜๋„๋ก < ๋งŒ ์“ฐ๊ณ  <= ๋ฅผ ์•ˆ ์“ฐ๋ฉด ์ž๋™์œผ๋กœ ์•ˆ์ •์„ฑ์ด ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด quicksort์˜ partition์€ pivot ์ขŒ์šฐ๋กœ ์›์†Œ๋ฅผ swapํ•˜๋Š” ๊ณผ์ •์—์„œ ๋™๋“ฑ ์›์†Œ์˜ ์ƒ๋Œ€ ์ˆœ์„œ๊ฐ€ ๊นจ์ง‘๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ introsort ์ „์ฒด๋กœ ๋ดค์„ ๋•Œ std::sort๋Š” stable์„ ๋ณด์žฅํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์•ˆ์ •์„ฑ์ด ํ•„์š”ํ•˜๋ฉด std::stable_sort๋ฅผ ์“ฐ๋ฉด ๋˜๋Š”๋ฐ, ์ด๊ฑด ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ O(n)์ด ํ•„์š”ํ•˜๊ฑฐ๋‚˜ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋ชป ์žก์„ ๋•Œ ์‹œ๊ฐ„์ด O(n logยฒ n)๋กœ ๋–จ์–ด์ง‘๋‹ˆ๋‹ค.

Q5. โ€œforward_list์—๋„ sort๊ฐ€ ๋”ฐ๋กœ ์žˆ๋‚˜์š”?โ€

๋„ค, std::forward_list::sort()๊ฐ€ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋กœ ๋”ฐ๋กœ ์žˆ์Šต๋‹ˆ๋‹ค. forward_list๋Š” ForwardIterator๋งŒ ์ง€์›ํ•ด์„œ --it๋„ ์•ˆ ๋˜๋‹ˆ list๋ณด๋‹ค ๋” ์ œ์•ฝ์ด ํฝ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์™ธ๋ถ€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์†๋Œˆ ์ˆ˜๊ฐ€ ์—†๊ณ , ๋‹จ๋ฐฉํ–ฅ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ๊ตฌ์กฐ๋ฅผ ํ™œ์šฉํ•œ ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)๋ฅผ ๋ฉค๋ฒ„๋กœ ์ œ๊ณตํ•˜๋Š” ๊ฒŒ ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ๊ฐ™์€ ์ด์œ ๋กœ merge, splice_after, unique, reverse ๊ฐ™์€ ์—ฐ์‚ฐ๋„ ๋ชจ๋‘ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋กœ ์žˆ์Šต๋‹ˆ๋‹ค.

Q6. โ€œset์ด๋‚˜ map์€ ์ •๋ ฌ๋œ ์ƒํƒœ๋กœ ์œ ์ง€๋˜๋Š”๋ฐ sort ๋ฉค๋ฒ„ ํ•จ์ˆ˜๊ฐ€ ์—†๋Š” ์ด์œ ๋Š”?โ€

์ž๋ฃŒ๊ตฌ์กฐ ์ž์ฒด๊ฐ€ ์‚ฝ์ž… ์‹œ์ ์— ์ด๋ฏธ ์ •๋ ฌ์„ ์œ ์ง€ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. std::set๊ณผ std::map์€ RB-Tree ๊ธฐ๋ฐ˜์ด๊ณ  ์‚ฝ์ž…ํ•  ๋•Œ ํŠธ๋ฆฌ ํšŒ์ „๊ณผ ์žฌ์ƒ‰์น ๋กœ ์ •๋ ฌ ๋ถˆ๋ณ€์‹์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ณ„๋„์˜ sort ํ˜ธ์ถœ์ด ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค. ์ด๊ฒŒ list์™€์˜ ๊ฒฐ์ •์  ์ฐจ์ด์ž…๋‹ˆ๋‹ค โ€” list๋Š” ์ž„์˜ ์ˆœ์„œ๋กœ pushํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ •๋ ฌ์ด ๋ณ„๋„ ์—ฐ์‚ฐ์ด์ง€๋งŒ, set/map์€ ์ •๋ ฌ ์ƒํƒœ ์ž์ฒด๊ฐ€ ์ž๋ฃŒ๊ตฌ์กฐ์˜ invariant์ž…๋‹ˆ๋‹ค.

Q7. โ€œstd::sort ๋Œ€์‹  std::list::sort๋ฅผ ์“ฐ๋ฉด ํ•ญ์ƒ ๋น ๋ฅธ๊ฐ€์š”?โ€

์•„๋‹™๋‹ˆ๋‹ค. list ์ž์ฒด๊ฐ€ vector๋ณด๋‹ค ๊ฑฐ์˜ ํ•ญ์ƒ ๋А๋ฆฝ๋‹ˆ๋‹ค. 1M๊ฐœ ์ •์ˆ˜ ์ •๋ ฌ ๋ฒค์น˜๋งˆํฌ์—์„œ vector::sort๊ฐ€ list::sort๋ณด๋‹ค ๋ณดํ†ต 5~10๋ฐฐ ๋น ๋ฆ…๋‹ˆ๋‹ค. ์บ์‹œ ์นœํ™”์„ฑ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. list๊ฐ€ ์ •๋‹นํ™”๋˜๋Š” ์ผ€์ด์Šค๋Š” 13๋ฒˆ์—์„œ ์ •๋ฆฌํ•œ ๊ทธ๋Œ€๋กœ โ€” ๋งค์šฐ ํฐ ๊ฐ์ฒด + ์žฆ์€ splice/merge + iterator ์•ˆ์ •์„ฑ ์ ˆ๋Œ€ ํ•„์š”. ํ‰๋ฒ”ํ•œ ์ •๋ ฌ ์›Œํฌ๋กœ๋“œ๋ฉด vector + std::sort๊ฐ€ ์••์Šน์ž…๋‹ˆ๋‹ค. โ€œlist::sort๊ฐ€ ๋”ฐ๋กœ ์žˆ๋‹คโ€๋Š” ์‚ฌ์‹ค์€ list๋ฅผ ์จ์•ผ ํ•  ๋•Œ์˜ ์ •๋ ฌ ๋ฐฉ๋ฒ•์ด์ง€, list๋ฅผ ์“ธ ์ด์œ ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

Q8. โ€œstable_sort์™€ list::sort๊ฐ€ ๋‘˜ ๋‹ค stable์ด๋ฉด ์ฐจ์ด๋Š”?โ€

๋™์ž‘ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. std::stable_sort๋Š” RandomAccessIterator ์ปจํ…Œ์ด๋„ˆ(vectorยทdequeยทarray)์šฉ ์•ˆ์ • ์ •๋ ฌ์ด๊ณ , std::list::sort๋Š” list ์ „์šฉ์ž…๋‹ˆ๋‹ค. ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๋„ ๋‹ค๋ฆ…๋‹ˆ๋‹ค โ€” stable_sort๋Š” O(n) ์ถ”๊ฐ€ ๋ฒ„ํผ๋ฅผ ์‹œ๋„ํ•˜๊ณ  ์‹คํŒจํ•˜๋ฉด ์‹œ๊ฐ„์ด O(n logยฒ n)๋กœ ๋–จ์–ด์ง€์ง€๋งŒ, list::sort๋Š” ๋…ธ๋“œ ์žฌ์—ฐ๊ฒฐ๋งŒ์œผ๋กœ ํ•ญ์ƒ O(1) ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ + O(n log n) ์‹œ๊ฐ„์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

Q9. โ€œ๊ทธ๋Ÿผ list::sort๋Š” std::stable_sort๋ณด๋‹ค ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์ด ์ข‹๋‹ค๋Š” ๊ฑด๊ฐ€์š”?โ€

๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ ์ธก๋ฉด์—์„œ๋Š” ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ list ์ž์ฒด๊ฐ€ ๋…ธ๋“œ๋งˆ๋‹ค prev/next ํฌ์ธํ„ฐ 16๋ฐ”์ดํŠธ + ํž™ ํ• ๋‹น ํ—ค๋”๋ฅผ ๊ฐ–๊ณ  ์žˆ์–ด ๋ฉ”๋ชจ๋ฆฌ ์ด๋Ÿ‰์€ vector๋ณด๋‹ค ํ›จ์”ฌ ๋งŽ์ด ์”๋‹ˆ๋‹ค (13๋ฒˆ 5์žฅ). ์ •๋ ฌ ์ค‘ ์ถ”๊ฐ€๋กœ ์“ฐ๋Š” ์ž„์‹œ ๋ฉ”๋ชจ๋ฆฌ๋งŒ ์ ์„ ๋ฟ์ด๊ณ , ๋ฒ ์ด์Šค ๋ฉ”๋ชจ๋ฆฌ ํ‘ธํ„ฐํ”„๋ฆฐํŠธ๋Š” vector๊ฐ€ ์••์Šน์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์ด๋ผ๋Š” ๋‹จ์–ด๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด์„ํ•˜๋А๋ƒ์— ๋”ฐ๋ผ ๋‹ต์ด ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค.

Q10. โ€œTLinkedList๋Š” ์™œ Sort ๋ฉค๋ฒ„ ํ•จ์ˆ˜๊ฐ€ ์—†๋‚˜์š”?โ€

์–ธ๋ฆฌ์–ผ์ด ์˜๋„์ ์œผ๋กœ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ 1๊ธ‰ ์ž๋ฃŒ๊ตฌ์กฐ๋กœ ๋งŒ๋“ค์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ฒŒ์ž„ ์—”์ง„์€ ๋งค ํ”„๋ ˆ์ž„ ์ˆ˜๋งŒ ๊ฐœ ๊ฐ์ฒด๋ฅผ ์ˆœํšŒํ•˜๋Š”๋ฐ list ๋…ธ๋“œ ๋ถ„์‚ฐ์€ ์บ์‹œ ๋ฏธ์Šค๋กœ ์ง๊ฒฐ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์–ธ๋ฆฌ์–ผ์€ TArray๋ฅผ 1๊ธ‰์œผ๋กœ ๋‘๊ณ , TLinkedList/TDoubleLinkedList๋Š” ๊ฐ€๋ฒผ์šด ํ—ฌํผ๋กœ๋งŒ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ •๋ ฌ์ด ํ•„์š”ํ•˜๋‹ค๋ฉด ๋ณดํ†ต TArray๋กœ ๋ณ€ํ™˜ํ•˜๊ฑฐ๋‚˜ ์ง์ ‘ merge sort๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒŒ 13๋ฒˆ์—์„œ ๋ณธ โ€œ์บ์‹œ ์นœํ™”์„ฑ ์šฐ์„ โ€ ์ฒ ํ•™์˜ ๋˜ ๋‹ค๋ฅธ ๋ฐœํ˜„์ž…๋‹ˆ๋‹ค.


ํ•ต์‹ฌ ์š”์•ฝ ์นด๋“œ (์žฌ๊ฒŒ์žฌ)

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
std::sort        = <algorithm>, RandomAccess ์š”๊ตฌ, introsort, unstable
                   ๊ฐ์ฒด swap ๋‹ค์ˆ˜, O(log n) ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ, ์บ์‹œ ์นœํ™”

std::list::sort  = list ๋ฉค๋ฒ„, Bidirectional๋กœ OK, ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort), stable
                   ํฌ์ธํ„ฐ ์žฌ์—ฐ๊ฒฐ๋งŒ, O(1) ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ, iterator ๋ฌดํšจํ™” X

std::forward_list::sort  = forward_list ๋ฉค๋ฒ„, Forward๋กœ OK, ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort), stable

์ฐจ์ด๊ฐ€ ์ƒ๊ธด ์ด์œ  3๊ฐ€์ง€:
  โ‘  iterator ์นดํ…Œ๊ณ ๋ฆฌ โ€” list iterator๋Š” RandomAccess ์•„๋‹˜ โ†’ std::sort ์ปดํŒŒ์ผ ์—๋Ÿฌ
  โ‘ก ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ ํ•ฉ์„ฑ โ€” quicksort partition์€ ๋ฌด์ž‘์œ„ ์ ‘๊ทผ ํ•„์ˆ˜, list์—” ๋ณ‘ํ•ฉ ์ •๋ ฌ (merge sort)๊ฐ€ ์ž์—ฐ
  โ‘ข ๋น„์šฉ ๊ตฌ์กฐ โ€” list::sort๋Š” ๋ฐ์ดํ„ฐ ์ด๋™ 0 (ํฌ์ธํ„ฐ๋งŒ), ํฐ ๊ฐ์ฒด์ผ์ˆ˜๋ก ์ด๋“ ํผ

๊ฐ™์€ ํŒจํ„ด (๋ฉค๋ฒ„ vs ์•Œ๊ณ ๋ฆฌ์ฆ˜):
  set/map::find       โ†’ O(log n)  โ† ์•Œ๊ณ ๋ฆฌ์ฆ˜ std::find๋Š” O(n)
  unordered_map::find โ†’ O(1) ํ‰๊ท 
  list::merge/splice/unique/reverse โ†’ ๋…ธ๋“œ ์žฌ์—ฐ๊ฒฐ๋งŒ

์ •๋ ฌ family:
  std::stable_sort    โ†’ vectorยทdequeยทarray ์šฉ ์•ˆ์ • ์ •๋ ฌ, O(n) ๋ฉ”๋ชจ๋ฆฌ ๋˜๋Š” O(n logยฒ n) ์‹œ๊ฐ„
  std::partial_sort   โ†’ ์ƒ์œ„ k๊ฐœ๋งŒ, O(n log k)
  std::nth_element    โ†’ k๋ฒˆ์งธ๋งŒ ์ œ์ž๋ฆฌ, O(n) ํ‰๊ท 

์–ธ๋ฆฌ์–ผ:
  Algo::Sort / TArray::Sort           โ€” std::sort ๋Œ€์‘
  Algo::StableSort / TArray::StableSort โ€” std::stable_sort ๋Œ€์‘
  TLinkedList โ€” Sort ๋ฉค๋ฒ„ ํ•จ์ˆ˜ ์—†์Œ (1๊ธ‰ X, ์ˆ˜๋™ ๊ตฌํ˜„)

ํ‘œ์ค€ ์š”๊ตฌ:
  list::sort โ†’ stable + O(n log n) ๋ณด์žฅ
  std::sort  โ†’ ํ‰๊ท /์ตœ์•… O(n log n) ๋ณด์žฅ (introsort ๋•๋ถ„)

ํšŒ๊ท€ ๋‹ค๋ฆฌ โ€” ๋‹ค๋ฅธ CS ํŒŒ์ผ ์—ฐ๊ฒฐ

ํŒŒ์ผ์—ฐ๊ฒฐ ์ง€์ 
13_vector_vs_list๋ฉ”๋ชจ๋ฆฌ ๋ ˆ์ด์•„์›ƒยท์บ์‹œ ์นœํ™”์„ฑ. list๊ฐ€ ์ •๋‹นํ™”๋˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค(ํฐ ๊ฐ์ฒด + splice + iterator ์•ˆ์ •์„ฑ)๊ฐ€ list::sort์˜ ๊ฐ€์น˜์™€ ์ง๊ฒฐ
16_stl_containersSTL ์ปจํ…Œ์ด๋„ˆ ์นดํ…Œ๊ณ ๋ฆฌ ์ •๋ฆฌ. forward_list / list / vector iterator ์นดํ…Œ๊ณ ๋ฆฌ ํ‘œ
17_find_vs_binary_search9-1 iterator ์นดํ…Œ๊ณ ๋ฆฌ(Input โ†’ Forward โ†’ Bidirectional โ†’ RandomAccess), ๋ฉค๋ฒ„ vs ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ปจ๋ฒค์…˜. ์ด๋ฒˆ 18๋ฒˆ์ด ๊ทธ ์ปจ๋ฒค์…˜์˜ ์ •๋ ฌ ๋ฒ„์ „
15_pushback_vs_emplacebackmove ์ƒ์„ฑ์žยท๊ฐ์ฒด ์ด๋™ ๋น„์šฉ. list::sort๊ฐ€ โ€œ๋ฐ์ดํ„ฐ ์ด๋™ 0โ€์œผ๋กœ ํšŒํ”ผํ•˜๋Š” ๋น„์šฉ์˜ ์ •์ฒด
14_std_mapRB-Tree ์ž๋ฃŒ๊ตฌ์กฐ์˜ invariant ์œ ์ง€(set/map์€ ์ •๋ ฌ ๋ฉค๋ฒ„๊ฐ€ ๋ถˆํ•„์š”ํ•œ ์ด์œ ). list์™€์˜ ๋Œ€๋น„
์ด ๊ธฐ์‚ฌ๋Š” ์ €์ž‘๊ถŒ์ž์˜ CC BY 4.0 ๋ผ์ด์„ผ์Šค๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.

ยฉ GoldBoll. ์ผ๋ถ€ ๊ถŒ๋ฆฌ ๋ณด์œ 

Powered by Jekyll with Chirpy theme

์ธ๊ธฐ ํƒœ๊ทธ