교재 : 파이썬으로 배우는 자료구조 프로그래밍 (유석종, 휴먼싸이언스)
5.1 연결 리스트 개요
1) 연결 리스트의 종류
- 연결리스트 (linked list) : 노드들이 링크에 의해 순차적으로 연결된 자료구조
- 노드는 값을 저장하는 공간과 노드를 연결하는 링크(link)로 구성된다.
- 단일 연결 리스트 (singly linked list) : 노드들이 한 방향으로만 연결된 구조
- 이중 연결 리스트 (doubly linked llist) : 앞 뒤 양방향으로 연결된 구조
- 체인(chain) : 연결 리스트가 마지막 노드(마지막 노드 링크에 None이 저장됨.)에서 끝나는 구조
- 순환 연결 리스트 (circular linked list) : 마지막 노드가 첫 노드와 연결되는 구조
2) 연결 리스트의 표현
- 기본 단위 : 노드(node)
- 값을 저장하는 데이터(data) 필드, 노드를 연결하는 링크(link) 필드로 구성된다.
5.2 단일 연결 리스트
1) 개요
- 연결 리스트이 첫 노드를 가리키는 head 변수(리스트 포인터, list pointer), 마지막 노드를 가리키는 tail 변수
- 마지막 노드의 링크 값은 None
class Node:
def __init__(self, item):
self.data = item
self.link = None
class SinglyLinkedList:
def __init__(self):
self.head = None
self.tail = None
def isEmpty(self):
return not self.head
def view(self):
temp = self.head
print("[", end = ' ')
while temp:
print(temp.data, end = ' ')
temp = temp.link
print("]", end = ' ')
if self.head:
print("H = ", self.head.data , "T = ", self.tail.data)
else:
print("빈 리스트")
def attach(self,item):
node = Node(item)
if not self.node:
self.head = node
self.tail = node
elif self.tail:
self.tail.link = node
self.tail = node
2) 연결 리스트 노드 추가
- 추가할 노드(node)를 생성한 후 data 필드에 값을 저장하고 link 필드를 None으로 초기화한다.
- 연결 리스트가 빈 경우 (empty) : 노드(node)를 리스트 변수(head)에 저장하고 종료한다.
- 연결 리스트가 비어 있지 않은 경우 (not empty) : 앞 노드(prev)를 탐색한다.
- prev가 존재하는 경우
- prev의 link 필드 값을 노드(node)의 link 필드에 저장한다.
- prev의 link 필드에 노드(node)를 저장하고 종료한다.
- prev가 존재하지 않는 경우 (리스트 맨 앞에 추가)
- 노드(node)의 link 필드에 리스트 변수(head)를 저장한다.
- 리스트 변수(head)에 노드(node)를 저장하고 종료한다.
- prev가 존재하는 경우
def find(self, item):
if not self.head:
return None, None
temp = self.head
prev = None
while temp:
if temp.data == item:
return prev, temp
prev = temp
temp = temp.link
return None, None
def insert(self, prev,item):
if not self.head:
return
node = Node(item)
if not prev:
node.link = self.head
self.head = node
return
before, temp = self.find(prev)
if not temp:
print("앞 노드 없음")
return
else:
node.link = temp.link
temp.link = node
if not node.link:
self.tail =node
3) 연결 리스트 노드 삭제
- 리스트가 빈 경우 (empty) : 그대로 종료한다.
- 리스트에 노드가 있는 경우 (not empty) : 삭제 노드(node)와 앞 노드(prev)를 탐색하고, 노드가 없으면 종료한다.
- prev가 있는 경우 (중간 노드 삭제) : prev의 link 필드에 node의 link 값을 저장한다.
- prev가 없는 경우 (첫 노드 삭제) : 리스트 변수(head)에 node의 link를 저장한다.
- node를 삭제하고 종료한다.
def del_find(self, item):
if not self.head:
print("빈 리스트")
return
prev, node = self.find(item)
if not node:
print("노드 없음")
return
if prev:
prev.link = node.link
print("노드 삭제됨.")
else:
if self.head == node:
print("첫 노드 삭제됨.")
self.head = node.link
if node == self.tail:
self.tail = prev
del node
5.3 연결 리스트 연산
1) 리스트 길이 세기
- 연결 리스트의 길이 (length) : 노드의 수
- 반복문으로 리스트 변수에서부터 노드의 수를 계산하여 구현할 수 있다.
- 코드
def length_list(self):
count = 0
temp = self.head
while temp:
count +=1
temp = temp.link
return count
2) 리스트 합치기
- 결합 (concatenation) : 두 개의 리스트를 연결하여 하나로 합치는 것
- 알고리즘
- 앞 리스트가 빈 리스트라면 뒤의 리스트를 반환하고 종료한다.
- 앞 리스트가 비어 있지 않다면
- 뒤의 리스트가 비어 있다면 앞의 리스트를 반환하고 종료한다.
- 뒤의 리스트가 비어 있지 않다면 앞 리스트의 마지막 노드를 탐색하여 뒤의 리스트를 연결하고 앞의 리스트를 반환한다.
- 코드
def concat(self, second):
if not self.head:
return second
elif second:
temp = self.head
while temp.link:
temp = temp.link
temp.link =second
return self.head
lst1.head = lst2.concat(lst2.haed)
5.4 순환 연결 리스트
1) 순환 연결 리스트 (circular linked list)
- 마지막 노드의 링크가 None이 아니고 그 리스트의 첫 노드에 다시 연결되어 있다.
- 순환 연결 리스트의 길이 : 시작 노드로 다시 되돌아오는 순간이 전체 리스트를 모두 탐색한 시점
- 코드
class Node:
def __init__(self, item):
self.data = item
self.link = None
class CircularList:
def __init__(self, item):
self.head = item
self.link = None
def isEmpty(self):
return not self.head
def add_rear(self,item):
node = Node(item)
if not self.head:
self.head = node
self.tail = node
elif self.tail:
self.tail.link = node
self.tail = node
node.link = self.head
def length_list(self):
if not self.head:
return 0
count = 0
temp = self.head
while True:
count += 1
temp = temp.link
if temp == self.head:
break
return count
def view(self):
temp = self.head
print("[", end = ' ')
while temp:
print(temp.data, end=' ')
temp = temp.link
if temp is self.head:
break
print("]")
if self.head:
print("H=", self.head.data, "T=", self.tail.data)
else:
print("빈 리스트")
2) 역순 연결 리스트 (reverse linked list)
- 주어진 리스트의 노드들을 반대 방향으로 연결된 리스트
- 알고리즘
- 빈 리스트이거나 노드가 1개만 있는 경우, 리스트 변수(head)를 반환하고 종료한다.
- 리스트 노드가 2개 이상인 경우, 추가 변수(second, third)를 사용하여 아래를 수행한다.
- third 변수가 second 노드를 가리키게 한다.
- second 변수가 first 노드를 참조하게 한다.
- first 변수를 다음 노드로 이동시킨다.
- second 노드의 링크에 third 값을 저장한다.
- first가 None이 아닐 때까지 2.1부터 반복한다.
- 코드
def reverse(self):
first = self.head
second = third = None
self.tail = self.head
while first:
third = second
second = first
first = first.link
second.link = third
self.head = second
5.5 이중 연결 리스트
1) 이중 연결 리스트 (doubly linked list)
- 각 노드에서 앞 뒤 노드로 링크가 연결되어 있다.
- 이진 트리(binary tree)를 구현하는 데 활용된다.
- node == node.llink.rlink == node.rlink.llink
2) 이중 연결 리스트의 표현
- 일반적으로 헤드 노드(head)가 존재하는데, 헤드 노드의 링크는 리스트의 첫 노드와 마지막 노드를 가리키고, 데이터 필드에는 전체 노드의 수를 저장한다.
- 헤드 노드는 삭제할 수 없는 노드이며 항상 존재하므로 노드의 삽입, 삭제 연산이 편리하다.
class Node:
def __init__(self, item):
self.data = item
self.rlink = None
self.llink = None
class LinkedList:
def __init__(self):
self.head = Node(0)
self.head.rlink = self.head
self.head.llink = self.head
def empty(self):
return self.head.rlink == self.head
3) 이중 연결 리스트에 노드 추가
- 알고리즘
- node의 llink가 prev 노드를 가리키도록 한다
- node의 rlink가 prev 다음 노드를 가리키도록 한다.
- prev 다음 노드의 llink가 node를 가리키도록 한다.
- prev의 llink가 node를 가리키도록 한다.
- 코드
def add(self, item):
node = Node(item)
self.head.data +=1
if self.empty():
node.llink = self.head
node.rlink = self.head
node.head.rlink = node
self.head.llink = node
else:
node.llink = self.head.llink
node.rlink = self.head
self.head.llink.rlink = node
self.head.llink = node
4) 이중 연결 리스트의 노드 삭제
- 알고리즘
- 빈 리스트이거나 삭제할 노드(node)가 존재하지 않으면 종료한다.
- 삭제 노드(node)가 head 노드가 아닐 경우, 앞 노드(node.llink)의 rlink에 node의 다음 노드(node.rlink)를 저장한다.
- node의 다음 노드(node.llink)의 llink에 node의 앞 노드(node.llink)를 저장한다.
- node를 삭제한다.
- 코드
def find(self, item):
temp = self.head.rlink
while temp!=self.head:
if temp.data == item:
return temp
temp = temp.rlink
return None
def delete(self, item):
if self.empty():
print("List Empty")
return
node = self.find(item)
if not node:
print("Not Found")
return
if node == self.head:
print("head is not deleted")
return
self.head.data -= 1
node.llink.rllink = node.rlink
node.rlink.llink = node.llink
del node
'전공과목 정리 > 자료구조' 카테고리의 다른 글
[자료구조💾] 7장 최대 힙 (0) | 2024.01.20 |
---|---|
[자료구조💾] 6장 이진 트리 (0) | 2024.01.18 |
[자료구조💾] 4장 스택과 큐 (0) | 2024.01.16 |
[자료구조💾] 3장 재귀호출 (2) | 2024.01.10 |
[자료구조💾] 2장 파이썬 자료구조 (0) | 2024.01.09 |