2 분 소요

DoubleLinkedList 뜯어보기!

class Node:  
    def __init__(self, data, prev_=None, next_=None):  
        self.data = data  
        self.prev = prev_  
        self.next = next_  
  
  
class DoubleLinkedList:  
    def __init__(self):  
        self.head = Node(None)  
        self.tail = Node(None)  
        self._size = 0  
  
        self.head.next = self.tail  
        self.tail.prev = self.head  
  
    def size(self):  
        return self._size  
  
    def add(self, data):  
        last = self.tail.prev  
        new_node = Node(data, last, self.tail)  
        last.next = new_node  
        self.tail.prev = new_node  
        self._size += 1  
  
    def insert(self, index, data):  
        if index > self._size or index < 0:  
            raise RuntimeError("Index out of error")  
  
        prev, current = None, None  
        i = 0  
        if index < self._size // 2:  
            prev = self.head  
            current = self.head.next  
            while i < index:  
                prev = prev.next  
                current = current.next  
                i += 1  
        else:  
            current = self.tail  
            prev = self.tail.prev  
            while i < (self._size - index):  
                current = current.prev  
                prev = prev.prev  
                i += 1  
  
        new_node = Node(data, prev, current)  
        current.prev = new_node  
        prev.next = new_node  
        self._size += 1  
  
    def clear(self):  
        self._size = 0  
        self.head.next = self.tail  
        self.head.prev = None  
        self.tail.next = None  
        self.tail.prev = self.head  
  
    def delete(self, data):  
        prev = self.head  
        current = prev.next  
        while current is not None:  
            if current.data == data:  
                prev.next = current.next  
                current.next.prev = prev  
                current.next = None  
                current.prev = None  
                self._size -= 1  
                return True  
  
            prev = prev.next  
            current = current.next  
  
        return False  
  
    def delete_by_index(self, index):  
        if index >= self._size or index < 0:  
            raise RuntimeError("Index out of error")  
  
        prev_, current_, next_ = None, None, None  
        i = 0  
        if index < self._size // 2:  
            prev_ = self.head  
            current_ = self.head.next  
            while i < index:  
                prev_ = prev_.next  
                current_ = current_.next  
                i += 1  
            prev_.next = current_.next  
            current_.next.prev = prev_  
            current_.next = None  
            current_.prev = None  
        else:  
            current_ = self.tail.prev  
            next_ = self.tail  
            while i < (self._size - index - 1):  
                next_ = next_.prev  
                current_ = current_.prev  
  
            next_.prev = current_.rpev  
            current_.prev.next = next_  
            current_.next = None  
            current_.prev = None  
  
        self._size -= 1  
        return True  
  
    def get(self, index):  
        if index >= self._size or index < 0:  
            raise RuntimeError("Index out of error")  
  
        i = 0  
        current = None  
        if index < self.size // 2:  
            current = self.head.next  
            while i < index:  
                current = current.next  
                i += 1  
        else:  
            current = self.head.prev  
            while i < (self._size - index - 1):  
                current = current.prev  
                i += 1  
  
        return current.data  
  
    def index_of(self, data):  
        current = self.head.next  
        index = 0  
        while current != None:  
            if current.data != None and current.data == data:  
                return index  
            current = current.next  
            index += 1  
        return -1  
  
    def is_empty(self):  
        return self.head.next == self.tail  
  
    def contains(self, data):  

        front = self.head.next  
        rear = self.tail.prev  
  
        while front != None and rear != None:  
            if front.data != None and front.data == data:  
                return True  
  
            if rear.data != None and rear.data == data:  
                return True  
  
            front = front.next  
            rear = rear.prev  
  
        return False  
  
  
if __name__ == "__main__":  
    l = DoubleLinkedList()  
    for elem in [3, 2, 5, 1, 4]:  
        print(f"l.add({elem})")  
        l.add(elem)  
  
    print(f"l.size(): {l.size()}")  
  
    print("=====================")  
    for elem in [3, 2, 5, 1, 4, 100]:  
        print(f"l.contains({elem}): {l.contains(elem)}")  
        print(f"l.index_of({elem}): {l.index_of(elem)}")  
  
    print("=====================")  
    for elem in [4, 5, 100]:  
        print(f"l.delete({elem}): {l.delete(elem)}")  
  
    print(f"l.size(): {l.size()}")  
  
    print(f"l.insert(0, 100)")  
    l.insert(0, 100)  
    print(f"l.insert(2, 101)")  
    l.insert(2, 101)  
  
    for elem in [3, 2, 5, 1, 4, 100, 101]:  
        print(f"l.contains({elem}): {l.contains(elem)}")  
        print(f"l.index_of({elem}): {l.index_of(elem)}")
  • 리스트의 가장 앞과 가장 뒤를 동시에 탐색
  • 연산의 횟수는 데이터의 갯수가 N 일때 절반이 줄어든 N/2 만큼 loop 반복
  • 시간복잡도는 상수는 날린다는 특성에 따라 O(N/2) 가 아닌, O(N) 으로 표현
  • 두 개의 위치로 데이터에 접근하는 방식을 투포인터 알고리즘이라고 함
  • 실제로는 아래 코드 처럼 더블 링크드 리스트의 투포인터 노드 접근 보다 위치를 가르키는 인덱스를 활용할 때 투포인터로 인한 성능상 이득이 두드러지기 떄문에 인덱스를 활용한 투포인터 알고리즘 문제가 많음
  • 투포인터 알고리즘을 응용한 문제는 아래 블로그 참고
  • https://myeongmy.tistory.com/7

참고 : https://pstudio411.tistory.com/entry/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-Linked-List-Hash-Table , https://myeongmy.tistory.com/7

댓글남기기