기본적으로 “연결 리스트”는 요소가 노드에 저장되는 선형 데이터 구조입니다. 배열과 달리 연결된 목록에는 연속적인 메모리 공간이 필요하지 않습니다. 대신, 각 요소(노드)에는 데이터와 시퀀스의 다음 노드에 대한 참조(링크 또는 포인터)가 포함됩니다.
노드
연결 리스트는 “데이터 + 포인터”를 포함하는 컨테이너인 노드로 구성되어 있습니다.
데이터: 정수, 문자 또는 기타 데이터 유형과 같이 저장하려는 실제 정보입니다.
다음 포인터: 시퀀스의 다음 노드를 가리키는 링크 또는 포인터입니다. 마지막 노드에서 이 포인터는 일반적으로 목록의 끝을 나타내는 NULL을 가리킵니다.
연결 리스트의 장점
동적 크기
연결 리스트는 런타임 중에 실제 데이터 크기에 맞춰 동적으로 늘어나거나 줄어들 수 있습니다.
효율적인 삽입 및 삭제
연결 리스트에서 요소를 추가하거나 제거하는 것은 배열과 비교할 때 효율적입니다.
파이썬에서 연결 리스트
Python에는 목록, 튜플, 집합 및 사전과 같은 내장 데이터 구조가 있는 것과 같은 방식의 내장 연결 리스트 데이터 구조는 없습니다…!
Python에 내장된 ‘리스트’은 연결 리스트가 아닌 동적 배열입니다.
유사한 기능을 제공하지만 다르게 구현되어 인덱스 및 동적 크기 조정을 통해 요소에 대한 지속적인 액세스를 제공합니다.
파이썬에서 연결 리스트 구현
파이썬에서 직접 linked list를 구현하려면 아래와 같이 구현할 수 있습니다.
class Node:
# 노드 클래스 정의: 연결 리스트의 각 요소(노드)를 나타냄
def __init__(self, data):
self.data = data # 노드가 저장할 데이터
self.next = None # 다음 노드를 가리키는 포인터, 초기값은 None
class LinkedList:
# 연결 리스트 클래스 정의
def __init__(self):
self.head = None # 리스트의 시작 노드를 가리키는 head, 초기값은 None
def print_list(self):
# 리스트의 모든 요소를 출력하는 메소드
current = self.head # 현재 위치를 리스트의 시작으로 설정
while current:
# 리스트의 끝에 도달할 때까지 반복
print(current.data, end=" -> ") # 현재 노드의 데이터 출력
current = current.next # 다음 노드로 이동
print("None") # 리스트의 끝 표시
def clear(self):
# 리스트의 모든 요소를 제거하는 메소드
self.head = None # head를 None으로 설정하여 리스트 초기화
def insert_at_index(self, index, data):
# 특정 인덱스에 새로운 노드를 삽입하는 메소드
new_node = Node(data) # 새로운 노드 생성
if index == 0:
# 리스트의 시작 부분에 삽입하는 경우
new_node.next = self.head # 새 노드의 다음 노드를 현재 head로 설정
self.head = new_node # 새 노드를 새로운 head로 설정
return
current = self.head
for i in range(index - 1):
# 삽입할 위치의 바로 이전 노드까지 이동
if current is None:
raise IndexError("Index out of bounds") # 인덱스 범위 초과 예외 처리
current = current.next
new_node.next = current.next # 새 노드의 다음 노드를 현재 노드의 다음 노드로 설정
current.next = new_node # 현재 노드의 다음 노드를 새 노드로 설정
def append(self, data):
# 리스트의 끝에 새로운 노드를 추가하는 메소드
new_node = Node(data) # 새로운 노드 생성
if self.head is None:
# 리스트가 비어있는 경우
self.head = new_node # 새 노드를 head로 설정
return
last = self.head
while last.next:
# 리스트의 마지막 노드를 찾을 때까지 이동
last = last.next
last.next = new_node # 마지막 노드의 다음 노드를 새 노드로 설정
def delete_at_index(self, index):
# 특정 인덱스의 노드를 삭제하는 메소드
if self.head is None:
# 리스트가 비어있는 경우
return
if index == 0:
# 첫 번째 노드를 삭제하는 경우
self.head = self.head.next # head를 다음 노드로 업데이트
return
current = self.head
for i in range(index - 1):
# 삭제할 노드의 바로 이전 노드까지 이동
if current.next is None:
raise IndexError("Index out of bounds") # 인덱스 범위 초과 예외 처리
current = current.next
current.next = current.next.next if current.next else None # 삭제할 노드를 연결 리스트에서 제거
def pop(self):
# 리스트의 마지막 요소를 삭제하는 메소드
if self.head is None:
# 리스트가 비어있는 경우
return
if self.head.next is None:
# 리스트에 요소가 하나만 있는 경우
self.head = None
return
current = self.head
while current.next.next:
# 마지막 요소의 바로 이전 요소까지 이동
current = current.next
current.next = None # 마지막 요소를 제거
def get(self, index):
# 특정 인덱스의 노드의 데이터를 반환하는 메소드
current = self.head
for i in range(index):
# 지정된 인덱스까지 이동
if current is None:
raise IndexError("Index out of bounds") # 인덱스 범위 초과 예외 처리
current = current.next
return current.data if current else None # 인덱스의 노드 데이터 반환
# 사용 예시
ll = LinkedList()
ll.append(1)
ll.append(2)
ll.insert_at_index(1, 3)
ll.print_list() # 1 -> 3 -> 2 -> None
print("Element at index 1:", ll.get(1)) # 출력: 3
ll.delete_at_index(1)
ll.print_list() # 출력: 1 -> 2 -> None
ll.pop()
ll.print_list() # 출력: 1 -> None
ll.clear()
ll.print_list() # 출력: None
배열 vs 연결 리스트
측면 | 정적 배열 | 동적 배열 | 연결 리스트 |
---|---|---|---|
크기 조절 | 크기가 고정됨. | 크기를 동적으로 조절할 수 있음. | 크기를 동적으로 조절할 수 있음. |
메모리 사용량 | 크기가 고정되어 있어 예측 가능. | 크기에 따라 메모리 할당이 동적으로 조절됨. | 노드마다 추가적인 포인터로 인한 메모리 오버헤드. |
요소 추가 및 삭제 | 비효율적. 삽입 또는 삭제 시 다른 요소를 이동해야 함. | 동적으로 크기를 조절하므로 삽입 및 삭제가 효율적. | 노드를 추가하거나 삭제할 때 노드만 조작하면 되므로 효율적. |
접근 시간 | 인덱스를 통한 직접적인 접근이 가능. | 인덱스를 통한 접근이 가능하며, 동적 크기 조절에 따른 성능 저하 가능. | 다음 노드를 찾아가야 하므로 일반적으로 접근 속도가 느림. |
메모리 단편화 | 단편화 없음. | 메모리 할당 및 해제로 인한 단편화 가능. | 노드 추가 및 삭제로 인한 단편화 가능. |
구현의 복잡성 | 간단하고 직관적. | 동적 크기 조절 및 메모리 관리로 인한 구현이 복잡. | 노드 간의 연결 및 메모리 할당 관리로 인한 구현이 복잡. |
용도 | 크기가 고정되어 있고 빠른 접근이 필요한 경우. | 크기의 동적 변경이 필요하며 삽입 및 삭제가 빈번한 경우. | 크기가 동적으로 변하며, 삽입 및 삭제가 자주 발생하는 경우. |
참고하면 좋은 글
정적 배열, 동적 배열 : 초보자도 파이썬으로 이해하는 자료구조
배열에는 배열의 크기를 미리 정하는지 여부에 따라 정적 배열과 동적 배열로 나뉩니다. 정적 배열은 각 상자에 고유 번호가 붙은 일련의 상자로 생각하면 됩니다… Read more
Data Structure : Introduction to Linked List – Codeforwin
Linked list is a ADT(Abstract Data Type) consisting of group of nodes in a connected way forming a sequence. A linked list is used to maintain dynamic series of data. Each node of a linked list basically contains only two parts data part and the address part. Data part of the node hold the actual … Read more