앞서 알아본 링크드 리스트(Linked List)에 대해 조금 더 깊이 알아보겠다.
4. 링크드 리스트 데이터 사이에 데이터를 추가
링크드 리스트는 유지 관리에 부가적인 구현이 필요하다.
위 그림을 보면, 원래 데이터 값이 12인 노드는 데이터 값이 99인 노드를 가리키고 있다. 그런데 데이터 값이 37인 새로운 노드가 이 두 노드 사이에 들어가려고 하면, 원래 99를 가리키고 있던 12는 37을 가리켜야 하고, 추가된 노드인 37은 99를 가리켜야 한다. 부가적인 구현이 필요한 것이다.
링크드 리스트 데이터 사이에 데이터를 추가하는 코드를 만들어보면,
node = head # 노드에 헤드값 넣기
search = True
while search:
if node.data == 1: # 데이터 값이 1인 노드 바로 뒤에 새로운 노드를 추가하고 싶을 때
search = False
else:
node = node.next # 아직 못 찾았으면 다음 노드로 이동
node_next = node.next # 새로운 노드 다음 노드 위치를 node_next에 임시 저장
node.next = newNode # 새로운 노드인 newNode를 가리키도록 설정
newNode.next = node_next # 새로운 노드인 newNode가 전 노드가 가리키는 곳을 가리키도록 설정
이렇게 된다. 가령 데이터 값이 1.5인 노드를 새롭게 만들어 데이터 값이 1과 2인 노드들 사이에 추가하고 싶다면,
class Node:
def __init__(self, data, next=None):
self.data = data
self.next = next
# 첫 번째 노드 생성 및 head에 첫 번째 노드 값 담기
node1 = Node(1)
head = node1
def add(data):
node = head
while node.next:
node = node.next
node.next = Node(data)
# 첫 번째 노드에 2~9의 노드 추가하기
for index in range(2, 10):
add(index)
# 새로운 노드 newNode 생성
newNode = Node(1.5)
# 데이터 사이에 새 노드 추가
node = head
search = True
while search:
if node.data == 1:
search = False
else:
node = node.next
node_next = node.next
node.next = newNode
newNode.next = node_next
# 출력
node = head
while node.next:
print(node.data)
node = node.next
print(node.data)
이렇게 되고,
이렇게 출력된다.
5. 파이썬 객체지향 프로그래밍으로 링크드 리스트 구현하기
파이썬 객체지향을 활용해, NodeMgmt라는 클래스를 만들어 데이터 추가, 출력 등의 작업을 수월하게 할 수 있다.
코드로 구현하면,
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 middleAdd(self, prevData, addData): # 해당 링크드 리스트의 중간에 값을 추가하는 함수
node = self.head
while node:
if node.data == prevData:
break
else:
node = node.next
if node is None:
print("해당 연결 리스트에는 찾으시는 노드가 존재하지 않습니다.")
return
newNode = Node(addData)
node_next = node.next
node.next = newNode
newNode.next = node_next
def desc(self): # 전체 데이터 출력하는 함수 (description)
node = self.head
while node:
print (node.data)
node = node.next
이렇게 해서 객체를 만들고 쉽게 관리할 수 있다.
linkedlist1 = NodeMgmt(0)
for data in range(1, 10):
linkedlist1.add(data)
linkedlist1.desc()
이렇게 하면 0~9까지 생성된 노드가 출력되는 것이다.
5. 특정 노드를 삭제
링크드 리스트에서 특정 노드를 삭제하는 것은 세 가지 경우의 수가 있다.
- head 삭제
- 마지막 노드 삭제
- 중간 노드 삭제
우선, head를 삭제하는 경우 맨 앞의 노드를 삭제하고 그 다음 노드를 head로 지정하면 된다. 마지막 노드를 삭제하는 경우, 마지막 노드를 삭제하고 직전 노드가 가리키는 곳을 None(null)로 하면 된다. 중간에 있는 노드를 삭제할 때에는, 삭제하고자 하는 노드의 직전 노드가 삭제하고자 하는 노드의 바로 다음 노드를 가리키게 하고, 삭제 작업을 진행하면 된다.
특정 노드를 삭제하는 코드는 다음과 같다.
def delete(self, data):
if self.head == '': # head가 없는, 즉 링크드 리스트가 텅 비어 있는 상황
print ("해당 값을 가진 노드가 없습니다.")
return
if self.head.data == data: # head 삭제
temp = self.head # temp라는 변수에 임시로 head 값 저장
self.head = self.head.next # 원래 head의 다음 노드를 head로 지정
del temp # 저장공간 관리를 위해 지우고자 했던 헤드(temp) 삭제
else: # 마지막 노드, 중간 노드 삭제는 이 코드로 한꺼번에 관리할 수 있다.
node = self.head
while node.next:
if node.next.data == data: # 중간이든 마지막이든 지우고 싶은 값을 가진 노드가 있을 때
temp = node.next
node.next = node.next.next # 마지막 노드 삭제하는 경우, 어차피 null(None) 가리키게 하면 사라지는 것은 동일하다.
del temp
return
else:
node = node.next
특이한 점은 중간에 있는 노드를 삭제하는 것과, 마지막 노드를 삭제하는 부분은 통합 관리할 수 있다는 것이다. node.next = node.next.next을 사용함으로써, 중간 노드를 삭제한다면 실재하는 다음 노드를 직전 노드가 가리키게 하는 것이고, 마지막 노드를 삭제한다면 실재하지 않는 다음 노드인 None(null) 값을 직전 노드가 가리키게 하는 것이다.
테스트를 위해서 앞서 작성한 NodeMgmt 클래스를 이용해 링크드 리스트 객체를 생성하고 삭제 작업을 수행해보면,
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 middleAdd(self, prevData, addData):
node = self.head
while node:
if node.data == prevData:
break
else:
node = node.next
if node is None:
print("해당 연결 리스트에는 찾으시는 노드가 존재하지 않습니다.")
return
newNode = Node(addData)
node_next = node.next
node.next = newNode
newNode.next = node_next
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개 노드를 만들어 봄
linkedList1 = NodeMgmt(0)
linkedList1.desc() # 0
# head가 살아있음을 확인
print(linkedList1.head) # <__main__.Node object at 0x10310dfa0> 살아있음
# head를 지워보고 출력
linkedList1.delete(0)
print(linkedList1.head) # None
# 다시 하나의 노드 만들고, 여러 노드 추가한 다음, 노드 중에 한 개 삭제
linkedList1 = NodeMgmt(0)
for data in range(1, 10):
linkedList1.add(data)
linkedList1.delete(4)
linkedList1.desc() # 데이터 값이 4인 노드가 삭제된 것을 알 수 있다.
이렇게 4가 성공적으로 삭제된 채 출력된다.
[참고문헌]
패스트캠퍼스 개발자 취업 합격 패스 With 코딩테스트, 기술면접 초격차 패키지 Online 강의자료
'Data Structure & Algorithm' 카테고리의 다른 글
해시 테이블 (Hash Table) (0) | 2022.12.07 |
---|---|
링크드 리스트 (Linked List) (3) (0) | 2022.12.06 |
링크드 리스트 (Linked List) (0) | 2022.12.03 |
큐(Queue) & 스택(Stack) (0) | 2022.11.30 |
위상 정렬 알고리즘(Topological Sort Algorithm) - 그래프 이론 (0) | 2022.05.18 |