링크드 리스트 (Linked List)
1. Linked List 구조
배열의 데이터와 그 다음 배열요소의 주소(포인터)를 저장하는 것.(노드)
링크드 리스트의 장점과 단점
장점 | 단점 |
---|
자료의 삽입과 삭제가 용이 | 포인터의 사용으로 인해 저장 공간의 낭비가 있음 |
리스트 내에서 자료의 이동이 필요하지 않다. | 알고리즘이 복잡하다. |
사용 후 기억장소의 재사용이 가능 | 특정 자료의 탐색시간이 많이 소요됨 |
연속적인 기억 장소의 할당이 필요하지 않다. | |
ArrayList 와 LinkedList 의 비교 성능은 아래 표와 같다.
| ARRAYLIST | LINKEDLIST |
---|
Indexing | O(1) | O(n) |
Insert/delete at beginning | O(n) | O(1) |
Insert/delete at end | O(1) | O(n) - last element is unknown |
| | O(1) - last element is known |
Insert/delete in middle | O(n) | O(1) |
Wasted spave (average) | O(n) | O(n) |
2. 간단한 링크드 리스트 예
Node 구현
1
2
3
4
5
6
7
| class Node:
# __init__ 은 클래스 내장 메소드
# 이 클래스로 객체를 만들때마다 노드가 생성됨(data + pointer)
# self parameter 는 __init__ 메소드에서 사용되지 않는다.
def __init__(self, data):
self.data = data
self.next = None
|
다음과 같이 좀더 객체 지향적으로 바꿀 수 있다.
1
2
3
4
| class Node:
def __init__(self, data, next=None):
self.data = data
self.next = next
|
Node 와 Node 연결하기 (포인터 활용)
1
2
3
4
| node1 = Node(1)
node2 = Node(2)
node1.next = node2
head = node1 # 어떤 리스트인지 알아야 하기 때문에, head 를 정해줘야 함.
|
링크드 리스트로 데이터 추가하기 (어렵게 느껴짐 처음봄)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| class Node:
def __init__(self, data, next = None): # default value가 none 일뿐, 값을 지정할 수 있다.
self.data = data
self.next = next
def add(data): # data 를 추가하는 함수
node = head # 링크드 리스트의 위치를 알려주는 head 를 node 에 할당
while node.next: # node.next 가 null 인경우를 찾을때까지 while 문을 돈다.
node = node.next # 링크드 리스트의 다음노드가 node 에 할당되고, node.next 가 null인경우를 찾을 때 까지 반복됨.
node.next = Node(data) # null 인놈을 찾아서, 새로운 data 를 갖고있는 노드의 주소를 기존 node 에 추가함.
node1 = Node(1)
head = node1
for index in range(2,10):
add(index)
# 2~ 9까지 각 숫자를 데이터로 갖는 노드들의 집합(링크드리스트) 완성.
|
링크드 리스트 데이터 출력하기
1
2
3
4
5
6
7
| node = head
while node.next:
print(node.data)
node = node.next
print (node.data)
# 1 , 2 , 3,4,5,6,7,8,9
|
3. 링크드 리스트의 장단점 ( 전통적인 C언어에서의 배열과 링크드 리스트)
장점
단점
- 연결을 위한 별도 데이터 공간이 필요, 저장공간 효율이 높지 않음
- 연결 정보를 찾는 시간이 필요하므로 접근 속도가 느림
- 중간 데이터 삭제 시 , 앞뒤 데이터의 연결을 재구성해야 하는 부가적인 작업 필요
4. 링크드 리스트의 복잡한 기능1 (링크드 리스트 데이터 사이에 데이터를 추가)
- 링크드 리스트는 유지 관리에 부가적인 구현이 필요. (출처: wikipedia, https://en.wikipedia.org/wiki/Linked_list)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| class Node:
def __init__(self, data, next=None) : # 파이썬 class 함수에서는 param 이 있든 없든 self 인자를 첫번 째로 넣어줘야 한다.
self.data = data
self.next = next
def add(data):
node = head
while.node.next:
node = node.next
node.next = Node(data)
node1 = Node(1)
head = node1
for index in range(2,10):
add(index)
|
1
2
3
4
5
| node = head
while node.next:
print(node.data)
node = node.next
# 1,2,3,4,5,6,7,8,9
|
1
2
3
4
5
6
7
8
9
10
11
| node = head
search = True
while search:
if node.data == 1:
search = False
else:
node = node.next
node_next = node.next
node.next = node3
node3.next = node_next
|
1
2
3
4
5
6
7
| # node 링크드 리스트의 데이터를 print 하는 함수
node = head
while node.next:
print(node.data)
node = node.next
print (node.data)
# 1, 1.5 ,2,3,4,5,6,7,8,9
|
5. 파이썬 객체지향 프로그래밍으로 링크드 리스트 구현하기
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
| 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:
print(node.data)
node = node.next
node.next = Node(data)
# 각 노드데이터를 print 하는 description 함수
def desc(self):
node = self.head
while node:
print (node.data)
node = node.next
|
1
2
3
| linkedlist1 = NodeMgmt(0)
linkedlist1.desc()
# 0
|
1
2
3
4
| for data in range(1,10):
linkedlist1.add(data)
linkedlist1.desc()
# 0,1,2,3,4,5,6,7,8,9
|
6. 링크드 리스트의 복잡한 기능2 (특정 노드를 삭제)
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
| 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 == '':
print("해당 값을 가진 노드가 없습니다.")
return
if self.head.data == data:
temp = self.head
self.head = self.head.next
del temp
else:
node = self.head
while node.next:
if node.next.data == data:
temp = node.next
node.next = node.next.next
del temp
return
else:
node = node.next
|
테스트를 위해 1개 노드를 만들어 봄
1
2
3
| linkedlist1 = NodeMgmt(0)
linkedlist1.desc()
# 0
|
head 가 살아있음을 확인
1
2
| linkedlist1.head
# <__main__.Node at 0x1099fc6a0> 살아 있는 것
|
head 를 지워봄
다음 코드 실행 시 아무것도 나오지 않는다는 것은 linkedlist1.head 가 정상적으로 삭제되었음을 의미
1
2
3
| linkedlist1.head
# NameError : name 'linkedlist1' is not defined
|
다시 하나의 노드를 만들어봄
1
2
3
4
| linkedlist1 = NodeMgmt(0)
linkedlist1.desc()
# 0
|
이번엔 여러 노드를 더 추가해봄
1
2
3
4
5
| for data in range(1, 10):
linkedlist1.add(data)
linkedlist1.desc()
# 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
노드 중에 한개를 삭제함 (위에서 언급한 경우의수2)
특정 노드가 삭제되었음을 알 수 있음
1
2
3
| linkedlist1.desc()
# 0, 1, 2, 3, 5, 6, 7, 8, 9
|
하나 더 삭제해 보자.
1
2
3
4
| linkedlist1.delete(9)
linkedlist1.desc()
# 0, 1, 2, 3, 5, 6, 7, 8
|
연습1 : 위 코드에서 노드 데이터가 특정 숫자인 노드를 찾는 함수를 만들고 테스트해보기
테스트: 임의로 1~9까지 데이터를 링크드 리스트에 넣어보고, 데이터 값이 4인 노드의 데이터 값 출력해보기.
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
| class Node:
def __init__(self, data):
self.data = data
self.next = None
class NodeMgmgt:
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:
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
|
1
2
3
4
5
6
7
| # 테스트
node_mgmt = NodeMgmt(0)
for data in range(1, 10):
node_mgmt.add(data)
node = node_mgmt.search_node(4)
print (node.data)
|
7. 다양한 링크드 리스트 구조
- 더블 링크드 리스트(Doubly linked list) 기본 구조
- 이중 연결 리스트라고도 함
- 장점: 양방향으로 연결되어 있어서 노드 탐색이 양쪽으로 모두 가능 (출처: wikipedia, https://en.wikipedia.org/wiki/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, 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
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
|
1
2
3
4
5
6
| double_linked_list = NodeMgmt(0)
for data in range(1, 10):
double_linked_list.insert(data)
double_linked_list.desc()
# 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
연습 2 : 위 코드에서 노드 데이터가 특정 숫자인 노드 앞에 데이터를 추가하는 함수를 만들고, 테스트 해보기
더블 링크드 리스트의 tail 에서부터 뒤로 이동하며, 특정 숫자인 노드를 찾는 방식으로 함수 구현하기 테스트: 임의로 0 ~ 9까지 데이터를 링크드 리스트에 넣어보고, 데이터 값이 2인 노드 앞에 1.5 데이터 값을 가진 노드를 추가해보기
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
| class Node:
def __init__(self, data, prev = None, next = None):
slef.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
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
while node:
if node.data == data:
return node
else:
node = node.prev
return False
def insert_before(self, data, before_data):
if self.head == None:
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)
before_new = node.prev
before new.next = new
new.prev = before_new
new.next = node
node.prev = new
return True
|
1
2
3
4
5
6
| double_linked_list = NodeMgmt(0)
for data in range(1, 10):
double_linked_list.insert(data)
double_linked_list.desc()
# 0,1,2,3,4,5,6,7,8,9
|
1
2
3
4
| node_3 = double_linked_list.search_from_tail(3)
node_3.data
# 3
|
1
2
3
4
| double_linked_list.insert_before(1.5, 2)
double_linked_list.desc()
# 0, 1, 1.5, 2, 3, 4, 5, 6, 7, 8, 9
|
1
2
3
4
| node_3 = double_linked_list.search_from_tail(1.5)
node_3.data
# 1.5
|
연습 3 : 위 코드에서 노드 데이터가 특정 숫자인 노드 뒤에 데이터를 추가하는 함수 만들고, 테스트하기
더블 링크드 리스트의 head 에서부터 다음으로 이동하며, 특정 숫자인 노드를 찾는 방식으로 함수를 구현하기 임의로 0 ~ 9 까지 데이터를 링크드 리스트에 넣어보고, 데이터값이 1인 노드 다음에 1.7 데이터 값을 가진 노드를 추가해보기
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
| 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_before(self, data, beofre_data):
if self.head == None:
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)
before_new = node.prev
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.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
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| node_mgmt = NodeMgmt(0)
for data in range(1, 10):
node_mgmt.insert(data)
node_mgmt.desc()
# 1,2,3,4,5,6,7,8,9
node_mgmt.insert_after(1.5, 1)
node_mgmt.desc()
# 1, 1.5, 2,3,4,5,6,7,8,9
|
출처
https://www.nextree.co.kr/p6506/