따라서 이 Chapter에서는 linked list 데이터 구조를 소개한다. Array-based 자료 구조와 linked-list 자료 구조 모두 자료의 순서를 서로 다른 스타일로 보존한다.
class Node:
__slots__ = "e", "next_" # make limit attribute
def __init__(self, e):
self.e = e
self.next_ = None
Algorithm add_first(L,e):
newest = Node(e) # 새로운 node 객체 생성
newest.next = L.head
L.head = newest
L.size = L.size + 1
*보충 : 왜 special method slots 을 쓰는가?
Algorithm remove_first(L):
if L.head is None then
Indicate an error : the list is empty
L.head = L.head.next
L.size = L.size - 1
class LinkedStack:
class _Node: # nested class
def __init__(self, element, next):
self._element = element
self._next = next
def __init__(self):
self._head = None
self._size = 0
def __len__(self):
return self._size
def is_empty(self):
return self._size == 0
def push(self, e):
self._head = _Node(e, self._head)
self._size +=1
def pop(self):
if self.is_empty():
raise Empty("Stack is empty!")
item = self._head._element
self._head = self._head._next
self._size -= 1
return item
def top(self):
if self.is_epmty():
raise Empty("Stack is empty")
return self._head._element
class LinkedQueue:
class _Node:
def __init__(self, element, next):
self._element = element
self._next = next
def __init__(self):
self._head = None
self.tail = None
self._size = 0
def is_empty(self):
return self._size == 0
def __len__(self):
return self._size
def enqueue(self, e): # tail을 이용하는 부분을 한번 더 체크.
#self._head = _Node(e, self._head) # head를 기점으로 계속 삽입할 수도 있지만,
# tail을 이용하여 삽입하면서, 마지막을 항상 가리키도록 유도한다.
new_node = Node(e, None)
if is_empty(): self._head = new_node
else: self._tail.next = new_node # tail이 마지막을 가리키고 있기 때문에 마지막 다음에 삽입해준다는 의미.
self._tail = new_node # 그리고나서, tail이 다시 마지막을 가리키도록 작업.
self._size += 1
def dequeue(self):
if self.is_empty():
raise Empty("Queue is empty!")
self._head = self._head.next
self._size -= 1
# tail 처리 (저장된 데이터가 1개인 경우)
if is_empty(): self._tail = None
Implementing a Queue with a Circularly Linked List
class CircularQueue:
# _Node ADT 생략
def __init__(self):
#self._head = None
self._tail = None
self._size = 0
def
Header and Trailer Sentinels
3.1 Inserting and Deleting with a Doubly Linked List
class Node:
__slots__ = "_element", "_prev", "_next"
def __init__(self, element, prev, next):
self._element = element
self._prev = prev
self._next = next
class _DoublyLinkedBase:
def __init__(self):
self._header = self. Node(None, None, None)
self._trailer = self. Node(None, None, None)
self._header_next = self._trailer # 서로를 가리키고 있는 최초 linked list 생성.
self._trailer._prev = self._header
self._size = 0
def __len__(self):
return self._size
def is_empty(self):
return self._size == 0
def _insert_between(self, e, predecessor, successor):
new_node = self._Node(e, predecessor, successor)
predecessor._next = new_node
successor._prev = new_node
self._size +=1
return new_node
def _delete_node(self, node):
predecessor = node._prev
successor = node._next
predecessor._next = successor
successor._prev = predecessor
self._size -= 1
element = node._element
node._prev = node._next = node._element = None # deprecate node
return element # node's element return
3.2 Implementing a Deque with a Doubly Linked List
class LinkedDeque(_DoublyLinkedBase):
def first(self):
if self.is_empty():
raise Empty("Deque is empty")
return self._header._next._element
def last(self):
if self.is_empty():
raise Empty("Deque is empty")
return self._trailer._prev._element
def insert_first(self, e):
self._insert between(e, self._header, self._header._next)
def insert_last(self, e):
self._insert between(e, self._trailer._prev, self._trailer)
def delete_first(self):
if self.is_empty(): # delete 시에는 항상 is empty를 체크해준다.
raise Empty("Deque is empty")
return self._delete_node(self._header._next) # dobuly linked list 또한 head 또는 trailer로 접근한다.
def delete_last(self):
if self.is_empty():
raise Empty("Deque is empty")
return self._delete_node(self._trailer._prev)
A Node Reference as a Position?
4.1 The Positional List Abstract Data Type
4.2 Doubly Linked List Implementation
class PositionalList(_DoublyLinkedBase):
class Position:
def __init__(self, container, node):
self._container = container
self._node = node
def element(self):
return self._node._element
def __eq__(self, other):
return type(other) is type(self) and other._node is self._node
def __ne__(self, other):
return not(self == other) # 왜 self != other 이라고는 표현하지 않는걸까?
# --------------- utility method ------------- #
# we want to verify that the position is valid.
def _validate(self, p):
if not isinstance(p, self.Position):
raise TypeError( "p must be proper Position type" )
if p._container is not self:
raise ValueError("p does not belong to this container")
if p._node._next is None:
raise ValueError( "p is no longer valid" )
return p._node
# we determine the underlying node associated with the position.
**def make_position(self, node):
if node is self._header or node is self._trailer:
return None # If node is put on first or last...
else: return self.Position(self, node)**
# --------------accessors--------------------- #
def first(self):
return self._make_position(self._header._next) # position을 return 함.
def last(self):
return self._make_position(self._trailer._prev)
def before(self, p):
node = self._validate(p)
return self._make_position(node._prev)
def after(self, p):
node = self._validate(p)
return self._make_position(node._next)
def __iter__(self): # L의 모든 커서들에 대해
cursor = self.first()
while cursor is not None:
yield cursor.element()
cursor = self.after(cursor)
# -------------- mutators -------------------- #
def insert between(self, e, predecessor, successor):
node = super()._insert_between(e, predecessor, successor)
return self._make_position(node)
def add_first(self, e):
return self._insert_between(e, self._header, self._header._next)
def add_last(self, e):
return self._insert_between(e, self._trailer._prev, self._trailer)
def add_before(self, p, e):
original = self._validate(p)
return self._insert_between(e, original_prev, original)
def add_after(self, p, e):
original = self._validate(p)
return self._insert_between(e, original, original_next)
def delete(self, p):
original = self._validate(p)
return self._delete_node(original)
def replace(self, p, e):
original = self. validate(p)
old_value = original._element
original._element = e
return old_value
def insertion_sort(L):
if len(L) > 1:
marker = L.first()
while marker != L.last():
pivot = L.after(marker)
value = pivot.element()
if value > marker.element():
marker = pivot
else:
walk = marker
while walk != L.first() and L.before(walk).element() > value:
walk = L.before(walk)
L.delete(pivot) # pivot element는 이미 value로 저장.
L.add_before(walk, value)
# 배열 insertion sort와 비교.
def insert_sort(arr):
for i in range(1, len(arr)):
temp = arr[i]
j = i
while j > 0 and temp < arr[j-1]:
arr[j] = arr[j-1]
j-=1
arr[j] = temp
return arr
Array-Based Sequences
Pros
Cons
Link-Based Seqeuences
Pros
Cons