์ž๋ฃŒ๊ตฌ์กฐ/๐Ÿ‘‰์•Œ๊ณ ๋ฆฌ์ฆ˜ - 24

์˜ค๋Š˜ ๋“ค์€ ๊ฐ•์˜ ๋ชฉ๋ก

  1. Union Find
  2. ํฌ๋ฃจ์Šค์นผ - 1 : Union-by-Rank

Union Find ์ตœ์ ํ™”

๊ธฐ์กด Union Find ํฌ์ŠคํŠธ

worst
์ตœ์•…

์ €๋ฒˆ ํฌ์ŠคํŠธ์—์„œ ์ตœ์•…์˜ ๊ฒฝ์šฐ๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ๊นŒ์ง€ ํ–ˆ๋‹ค.
์ด์ œ ์ด๋Ÿฐ ์ตœ์•…์˜ ๊ฒฝ์šฐ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ์ตœ์ ํ™” ๊ธฐ๋ฒ• ๋‘๊ฐ€์ง€๋ฅผ ์†Œ๊ฐœํ•˜๊ฒ ๋‹ค.

  1. union-by-rank
  2. path-compression : ๊ฒฝ๋กœ์••์ถ•

Unionํ•จ์ˆ˜์—์„œ ์ตœ์ ํ™” : union-by-rank

๊ฐ ๋†’์ด๋ณ„๋กœ ๋žญํฌ๋ฅผ ๋ถ€์—ฌํ•˜์—ฌ, Unionํ•  ๋•Œ ๋‘ ์ง‘ํ•ฉ์˜ ์ตœ๋Œ€ ๋…ธ๋“œ๋ฅผ ๋น„๊ตํ•˜๊ณ ,
๋” ๋†’์€ ๋žญํฌ๋ฅผ ๊ฐ€์ง„ ์ง‘ํ•ฉ์— ๋‚ฎ์€ ๋žญํฌ๋ฅผ ๊ฐ€์ง„ ์ง‘ํ•ฉ์„ ๋ถ™์ด๋Š” ๋ฐฉ๋ฒ•.

์‹œ๊ฐ„๋ณต์žก๋„ : ์ตœ์•…์˜ ๊ฒฝ์šฐ์—์„œ leaf๋…ธ๋“œ(์ตœํ•˜์œ„ ๋…ธ๋“œ)๋ฅผ ์ด์šฉํ•ด union/find์—ฐ์‚ฐ์˜ ๊ฒฝ์šฐ ๋†’์ด๊ฐ€ $N$์ด๋ผ์„œ $O(N)$์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ€์ง€๋Š”๋ฐ,
์ด ๋ฐฉ๋ฒ•์„ ์ด์šฉํ•˜๋ฉด ์ตœ์•…์˜ ๊ฒฝ์šฐ์—๋„ ๋†’์ด๊ฐ€ $log N$์œผ๋กœ $O(log N)$์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋œ๋‹ค.

  1. ๋‘ ์ง‘ํ•ฉ A, B์—์„œ ํ•œ ์ง‘ํ•ฉ์˜ ๋žญํฌ๊ฐ€ ๋†’์€ ๊ฒฝ์šฐ,
    ๋žญํฌ๊ฐ€ ๋†’์€ ์ง‘ํ•ฉ์— ๋‚ฎ์€ ์ง‘ํ•ฉ์„ ๋ถ™์ธ๋‹ค.
  2. ๋‘ ์ง‘ํ•ฉ A, B์—์„œ ๋‘ ์ง‘ํ•ฉ์˜ ๋žญํฌ๊ฐ€ ๊ฐ™์€ ๊ฒฝ์šฐ,
    ํ•œ ์ง‘ํ•ฉ์˜ ๋žญํฌ๋ฅผ ์˜ฌ๋ฆฌ๊ณ , ๋‹ค๋ฅธ ์ง‘ํ•ฉ์„ ๋ถ™์ธ๋‹ค.

union

union-by-rank ๊ตฌํ˜„

union-by-rank ๊ตฌํ˜„์„ ์œ„ํ•ด์„œ๋Š” rank๋ผ๋Š” ๊ณต๊ฐ„์ด ํ•„์š”ํ•˜๋‹ค.
๊ฐ ๋…ธ๋“œ๋Š” ๋žญํฌ๊ฐ’์„ ๊ฐ€์ง€๊ณ , ๋žญํฌ์˜ ํŒ๋ณ„์€ ์ตœ์ƒ์œ„ ๋…ธ๋“œ์˜ ๋žญํฌ๋กœ ํŒ๋ณ„ํ•˜๋ฉด ๊ฐ„๋‹จํ•˜๋‹ค.

from string import ascii_uppercase
parentOf = {v : v for v in ascii_uppercase[:6]}
rank = {v : 0 for v in ascii_uppercase[:6]}

def Find(node):
    if parentOf[node] != node:
        return Find(parentOf[node])
    return node

def Union (n1, n2):
    p1 = Find(n1)
    p2 = Find(n2)
    if p1 == p2:
        return
    # union-by-rank ๊ตฌํ˜„
    if rank[p1] < rank[p2]:
        parentOf[p1] = p2
    elif rank[p1] > rank[p2]:
        parentOf[p2] = p1
    else:
        rank[p1] += 1
        parentOf[p2] = p1

Union('E', 'F')
Union('D', 'E')
Union('C', 'D')
Union('B', 'C')
Union('A', 'B')
print(parentOf)

์ตœ์•…์˜ ๊ฒฝ์šฐ๋กœ ๋‚˜ํƒ€๋‚ฌ๋˜ ๊ฒƒ์ด 1์˜ ๋žญํฌ๋ฅผ ๊ฐ€์ง€๋Š” ์ง‘ํ•ฉ์ด ๋˜์—ˆ๋‹ค.

Findํ•จ์ˆ˜์—์„œ ์ตœ์ ํ™” : path-compression

๊ฒฝ๋กœ์••์ถ•์ด๋ผ๊ณ  ํ•˜๋ฉฐ, Find๋ฅผ ์‹คํ–‰ํ•œ ๋…ธ๋“œ์™€, ํƒ€๊ณ  ์˜ฌ๋ผ๊ฐ„ ๋…ธ๋“œ๋“ค์„ ๋ฃจํŠธ ๋…ธ๋“œ์— ๋ฐ”๋กœ ์—ฐ๊ฒฐํ•˜์—ฌ ๋‹ค์Œ Find ์—ฐ์‚ฐ์‹œ ํƒ์ƒ‰ ํšŸ์ˆ˜๋ฅผ ์ค„์ด๋Š” ๋ฐฉ๋ฒ•

์‹œ๊ฐ„๋ณต์žก๋„ : union-by-rank๋ฅผ ๊ตฌํ˜„ํ–ˆ์„๋•Œ, $O(log N)$์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ€์ง„๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ,
path-compression์„ ๊ตฌํ˜„ํ–ˆ์„ ๋•Œ๋Š”, $O(1)$์˜ ์‹œ๊ฐ„๋ณต์žก๋„์— ๊ฐ€๊น๋‹ค.

path-compression ๊ธฐ๋ฒ•์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ Findํ•จ์ˆ˜๋ฅผ ์žฌ๊ท€ํ•จ์ˆ˜๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค.

path-compression ๊ตฌํ˜„

path-compression์€ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„๋œ๋‹ค.
๊ธฐ์กด์—๋Š” Find(parentOf[node])์˜ ๋ฐ˜ํ™˜๊ฐ’์„ ๋ฐ”๋กœ ๋ฐ˜ํ™˜ํ–ˆ๋Š”๋ฐ,
์ด ๊ฐ’์„ parentOf[node]์— ์ €์žฅํ•˜๋ฉด์„œ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋œ๋‹ค.

from string import ascii_uppercase
parentOf = {v : v for v in ascii_uppercase[:6]}
rank = {v : 0 for v in ascii_uppercase[:6]}

def Find(node):
    if parentOf[node] != node:
        # path-compression
        parentOf[node] = Find(parentOf[node])
    return parentOf[node]

def Union (n1, n2):
    p1 = Find(n1)
    p2 = Find(n2)
    if p1 == p2:
        return
    # union-by-rank ๊ตฌํ˜„
    if rank[p1] < rank[p2]:
        parentOf[p1] = p2
    elif rank[p1] > rank[p2]:
        parentOf[p2] = p1
    else:
        rank[p1] += 1
        parentOf[p2] = p1

Union('A', 'B')
Union('C', 'D')
Union('A', 'D')
Union('E', 'F')
Union('D', 'F')
print(parentOf)
print(Find('F'))
print(parentOf)

path

D์˜ ๋ถ€๋ชจ๊ฐ€ C๊ฐ€ ์•„๋‹Œ A๋‹ค.
Union(โ€˜Dโ€™, โ€˜Fโ€™)์—์„œ Find(โ€˜Dโ€™)๋ฅผ ์‹คํ–‰ํ•˜๋ฉด์„œ ๊ฒฝ๋กœ์••์ถ•์œผ๋กœ A๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ๋˜์—ˆ๋‹ค.

๋งˆ์ง€๋ง‰

Unionํ•จ์ˆ˜๋Š” ๋‹ค์Œ์‹œ๊ฐ„์— ๊ตฌํ˜„??? ํ•œ๋‹ค๊ณ  ํ•œ๋‹ค???
??? : ์„ ์ƒ๋‹˜ ํฌ๋ฃจ์Šค์นผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋ผ๋ฉด์„œ์š” ๋ถ„๋ช… ์ œ๋ชฉ์—” ํฌ๋ฃจ์Šค์นผ์ด๋žฌ๋Š”๋ฐโ€ฆ

2020-11-18 ์ˆ˜์ •

unionํ•จ์ˆ˜์—์„œ ๊ฐ™์€ ์ง‘ํ•ฉ์ผ๋•Œ, ํ•ฉ์น˜์ง€ ์•Š๋Š” ๋ถ€๋ถ„์„ ์•ˆ์จ๋†จ๋‹ค.
Find์ดํ›„ ์•„๋ž˜ ์ฝ”๋“œ๋งŒ ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค.

if p1 == p2:
    return

๋Œ“๊ธ€๋‚จ๊ธฐ๊ธฐ