Data Structure(1) Linked List (์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ)

    ๋ฐ˜์‘ํ˜•

    ๐Ÿ“ŒLinked List (์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ)

    • linked list๋Š” ๋–จ์–ด์ง„ ๊ณณ์— ์กด์žฌํ•˜๋Š” ๋ฐ์ดํ„ฐ๋“ค์„ ํฌ์ธํ„ฐ๋กœ '์—ฐ๊ฒฐ'ํ•ด์„œ ๊ด€๋ฆฌํ•˜๋Š” data structure
    • ์žฅ์ (๋ฐฐ์—ด์˜ ๋‹จ์  ๊ทน๋ณต): ๋น„์—ฐ์†์  ๋ฐ์ดํ„ฐ๋ฅผ ํฌ์ธํ„ฐ๋กœ ์—ฐ๊ฒฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋ฏธ๋ฆฌ ํ• ๋‹น๋ฐ›์„ ํ•„์š”๊ฐ€ ์—†์Œ
      ๋ฐฐ์—ด์€ ์—ฐ์†์ ์œผ๋กœ ์—ฐ๊ฒฐ๋œ ๊ณต๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๋‚˜์—ดํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํŠน์ •ํ•œ ์—ฐ๊ฒฐ๋œ ๊ณต๊ฐ„์„ ๋ฏธ๋ฆฌ ํ• ๋‹น๋ฐ›์•„์•ผ ํ•จ
    • ๋‹จ์ : ๊ฐ ๋ฐ์ดํ„ฐ๋งˆ๋‹ค ๋‹ค์Œ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ฃผ์†Œ(ํฌ์ธํ„ฐ)๋„ ๊ฐ™์ด ์ €์žฅํ•ด์•ผํ•˜๋ฏ€๋กœ ์ €์žฅ๊ณต๊ฐ„ ํšจ์œจโ†“
      ์ฒซ ๋…ธ๋“œ(head)๋ถ€ํ„ฐ ์ญˆ์šฐ์šฐ-์šฑ ๊ฒ€์ƒ‰ํ•ด์•ผ ํ•ด์„œ ์—ฐ๊ฒฐ ์ •๋ณด๋ฅผ ์ฐพ๋Š” ์‹œ๊ฐ„์ด ํ•„์š”ํ•˜์—ฌ ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜๋Š”๋ฐ์— ์‹œ๊ฐ„์ด ์†Œ์š” (๋ฐฐ์—ด์€ index๋กœ ๋ฐ”๋กœ ์ ‘๊ทผ ๊ฐ€๋Šฅ)
      ์ค‘๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€/์‚ญ์ œํ•  ๋•Œ, ์ถ”๊ฐ€์  ์ž‘์—…์ด ํ•„์š”

    ๐Ÿ“Œ์ผ๋ฐ˜(๊ฐ„๋‹จํ•œ) linked list

    1) node ๊ตฌํ˜„

    python class๋ฅผ ์ด์šฉํ•˜์—ฌ linked list node ๊ตฌํ˜„

    class Node:  
    def **init**(self, data):  
    self.data = data  
    self.next = None  

    __init__ํ•จ์ˆ˜๋กœ ํด๋ž˜์Šค๊ฐ€ ๊ฐ์ฒดํ™” ๋  ๋•Œ๋งˆ๋‹ค ๊ฐ์ฒด์˜ data์™€ next๋ฅผ initialize
    ๊ฐ์ฒดํ™” ๋  ๋•Œ๋งˆ๋‹ค next๋Š” None์œผ๋กœ ์„ ์–ธ

    def **init**(self, data, next=None):  
    self.data = data  
    self.next = next  

    instance๋ฅผ ์ƒ์„ฑํ•  ๋•Œ๋งˆ๋‹ค parameter๋ฅผ 2๊ฐœ ๋„ฃ์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ฐ”๋กœ next๋ฅผ ์„ค์ • ๊ฐ€๋Šฅ(next ๊ฐ’ ์„ ์–ธํ•˜์ง€ ์•Š์œผ๋ฉด default๊ฐ’์€ None๊ฐ’์œผ๋กœ)

    2) node์™€ node ์—ฐ๊ฒฐ(pointer)

    node2 = Node(2) #node2.data = 2, node2.next = None  
    node1.next = node2  
    head = node1  

    3) ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ํ•˜๊ธฐ

    def **init**(self, data, next=None):  
    self.data = data  
    self.next = next
    
    def add(data):  
    node = head #ํ—ค๋“œ ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ(node = head = node1 = Node(1))  
    while node.next: #๋‹ค์Œ ๋…ธ๋“œ๊ฐ€ ์žˆ์œผ๋ฉด(node.next๊ฐ€ ์žˆ์œผ๋ฉด)  
    node = node.next #๋‹ค์Œ ๋…ธ๋“œ๋กœ ์ด๋™ (๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๊นŒ์ง€ ํƒ€๊ธฐ)  
    node.next = Node(data) #๋งˆ์ง€๋ง‰ ๋…ธ๋“œ์˜ next์— ์ƒˆ๋กœ์šด ๋…ธ๋“œ ํ• ๋‹น  
    • ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ํ•จ์ˆ˜ add() ์ •์˜
    • while๋ฌธ์€ ๋‹ค์Œ ๋…ธ๋“œ๊ฐ€ ์กด์žฌํ•  ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณต
      node๋ฅผ ๊ณ„์† ๋‹ค์Œ node๋กœ ์˜ฎ๊ฒจ๊ฐ€๋ฉฐ ๊ฒฐ๊ตญ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ node๋ฅผ ์ฐพ์„ ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณต
    • ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๋ฅผ ์ฐพ์œผ๋ฉด ๊ทธ ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ์˜ ๋‹ค์Œ ์ฃผ์†Œ๋ฅผ ์ƒˆ๋กญ๊ฒŒ ์ถ”๊ฐ€ํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฐ์ฒด Node(data)๋กœ ํ• ๋‹น
    head = node1  
    for index in range(2, 10):  
    add(index)  

    1๋ถ€ํ„ฐ 9๊นŒ์ง€ ์—ฐ๊ฒฐ๋œ linked list ์ƒ์„ฑ

    4) ๋ฐ์ดํ„ฐ ์ถœ๋ ฅํ•˜๊ธฐ (search)

    node = head  
    while node.next:  
    print(node.data)  
    node = node.next #๋‹ค์Œ ๋…ธ๋“œ ํƒ€๊ธฐ  
    print (node.data) #node.next๊ฐ€ ์—†๋Š” ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ node๊นŒ์ง€ ์ถœ๋ ฅ ์™„๋ฃŒ  

    ๐Ÿ“ŒํŒŒ์ด์ฌ ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์œผ๋กœ linked list ๊ตฌํ˜„

    ๊ตฌํ˜„ํ•  class: Node, NodeMgmt

    ๊ตฌํ˜„ํ•  function(method): add, desc, delete, search_node

    1) node์™€ node ์‚ฌ์ด์— ์ƒˆ๋กœ์šด node ์ถ”๊ฐ€

    img

    (์ถœ์ฒ˜: wikipedia, https://en.wikipedia.org/wiki/Linked_list)

    class Node:  
    def **init**(self, data, next=None):  
    self.data = data  
    self.next = next
    
    class NodeMgmt:  
    def **init**(self, data):  
    self.head = Node(data)
    
    
    def add(self, data):
        if self.head == '': #๋ฐฉ์–ด์ฝ”๋“œ
            self.head = Node(data)
        else:
            node = self.head
            while node.next: #while๋ฌธ์€ ์ œ์ผ ๋งˆ์ง€๋ง‰ node๋ฅผ ํƒ€๊ธฐ ์œ„ํ•จ
                node = node.next
            node.next = Node(data)
    
    def desc(self):
        node = self.head
        while node: #node๊ฐ€ ์žˆ์œผ๋ฉด
            print (node.data)
            node = node.next #๋‹ค์Œ node ํƒ€๊ธฐ
    
    • NodeMgmt class์—์„œ๋Š” __init__ํ•จ์ˆ˜์—์„œ NodeMgmt(data)๋ฅผ ๊ฐ์ฒดํ™”ํ•˜์—ฌ instance๋ฅผ ์ƒ์„ฑํ•˜๋ฉด Node(data)๊ฐ€ head๋กœ ๊ฐ™์ด ์ƒ์„ฑ๋จ
      (๋งจ ์•ž ๋…ธ๋“œ(head node)์˜ ์ฃผ์†Œ๋ฅผ ์•Œ๊ณ  ์žˆ์–ด์•ผ ์ „์ฒด ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ œ์–ด ๊ฐ€๋Šฅ(์ถ”๊ฐ€/์‚ญ์ œ/๊ฒ€์ƒ‰))
    • add(): ๋งจ ๋์— ๋…ธ๋“คใ„น ์ถ”๊ฐ€ํ•˜๋Š” ํ•จ์ˆ˜
    • desc(): ์ „์ฒด linked list์˜ ๊ฐ’์„ ์ถœ๋ ฅํ•ด์ฃผ๋Š” ํ•จ์ˆ˜

    ```

    linkedlist1 = NodeMgmt(0)
    print(linkedlist1.desc()) #0
    ```

    ๊ฐ์ฒด ์ƒ์„ฑ => data = 0, next = None, head = linkedlist1

    for data in range(1, 10):  
    linkedlist1.add(data)  
    print(linkedlist1.desc()) #0, 1, 2, 3, 4, 5, 6, 7, 8, 9  

    2) ํŠน์ • ๋…ธ๋“œ ์‚ญ์ œ (head node / tail node / middle node ์‚ญ์ œ)

    class Node:  
    def **init**(self, data, next=None):  
    self.data = data  
    self.next = next
    
    class NodeMgmt:  
    def **init**(self, data):  
    self.head = Node(data)
    
    
    def add(self, data):
        if self.head == '':
            self.head = Node(data)
        else:
            node = self.head
            while node.next:
                node = node.next
            node.next = Node(data)
    
    def desc(self):
        node = self.head
        while node:
            print (node.data)
            node = node.next
    
    def delete(self, data):
        if self.head == '': #๋ฐฉ์–ด ์ฝ”๋“œ: head๊ฐ€ ์•„์˜ˆ ์—†์„ ๋•Œ
            print ("ํ•ด๋‹น ๊ฐ’์„ ๊ฐ€์ง„ ๋…ธ๋“œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.")
            return
    
        if self.head.data == data: #head node๋ฅผ ์‚ญ์ œํ•  ๋•Œ
            temp = self.head
            self.head = self.head.next #head ๋ณ€๊ฒฝ
            del temp
        else: # middle/tail node๋ฅผ ์‚ญ์ œํ•˜๋Š” ๊ฒฝ์šฐ
            node = self.head
            while node.next:
                if node.next.data == data: # if-else๋ฌธ์€ ๋‚ด๊ฐ€ ์‚ญ์ œํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฐ’์„ ์ฐพ์„ ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณต
                    temp = node.next
                    node.next = node.next.next
                    del temp
                    return
                else: #๋‚ด๊ฐ€ ์ฐพ๋Š” ๊ฐ’์ด ์•„๋‹ˆ๋ฉด ๋‹ค์Œ ๋…ธ๋“œ ํƒ€๊ธฐ
                    node = node.next
    
    
    • delete(): ํŠน์ • data๋ฅผ ๊ฐ€์ง„ ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•˜๋Š” ํ•จ์ˆ˜
    • head node๋ฅผ ์‚ญ์ œํ•˜๋Š” ๊ฒฝ์šฐ์™€ ์ค‘๊ฐ„/tail node๋ฅผ ์‚ญ์ œํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ๋ถ„๋ฆฌ

    3) ๋…ธ๋“œ ๋ฐ์ดํ„ฐ๊ฐ€ ํŠน์ • ์ˆซ์ž์ธ ๋…ธ๋“œ๋ฅผ search

    class Node:  
    def **init**(self, data):  
    self.data = data  
    self.next = None
    
    class NodeMgmt:  
    def **init**(self, data):  
    self.head = Node(data)
    
    
    def add(self, data):
        if self.head == '':
            self.head = Node(data)
        else:
            node = self.head
            while node.next:
                node = node.next
            node.next = Node(data)
    
    def desc(self):
        node = self.head
        while node:
            print (node.data)
            node = node.next
    
    def delete(self, data):
        if self.head == '':
            print ('ํ•ด๋‹น ๊ฐ’์„ ๊ฐ€์ง„ ๋…ธ๋“œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.')
            return
        if self.head.data == data: # ๊ฒฝ์šฐ์˜ ์ˆ˜1: self.head๋ฅผ ์‚ญ์ œํ•ด์•ผํ•  ๊ฒฝ์šฐ - self.head๋ฅผ ๋ฐ”๊ฟ”์ค˜์•ผ ํ•จ
            temp = self.head # self.head ๊ฐ์ฒด๋ฅผ ์‚ญ์ œํ•˜๊ธฐ ์œ„ํ•ด, ์ž„์‹œ๋กœ temp์— ๋‹ด์•„์„œ ๊ฐ์ฒด๋ฅผ ์‚ญ์ œํ–ˆ์Œ
            self.head = self.head.next # ๋งŒ์•ฝ self.head ๊ฐ์ฒด๋ฅผ ์‚ญ์ œํ•˜๋ฉด, ์ด ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰์ด ์•ˆ๋˜๊ธฐ ๋•Œ๋ฌธ!
            del temp
        else:
            node = self.head
            while node.next: # ๊ฒฝ์šฐ์˜ ์ˆ˜2: self.head๊ฐ€ ์•„๋‹Œ ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•ด์•ผํ•  ๊ฒฝ์šฐ
                if node.next.data == data:
                    temp = node.next
                    node.next = node.next.next       
                    del temp                         
                    pass                             
                else:
                    node = node.next
    
    def search_node(self, data):
        node = self.head
        while node:
            if node.data == data:
                return node
            else:
                node = node.next
    
    
    • search_node(): ํŠน์ • ๊ฐ’์„ ๊ฐ€์ง„ node๋ฅผ searchํ•˜๋Š” ํ•จ์ˆ˜
    
    # test
    
    node\_mgmt = NodeMgmt(0)  
    for data in range(1, 10):  
    node\_mgmt.add(data)
    
    node = node\_mgmt.search\_node(4)  
    print (node.data)  

    ๐Ÿ“ŒDoubly Linked List

    img

    (์ถœ์ฒ˜: wikipedia, https://en.wikipedia.org/wiki/Linked_list)

    • ์ด์ค‘ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ
    • ์–‘๋ฐฉํ–ฅ ์—ฐ๊ฒฐ -> ์–‘์ชฝ์œผ๋กœ ๋…ธ๋“œ ํƒ์ƒ‰์ด ๊ฐ€๋Šฅํ•˜์—ฌ ๋” ํšจ์œจ์ ์œผ๋กœ ํƒ์ƒ‰ ๊ฐ€๋Šฅ
      (single linked list๋ผ๋ฉด head๋ถ€ํ„ฐ ํ•œ ๋ฐฉํ–ฅ์œผ๋กœ ์ฐพ์•„๊ฐ€์•ผ ํ•˜์ง€๋งŒ, ์ฐพ๊ณ ์ž ํ•˜๋Š” ๋ฐ์ดํ„ฐ์˜ ๋Œ€๋žต์ ์ธ ์œ„์น˜๋ฅผ ์•ˆ๋‹ค๋ฉด head์™€ tail ์–‘์ชฝ์—์„œ ๋ชจ๋‘ ํƒ์ƒ‰์ด ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํšจ์œจ์ !)

    1) doubly linked list ๊ตฌํ˜„

    def **init**(self, data, prev=None, next=None):  
    self.prev = prev  
    self.data = data  
    self.next = next
    
    class NodeMgmt:  
    def **init**(self, data):  
    self.head = Node(data)  
    self.tail = self.head
    
    
    def insert(self, data):
        if self.head == None:
            self.head = Node(data)
            self.tail = self.head #์ฒ˜์Œ์—๋Š” node๊ฐ€ 1๊ฐœ๋‹ˆ๊นŒ head๋ž‘ tail์ด๋ž‘ ๋˜‘๊ฐ™์Œ
        else:
            node = self.head
            while node.next:
                node = node.next
            new = Node(data) #insertํ•  ๋…ธ๋“œ๋ฅผ new๋ผ๋Š” ๋ณ€์ˆ˜์— ํ• ๋‹น
            node.next = new
            new.prev = node
            self.tail = new #insertํ•œ ๋…ธ๋“œ๊ฐ€ tail
    
    def desc(self):
        node = self.head
        while node:
            print (node.data)
            node = node.next
    
    
    • Node instance๋Š” ์ด์ „ ๋…ธ๋“œ ์ฃผ์†Œ(prev)์™€ ๋‹ค์Œ ๋…ธ๋“œ ์ฃผ์†Œ(next)๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Œ
    • insert(): ๊ฐ€์žฅ ๋์— node๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ํ•จ์ˆ˜
      node.next = new, new.prev = node๊ฐ€ ํ•ต์‹ฌ!!: ์›๋ž˜ ๋…ธ๋“œ๋Š” ๋‹ค์Œ ๋…ธ๋“œ๋Š” ์ƒˆ๋กœ์šฐ ใ„ด๋…ธ๋“œ๋ฅผ, ์ƒˆ๋กœ์šด ๋…ธ๋“œ์˜ ์ด์ „ ๋…ธ๋“œ๋Š” ์›๋ž˜ ๋…ธ๋“œ๋ฅผ
    #test  
    double\_linked\_list = NodeMgmt(0)  
    for data in range(1, 10):  
    double\_linked\_list.insert(data)  
    double\_linked\_list.desc()  

    2) ํŠน์ • ๋…ธ๋“œ search (head๋ถ€ํ„ฐ / tail๋ถ€ํ„ฐ)

    def **init**(self, data, prev=None, next=None):  
    self.prev = prev  
    self.data = data  
    self.next = next
    
    class NodeMgmt:  
    def **init**(self, data):  
    self.head = Node(data)  
    self.tail = self.head
    
    
    def insert(self, data):
        if self.head == None:
            self.head = Node(data)
        else:
            node = self.head
            while node.next:
                node = node.next
            new = Node(data)
            node.next = new
            new.prev = node
            self.tail = new
    
    def desc(self):
        node = self.head
        while node:
            print (node.data)
            node = node.next
    
    def search_from_head(self, data):
        if self.head == None:
            return False
    
        node = self.head
        while node:
            if node.data == data:
                return node
            else:
                node = node.next
        return False #์—ฌ๊ธฐ๊นŒ์ง€ ์™”๋‹ค๋Š” ๊ฑด ์ฐพ๊ณ ์žํ•˜๋Š” ๊ฐ’์„ ๋ชป์ฐพ์•˜๋‹ค๋Š” ๊ฑฐ
    
    def search_from_tail(self, data):
        if self.head == None:
            return False
    
        node = self.tail #tail์—์„œ ๋ถ€ํ„ฐ search
        while node:
            if node.data == data:
                return node
            else:
                node = node.prev
        return False
    
    
    • search_from_head(): head๋ถ€ํ„ฐ searchํ•˜๋Š” ํ•จ์ˆ˜
    • search_from_tail(): tail๋ถ€ํ„ฐ searchํ•˜๋Š” ํ•จ์ˆ˜

    3) ๋…ธ๋“œ ๋ฐ์ดํ„ฐ๊ฐ€ ํŠน์ • ์ˆซ์ž์ธ ๋…ธ๋“œ ์•ž / ๋’ค์— ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€

    class Node:  
    def **init**(self, data, prev=None, next=None):  
    self.prev = prev  
    self.data = data  
    self.next = next
    
    class NodeMgmt:  
    def **init**(self, data):  
    self.head = Node(data)  
    self.tail = self.head
    
    
    def insert(self, data):
        if self.head == None:
            self.head = Node(data)
        else:
            node = self.head
            while node.next:
                node = node.next
            new = Node(data)
            node.next = new
            new.prev = node
            self.tail = new
    
    def desc(self):
        node = self.head
        while node:
            print (node.data)
            node = node.next
    
    def insert_before(self, data, before_data):
        if self.head == None: #๋ฐฉ์–ด์ฝ”๋“œ: head node๊ฐ€ ์—†์œผ๋ฉด ๋ฐ”๋กœ node instance ๋งŒ๋“ค์–ด์ฃผ๊ธฐ
            self.head = Node(data)
            return True            
        else:
            node = self.tail
            while node.data != before_data: #๋‚ด๊ฐ€ ์ฐพ๋Š” ๊ฐ’์„ ์ฐพ์„ ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณต
                node = node.prev
                if node == None: #๋‚ด๊ฐ€ ์ฐพ๋Š” ๊ฐ’์ด ์—†์Œ
                    return False
            new = Node(data) #์ผ์น˜ํ•˜๋Š” ๊ฐ’์„ ์ฐพ์œผ๋ฉด ์‚ฝ์ž…ํ•  node๋ฅผ ์ƒˆ๋กœ์šด ๋ณ€์ˆ˜์— ํ• ๋‹น
            before_new = node.prev #์›๋ž˜ node์˜ ์ด์ „ ๋…ธ๋“œ ๋ณ€์ˆ˜๋กœ ์ •์˜
            before_new.next = new
            new.next = node
            return True
    
    def insert_after(self, data, after_data):
        if self.head == None:
            self.head = Node(data)
            return True            
        else:
            node = self.head
            while node.data != after_data:
                node = node.next
                if node == None:
                    return False
            new = Node(data)
            after_new = node.next
            new.next = after_new
            new.prev = node
            node.next = new
            if new.next == None:
                self.tail = new
            return True 
    
    
    • before_new.next = new, new.next = node

    • insert_before():

      doubly linked list - insert_before()

    • insert_after():

      doubly linked list - insert_after()

    • after_new.prev = new๋Š” ์–ด๋””๊ฐ„๊ฑธ๊นŒ
    • if new.next = None: self.tail = new๋Š” ์™œ ์“ฐ๋Š” ๊ฑธ๊นŒ
    ๋ฐ˜์‘ํ˜•

    ๋Œ“๊ธ€