(Codes : https://github.com/J-Hoplin/Algorithm-with-Python/tree/master/4%20.%20Double%20Linked%20List)
1 . Doubly Linked List
앞에서 보았던 연결리스트는 단일 연결 리스트(Singly Linked List)였다. 연결리스트는 배열과 같이 물리적 메모리적 메모리가 아닌 링크라는 형식의 개념을 사용하기에 관리하기가 매우 쉬웠다. 하지만 단일 연결리스트의 한계가 있다. 바로 일방성이라는것이다. 한방향으로만 나아갈 수 있을뿐 그와 반대방향으로 링크를 시킬 수 없다는 단점이 존재한다.
앞으로 볼 이중 연결리스트는 단일 연결리스트와 달리 양방향성을 지니고 있다.
다음 사진을 보자. 임의의 링크는 자신의 다음 링크도 가리키지만 반대로 그 전의 링크도 가리키고 있는 모습을 볼 수 있다. 이중 연결리스트의 기본적인 코드 구조를 보면 다음과 같다.
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 | class Node: def __init__(self,data,link = None,before = None): self.data = data self.link = link self.before = before def p_list(): global node_a node_a = Node("A") node_b = Node("B") node_d = Node("D") node_e = Node("E") node_a.link = node_b node_b.link = node_d node_b.before = node_a node_d.link = node_e node_d.before = node_b def print_all(): global node_a node = node_a while node: print(node.data) node = node.link if __name__=="__main__": print("Double Linked List's Nodes") p_list() print_all() | cs |
필자가 작성한 코드의 구조를 그려보면 다음과 같은 구조를 띄게 된다.
결론적으로 보면 앞의 단일 연결리스트와의 다른점이라면 Before이라는 멤버가 하나 추가되어 head와 tail부분을 제외하고는 그 외 노드들이 자신의 이전 노드를 가리키는것을 볼 수 있다.
2 . Doubly Linked List - Insertersection Algorithm
단일 연결리스트에서도 봤듯이 이중 연결리스트에서도 삽입과 삭제 알고리즘이 존재한다. 우선 삽입 알고리즘 부터 살펴보자.
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | class Node: def __init__(self,data,link = None,before = None): self.data = data self.link = link self.before = before def p_list(): global node_a node_a = Node("A") node_b = Node("B") node_d = Node("D") node_e = Node("E") node_a.link = node_b node_b.link = node_d node_b.before = node_a node_d.link = node_e node_d.before = node_b def insert(data): global node_a new = Node(data) node_1 = node_a node_2 = node_a while node_2.data <= data: node_1 = node_2 node_2 = node_2.link node_2.before = new new.link = node_2 new.before = node_1 node_1.link = new def print_all(): global node_a node = node_a while node: print(node.data) node = node.link if __name__=="__main__": print("Double Linked List's Nodes") p_list() print_all() print("Double Linked List's Intersection Algorithm") insert("C") print_all() | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 | def insert(data): global node_a new = Node(data) node_1 = node_a node_2 = node_a while node_2.data <= data: node_1 = node_2 node_2 = node_2.link node_2.before = new new.link = node_2 new.before = node_1 node_1.link = new | cs |
3 . Doubly Linke List - Delete Algorithm
단일연결리스트에서 했듯이 노드 삽입 알고리즘을 보았으니 이번에는 반대로 이중 연결 리스트에서 노드를 삭제하는 알고리즘도 다루어 보자.
원리는 앞에서 본 이중 연결리스트와 동일하다. 삭제해준 노드에 대해 해당 노드의 이전노드의 link멤버는 삭제되는 노드의 link멤버로 링크를 한 노드를 삭제되는 노드의 다음 노드에 대해서, before멤버에는 삭제되는 노드의 before멤버로 링크한 노드를 링크해주면 된다. 우선 코드를 살펴보자.
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | class Node: def __init__(self,data,link = None, before = None): self.data = data self.link = link self.before = before def p_list(): global node_a global node_e node_a = Node("A") node_b = Node("B") node_d = Node("D") node_e = Node("E") node_a.link = node_b node_b.link = node_d node_b.before = node_a node_d.link = node_e node_d.before = node_b node_e.before = node_d def insert(data): global node_a new = Node(data) node_1 = node_a node_2 = node_a while node_2.data <= new.data: node_1 = node_2 node_2 = node_2.link node_1.link = new node_2.before = new new.link = node_2 new.before = node_1 def delete(dele): global node_a global node_e node_1 = node_a node_2 = node_1.link node_3 = node_2.link node_Tail = node_e if node_Tail.data == dele: node_e = node_e.before node_e.link = None del node_Tail if node_1.data == dele: node_a = node_2 del node_1 return while node_2: if node_2.data == dele: node_3 = node_2.link node_1.link = node_2.link node_3.before = node_2.before del node_2 break node_1 = node_2 node_2 = node_2.link def print_all(): global node_a node = node_a while node: print(node.data) node = node.link if __name__ == "__main__": print("Doubly Linked List Nodes") p_list() print_all() print("Doubly Linked List Intersection Nodes") insert("C") print_all() print("Doubly Linked List Delete Algorithm - 1") delete("E") print_all() print("Doubly Linked List Delete Algorithm - 2") delete("A") print_all() print("Doubly Linked List Delete Algorithm - 3") delete("C") print_all() | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | def delete(dele): global node_a global node_e node_1 = node_a node_2 = node_1.link node_3 = node_2.link node_Tail = node_e if node_Tail.data == dele: node_e = node_e.before node_e.link = None del node_Tail if node_1.data == dele: node_a = node_2 del node_1 return while node_2: if node_2.data == dele: node_3 = node_2.link node_1.link = node_2.link node_3.before = node_2.before del node_2 break node_1 = node_2 node_2 = node_2.link | cs |
우선 지금까지 스스로 코드를 작성해보았던 사람이라면 변화점중 하나가 보일것이다. 바로 Tail부분의 노드에 해당하는 node_e를 전역변수 처리를 하여 사용하였다는 것이다. 물론 node_e를 전역변수 처리할때는 delete함수에서만 전역변수 처리를 하는것이 아닌 처음 노드들을 선언하는 부분인 p_list()함수에서도 node_e에 대해 전역변수 처리를 해주어야 한다.(global node_e)
우선 우리가 앞에서 보았던 단일 연결리스트에서의 삭제 알고리즘을 살펴보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | def delete(dele): global node_a pre = node_a next = node_a.link if pre.data == dele:#첫번쨰 노드가 삭제해야할 대상인 경우 node_a = next del pre return while next:#두번째 이상의 노드를 삭제해야할 경우 if next.data == dele: pre.link = next.link del next break pre = next next = next.link | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | def delete(dele): global node_a global node_e node_1 = node_a node_2 = node_1.link node_3 = node_2.link node_Tail = node_e if node_Tail.data == dele: node_e.before.link = None del node_Tail if node_1.data == dele: node_a = node_2 del node_1 return while node_2: if node_2.data == dele: node_3 = node_2.link node_1.link = node_2.link node_3.before = node_2.before del node_2 break node_1 = node_2 node_2 = node_2.link | cs |
4 . 결론
그렇다면 결론적으로 이중 연결리스트의 장점은 무엇이 되는것일까? 단일 연결 리스트와 달리 이중 연결 리스트는 하나의 노드에는 링크가 두개가 존재한다. 그렇기 때문에 단일 연결 리스트처럼 일방적인 탐색이 아닌 양방향성으로 전체탐색이 가능하기 때문에 전반적인 탐색 시간이 단일 연결리스트에 비해 훨씬 짧아질 수 있다는 장점이 있는것이다.
'CS 지식 > Algorithm-이론 및 PS스킬 정리' 카테고리의 다른 글
파이썬 Extended Slices (0) | 2019.09.09 |
---|---|
O 표기법(Big - O Notation), 쎄타 표기법(Theta Notation), 오메가 표기법(Omega Notation) (0) | 2019.03.18 |
순서도(Flow Chart)에 대해 (0) | 2019.01.16 |
Base Algorithm with Python #2 (0) | 2019.01.13 |
Base Algorithm with Python #1 (0) | 2019.01.13 |