꼭 알아두어야 할 자료구조: 링크드 리스트(Linked List)
대표적인 데이터 구조 - 링크드 리스트(Linked List)
링크드 리스트는 스택, 큐와 다르게 복잡함. 구조 자체는 간단하지만 이 구조를 구현을 할 때 복잡함.
1. 링크드 리스트(Linked List)구조
- 연결 리스트라고도 함
- 배열은 순차적으로 연결된 공간에 데이터를 나열하는 데이터 구조
- 링크드 리스트는 떨어진 곳에 존재하는 데이터를 화살표로 연결해서 관리하는 데이터 구조
- 본래 C언어에서는 주요한 데이터 구조이지만, 파이썬은 리스트 타입이 링크드 리스트의 기능을 모두 지원!
링크드 리스트는 배열과 달리 특정한 데이터를 저장을 할 때 해당 데이터를 저장하는 공간과 함께 뒤에 다음 데이터가 저장되어있는 주소공간을 하나의 데이터로 관리함.
👉 즉, 배열은 데이터만 저장, 링크드 리스트는 데이터+ (다음데이터)주소 저장
1-1. 링크드 리스트 기본 구조와 용어
- 노드(Node): 데이터 저장 단위(데이터 값, 포인터)로 구성
- 포인터(Pointer): 각 노드 안에서, 다음이나 이전의 노드와의 연결 정보를 가지고 있는 공간
2. 간단한 링크드 리스트 예
링크드 리스트를 파이썬으로 구현하려면 객체지향 문법을 알고 있어야 함
[1] Node 구현
- 보통 파이썬에서 링크드 리스트 구현 시, 파이썬 클래스를 활용함
- 파이썬 객체지향 문법 이해 필요
- 참고 : https://www.fun-coding.org/PL&OOP1-3.html
예시 1)
class Node
def _init_(self, data):
self.data = data
self.next = None
예시 2)
class Node
def _init_(self, data, next=Node):
self.data = data
self.next = next
[2] Node와 Node 연결하기(포인터 활용)
node1 = Node(1)
node2 = Node(2)
node1.next = node2
head = node1
# 가장 먼저 있는 node를 head로 만듬
[3] 링크드 리스트로 데이터 추가하기
class Node:
def _init_(self, data, next=Node):
self.data = data
self.next = next
def add(data):
node = head
# head라는 변수에다가 맨 앞에 있는 node의 값을 저장하기로 위에서 약속함
# 그래서 add라는 함수에는 항상 그 head의 값을 가지고 온다
# 링크드 리스트에서 데이터가 저장될 때에는 맨 끝에 저장되므로
# 맨끝에 연결되어있는 노드를 찾아가기 위해서 node.next가 있는지 확인
while node.next:
# node.next가 있다는 건 다음 노드를 가리키는 주소가 있다는 것
node = node.next
node.next = Node(data)
# --- test ---
# 맨 처음 Linked List의 노드를 만들어놓고,
node1 = Node(1)
# 그 노드를 head 즉, 맨 앞에 변수에 저장을 함
head = node1
# 2부터 9까지 총 10개 마지막 숫자는 -1
for index in range(2, 10):
# 2부터 9까지 add함수 호출
add(index)
[4] 링크드 리스트 데이터 출력하기(검색하기)
node = head
while node.next:
print(node.data)
node = node.next
print(node.data)
# --- result ---
# 1 -> node1 = Node(1)이였기에 1출력
# 2 -> 2~9까지는 add(index)를 통해 연결
# 3
# 4
# 5
# 6
# 7
# 8
# 9
3. 링크드 리스트의 장단점(전통적인 C언어에서의 배열과 링크드 리스트)
✦ 장점
- 미리 데이터 공간을 할당하지 않아도 됨
- 배열은 미리 공간을 할당해야함
✦ 단점
- 연결을 위한 별도 데이터 공간이 필요하므로, 저장공간 효율이 높지 않음
- 연결 정보를 찾는 시간이 필요하므로 접근 속도가 느림
- 중간 데이터 삭제 시, 앞 뒤 데이터의 연결을 재구성하는 부가적인 작업 필요
4. 링크드 리스트의 복잡한 기능 1 (링크드 리스트 데이터 사이에 데이터를 추가)
- 링크드 리스트는 유지 관리에 부가적인 구현이 필요함
node = head
while node.next:
print(node.data)
node = node.next
print(node.data)
# --- result ---
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
node3 = Node(1.5)
# 1과 2사이에 넣기
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
# --------- 출력---------
node = head
while node.next:
print(node.data)
node = node.next
print(node.data)
# --- result ---
# 1
# 1.5
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
5. 파이썬 객체지향 프로그래밍으로 링크드 리스트 구현하기
# 각각의 노드 생성 클래스
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.data == ":
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
구현된 리스트를 기반으로 링크드 리스트 코드 만들어보기
linkedlist1 = NodeMgmt(0)
linkedlist1.desc()
# 0
for data in range(1,10):
# 1부터 9(10-1)까지
linkedlist1.add(data)
linkedlist1.desc()
# 0
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
링크드 리스트의 복잡한 기능2(특정 노드를 삭제)
- head 삭제
- 마지막 노드 삭제
- 중간 노드 삭제
- 삭제는 delete함수
# 각각의 노드 생성 클래스
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.data == ":
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
# 1. head 삭제
if self.head.data == data:
temp = self.head
self.head = self.head.next
del temp
# 2. 마지막 노드 삭제 & 3. 중간 노드 삭제
else:
node = self.head
while node.next:
if node.next.data == data:
temp = node.next
node.next = node.next.next
del temp
테스트를 위해 1개 노드 만들어 보기
linkedlist1 = NodeMgmt(0)
linkedlist.desc()
# -> 0
head가 살아있는지 확인
linkedlist1.head
# -> <__main__.Node at 0x1099fc6a0>
head를 삭제(위에서 언급한 경우의 수 첫번째)
linkedlist1.delete(0)
코드 실행 시 값이 나오지 않는다면 head가 정상적으로 삭제됨
linkedlist1.head
# ->
다시 하나의 노드를 만들어 보기
linkedlist1 = NodeMgmt(0)
linkedlist.desc()
# -> 0
여러 노드를 더 추가
for data in range(1,10):
linkedlist1.add(data)
linkedlist1.desc()
# 0
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
노드 중 한개를 삭제함(중간 노드 삭제)
linkedlist1.delete(4)
특정 노드 삭제 결과 확인
linkedlist1.desc()
# 0
# 1
# 2
# 3
# 5
# 6
# 7
# 8
# 9
7. 다양한 링크드 리스트 구조
- 더블 링크드 리스트(Doubly linked list)기본 구조
- 이중 연결 리스트라고도 함
- 장점) 양방향으로 연결되어 있어서 노드 탐색이 양쪽으로 모두 가능
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
# ----- 실행 ------
double_linked_list = NodeMgmt(0)
for data in range(1,10):
double_linked_list.insert(data)
double_linked_list.desc()
# 0
# 1
# 2
# 3
# 5
# 6
# 7
# 8
# 9
8. 문제 풀기
연습 3 : 위 코드에서 노드 데이터가 특정 숫자인 노드 앞에 데이터를 추가하는 함수를 만들고, 테스트해보기
☑️ 더블 링크드 리스트의 tail에서부터 뒤로 이동하며, 특정 숫자인 노드를 찾는 방식으로 함수를 구현하기
☑️ 테스트: 임의로 0~9 데이터를 링크드 리스트에 넣어보고, 데이터 값이 2인 노드 앞에 1.5 데이터 값을 가진 노드를 추가해보기
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
# 검색 코드 만들기
# 앞에서 검색
def search_from_head(self, data):
if self.node = 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.node = 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
return True
# ----- 테스트 ------
double_linked_list = NodeMgmt(0)
for data in range(1,10):
double_linked_list.insert(data)
double_linked_list.desc()
# 0
# 1
# 2
# 3
# 5
# 6
# 7
# 8
# 9
node_3 = double_linked_list.search_from_head(3)
node_3.data
# 3
double_linked_list.insert_before(1.5, 2)
double_linked_list.desc()
# 0
# 1
# 1.5
# 2
# 3
# 5
# 6
# 7
# 8
# 9
Author And Source
이 문제에 관하여(꼭 알아두어야 할 자료구조: 링크드 리스트(Linked List)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@ye-ji/꼭-알아두어야-할-자료구조-링크드-리스트Linked-List저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)