https://koreanraichu.tistory.com/312
Python으로 연결 리스트 구현하기
https://koreanraichu.tistory.com/311 연결 리스트 JS는 토이프로젝트 해야 하는데 뭐 또 생각나면 만들겠음... 솔직히 프론트엔드가 쓸 일은 없겠지만 알아서 나쁠거 없잖아요? 아무튼. 배열은 만들 때 메
koreanraichu.tistory.com
부트캠프 들으면서 얘를 구현해 볼 기회가 또 생겼음. 전에 했던것보다 훨배 복잡한거라 들고 왔습니다. 아마 다음에 올리는건 트리랑 그래프정도?
# 노드
class Node:
# 뾰로롱
def __init__ (self, _value):
self.value = _value
self.nextnode = None
# 다음 노드의 주소값을 설정
def setnext(self,_nextnode):
self.nextnode = _nextnode
얘는 노드 만드는 애다. 연결 리스트는 노드 하나 안에 노드가 담을 정보와 다음 노드 주소(다음 노드 여기 있음)가 들어있다.
class Linkedlist:
# 머리
def __init__ (self):
self.headnode = Node(0)
self.datacount = 0 # 연결 리스트의 길이
# 데이터 넣기
def add_node (self, _value):
# 새로운 노드 생성
new_node = Node(_value)
pointernode = self.headnode
# 마지막 노드가 어디 있나
while True:
# 찾았으면 뒤에 추가해라
if pointernode.nextnode == None:
break
else:
pointernode = pointernode.nextnode
pointernode.nextnode = new_node
# 카운터 추가
self.datacount += 1
# 내놔
def where_node (self, _position):
target_index = _position - 1
# 잘못 입력했다면
if _position < 1:
print('순서값은 1보다 같거나 큰 정수입니다. ')
return
elif _position > self.datacount:
print(f'범위는 1부터 {self.datacount}까지입니다. ')
return
# 여기가 본론임...
else:
# 헤드에서 시작해서 우리가 찾는 포지션 값까지 가야 한다.
pointernode = self.headnode
# 전체 이동 횟수를 계산하고
move_cnt = target_index + 1
# 그만큼 반복 아...
for i in range(move_cnt):
# 가야돼 아...
pointernode = pointernode.nextnode
# 드디어 나옴
return pointernode.value
# 여기다 넣어줘
def insert_node (self, _position, _value):
# 수정할 포지션
target_index = _position - 1 # 3 입력하면 3번째 수정하려면 필요함
# prev: 하나 덜 감/curr: 정직하게 ㄱㄱ
# 2번때에 노드 끼워넣는거면 1, 2까지 갑니다.
if _position < 1:
print('순서값은 1보다 같거나 큰 정수입니다. ')
return
elif _position > self.datacount:
# 리스트 길이를 벗어나면... 아니 근데 그러면 걍 끼워넣기 하면 안됨?
print(f'범위는 1부터 {self.datacount}까지입니다. ')
return
else:
# 끼워넣을 노드
new_node = Node(_value)
# 노드를 끼워넣을 포지션과 그 앞 노드에 대한 정보가 필요함
# 그래서 두개지요
prev_pointer = self.headnode
curr_pointer = self.headnode.nextnode
move_cnt = target_index
for i in range(move_cnt):
prev_pointer = prev_pointer.nextnode
curr_pointer = curr_pointer.nextnode
# 노드 끼우는 순서: prev-노드-curr
prev_pointer.nextnode = new_node
new_node.nextnode = curr_pointer
# 아 맞다 카운터
self.datacount += 1
return
# 바꿔줘
def change_node (self, _position, _value):
# 3을 입력하면 정직하게 2번째 인덱스를 바꾸기 위해서는 변환 절차가 필요하다.
target_index = _position - 1
if _position < 1:
print('순서값은 1보다 같거나 큰 정수입니다. ')
return
elif _position > self.datacount:
# 리스트 길이를 벗어나면... 아니 근데 그러면 걍 끼워넣기 하면 안됨?
print(f'범위는 1부터 {self.datacount}까지입니다. ')
return
else:
# 원리는 간단하다. 찾아라, 그리고 바꿔라.
move_cnt = target_index + 1
pointernode = self.headnode
for i in range(move_cnt):
pointernode = pointernode.nextnode
# 도착했으면 수정을 해야됩니다.
pointernode.value = _value
# 빼줘
def delete_node (self, _position):
# 3을 입력하면 정직하게 2번째 인덱스를 지우기 위해서는 변환 절차가 필요하다.
target_index = _position - 1
if _position < 1:
print('순서값은 1보다 같거나 큰 정수입니다. ')
return
elif _position > self.datacount:
# 리스트 길이를 벗어나면... 아니 근데 그러면 걍 끼워넣기 하면 안됨?
print(f'범위는 1부터 {self.datacount}까지입니다. ')
return
else:
# 그 포인터 앞에 있는 노드의 연결을 다음다음노드로 하면 된다. 연결만 끊으면 끝.
move_cnt = target_index
pointernode = self.headnode
for i in range(move_cnt):
pointernode = pointernode.nextnode
pointernode.nextnode = pointernode.nextnode.nextnode
# 아 맞다 카운터
self.datacount -= 1
return
# 잘 된겨?
def node_show (self):
# 헤드노드의 다음 노드가 없으면
if self.headnode.nextnode == None:
print('이 리스트는 텅 비었습니다. ')
return
pointernode = self.headnode
while True:
# 다음으로 렛츄고
pointernode = pointernode.nextnode
print(pointernode.value)
# 없으면 시마이
if pointernode.nextnode == None:
break
return
본론은 여기 있다. 이게 다 머여!! 하나씩 알아봅시다... 이게 이래뵈도 OOP 서타일인데, 그거는 또 나중에 기회가 되면 얘기해주겠음.
머리 머리 머리
# 머리
def __init__ (self):
self.headnode = Node(0)
self.datacount = 0 # 연결 리스트의 길이
연결 리스트는 머리와 꼬리가 있다. 머리는 말 그대로 연결 리스트의 시발점이고, 앞 노드가 없다. 반대로 꼬리는 다음 노드의 주소를 갖고 있지 않고, 연결 리스트 맨 뒤에 있다.
노드 추가
# 데이터 넣기
def add_node (self, _value):
# 새로운 노드 생성
new_node = Node(_value)
pointernode = self.headnode
# 마지막 노드가 어디 있나
while True:
# 찾았으면 뒤에 추가해라
if pointernode.nextnode == None:
break
else:
pointernode = pointernode.nextnode
pointernode.nextnode = new_node
# 카운터 추가
self.datacount += 1
리스트를 만들고 거기에 노드를 추가하려면 쟤가 필요하다. 기본적으로 맨 앞... 그니까 헤드를 만들 때를 빼면 연결 리스트에 새 노드를 추가하는 과정은 1) 새 노드를 만들고 2) 새 노드와의 연결점을 맨 뒤 노드에 추가한다 이다. 얘는 그래도 좀 심플한 편이여...
특정 번호로 노드 찾기
# 내놔
def where_node (self, _position):
target_index = _position - 1
# 잘못 입력했다면
if _position < 1:
print('순서값은 1보다 같거나 큰 정수입니다. ')
return
elif _position > self.datacount:
print(f'범위는 1부터 {self.datacount}까지입니다. ')
return
# 여기가 본론임...
else:
# 헤드에서 시작해서 우리가 찾는 포지션 값까지 가야 한다.
pointernode = self.headnode
# 전체 이동 횟수를 계산하고
move_cnt = target_index + 1
# 그만큼 반복 아...
for i in range(move_cnt):
# 가야돼 아...
pointernode = pointernode.nextnode
# 드디어 나옴
return pointernode.value
리스트로 치자면 인덱싱이다. 이 코드에는 약간의 변형을 했는데, 원래는 연결 리스트의 3번째 노드에 들어있는 값을 보고 싶으면 2를 입력해야 하는데(콤퓨타는 0부터 셈) 이게 너무 직관적이지 않은겨... 헷갈려요 사람... 그래서 3 입력하면 3번째 노드의 값이 나오게끔 변형했다.
그럼 특정 번호로 노드를 찾는 과정에 대해 알아보자… 뭐 사실 알아보고 자시고 할 것도 없이 찾을 순번 될 때까지 반복문 도는 게 다긴 한데… 왜 이렇게까지 해야 하나요? 연결 리스트는 원래 그렇습니다. 배열은 일렬로 줄줄이 소세지라서 걍 첫 번째 값 찾고 하나 둘 셋 하면 되지만 쟤는 얘는 여기있고 얘 따라가면 여기있고 걔 따라가면 또 여기있고…가 꼬리까지 반복이다. 연결 리스트는 삭제, 수정, 추가가 상대적으로 용이한 대신 탐색이 좀 오래 걸리는데, 특히나 찾을 노드가 뒤에 있을수록 더 오래 걸린다. 3번 노드면 0->1->2->3만 가면 되지만 7번 노드면 0->1->2->3->4->5->6->7이거든.
사이에 끼워넣기
# 여기다 넣어줘
def insert_node (self, _position, _value):
# 수정할 포지션
target_index = _position - 1 # 3 입력하면 3번째 수정하려면 필요함
# prev: 하나 덜 감/curr: 정직하게 ㄱㄱ
# 2번때에 노드 끼워넣는거면 1, 2까지 갑니다.
if _position < 1:
print('순서값은 1보다 같거나 큰 정수입니다. ')
return
elif _position > self.datacount:
# 리스트 길이를 벗어나면... 아니 근데 그러면 걍 끼워넣기 하면 안됨?
print(f'범위는 1부터 {self.datacount}까지입니다. ')
return
else:
# 끼워넣을 노드
new_node = Node(_value)
# 노드를 끼워넣을 포지션과 그 앞 노드에 대한 정보가 필요함
# 그래서 두개지요
prev_pointer = self.headnode
curr_pointer = self.headnode.nextnode
move_cnt = target_index
for i in range(move_cnt):
prev_pointer = prev_pointer.nextnode
curr_pointer = curr_pointer.nextnode
# 노드 끼우는 순서: prev-노드-curr
prev_pointer.nextnode = new_node
new_node.nextnode = curr_pointer
# 아 맞다 카운터
self.datacount += 1
return
사이에 끼워넣는다는 건 1) 얘랑 2) 쟤(얘 앞에 있음) 사이에 노드를 새로 끼워넣는다는 얘기인데, 이건 어떻게 하느냐... 원리 자체는 간단하다. 앞의 노드 포인터를 추가할 애를 가리키게 하고, 추가할 애의 포인터가 뒤 노드를 가리키게 하면 된다. 그러니까 A와 B 사이에 C를 넣을거면 A의 포인터는 C를, C의 포인터는 B를 가리키게 하면 되는 것이다. 근데 뭐가 문제냐고? 저 노드들 출발선을 조절해야 할 거 아뉴... 반복문을 두 노드가 같이 돌게 되면 같은 횟수를 순회해야된다 이거지.
prev_pointer = self.headnode
curr_pointer = self.headnode.nextnode
여기서 prev_pointer보다 curr_pointer가 하나 앞으로 가야 한다. 근데 둘이 출발선상이 같으면 종점이 같아지잖아요? 그러니까 하나 앞으로 가야 하는 노드는 출발선을 하나 앞으로 땡기면 된다는거다. 이거 두개 앞으로 땡기면 넥스트 넥스트 달아야되나... 백준 그 롱롱롱롱롱롱롱롱인가 그거냐
노드가 담은 값 바꾸기
# 바꿔줘
def change_node (self, _position, _value):
# 3을 입력하면 정직하게 2번째 인덱스를 바꾸기 위해서는 변환 절차가 필요하다.
target_index = _position - 1
if _position < 1:
print('순서값은 1보다 같거나 큰 정수입니다. ')
return
elif _position > self.datacount:
# 리스트 길이를 벗어나면... 아니 근데 그러면 걍 끼워넣기 하면 안됨?
print(f'범위는 1부터 {self.datacount}까지입니다. ')
return
else:
# 원리는 간단하다. 찾아라, 그리고 바꿔라.
move_cnt = target_index + 1
pointernode = self.headnode
for i in range(move_cnt):
pointernode = pointernode.nextnode
# 도착했으면 수정을 해야됩니다.
pointernode.value = _value
뺑뺑이 도는 건 똑같은데 걍 도착해서 값만 바꾸면 된다.
노드 삭제
# 빼줘
def delete_node (self, _position):
# 3을 입력하면 정직하게 2번째 인덱스를 지우기 위해서는 변환 절차가 필요하다.
target_index = _position - 1
if _position < 1:
print('순서값은 1보다 같거나 큰 정수입니다. ')
return
elif _position > self.datacount:
# 리스트 길이를 벗어나면... 아니 근데 그러면 걍 끼워넣기 하면 안됨?
print(f'범위는 1부터 {self.datacount}까지입니다. ')
return
else:
# 그 포인터 앞에 있는 노드의 연결을 다음다음노드로 하면 된다. 연결만 끊으면 끝.
move_cnt = target_index
pointernode = self.headnode
for i in range(move_cnt):
pointernode = pointernode.nextnode
pointernode.nextnode = pointernode.nextnode.nextnode
# 아 맞다 카운터
self.datacount -= 1
return
연결 리스트에서 노드를 삭제하는 것도 원리 자체는 간단하다. 포인터가 다음다음 노드를 가리키게 하면 된다. 그러니까 A-B-C에서 B를 지우고 싶으면 A의 포인터가 C를 가리키게 하면 된다. 쉽죠? 솔직히 인서트 하고 나면 쟤는 선녀야...
전체 조회
# 잘 된겨?
def node_show (self):
# 헤드노드의 다음 노드가 없으면
if self.headnode.nextnode == None:
print('이 리스트는 텅 비었습니다. ')
return
pointernode = self.headnode
while True:
# 다음으로 렛츄고
pointernode = pointernode.nextnode
print(pointernode.value)
# 없으면 시마이
if pointernode.nextnode == None:
break
return
이건 뭐 별 거 없고, 연결 리스트를 머리부터 꼬리까지 쭉 돌면서 노드가 담고 있는 값을 출력하는 코드다. 연결 리스트의 꼬리는 다음으로 이어지는 게 없으니까 포인터 없어? 끝! 이 되는 것. 쉽죠?
'Coding > Python' 카테고리의 다른 글
| 이중 연결 리스트 (0) | 2025.12.10 |
|---|---|
| 제모옥은 스택과 큐로 하겠습니다 근데 이제 연결 리스트를 곁들인 (0) | 2025.12.10 |
| 파스칼의 삼각형 (0) | 2025.12.06 |
| 스택과 큐를 구현해보자 (0) | 2025.12.03 |
| 정말 오랜만에 Project restriction enzyme 업데이트 (0) | 2025.11.28 |