본문 바로가기

Theory/Algorithm & Data Structure

[자료구조] 링크드 리스트(Linked List)

Hi, There!
안녕하세요, 바오밥입니다.


목차

  1. 개요
  2. 본문
  3. Reference

개요

지금까지 스택, 큐, 배열 등 정말 기초적인 자료 구조를 알아보았습니다.
이어서 링크드 리스트에 대해 알아보도록 하겠습니다.


본문

링크드 리스트 (Linked List) 구조

  • 배열은 순차적인 메모리 공간에 데이터를 나열하는 구조인 반면, 링크드 리스트는 떨어진 곳에 존재하는 데이터를 참조하여 관리하는 데이터 구조입니다.

  • C 언어에서 주요한 데이터 구조이지만, 파이썬은 리스트 타입이 링크드 리스트의 기능을 모두 지원합니다.
    그래서 C언어와 다르게 파이썬은 별도의 리스트의 크기를 지정하지 않고 선언할 수 있습니다.

 

 

링크드 리스트 기본 구조와 용어

  • 노드(Node) : 데이터 저장 단위를 뜻하며 값, 포인터(참조 정보)로 구성되어 있습니다.

  • 포인터(Pointer) : 각 노드 안에서 다음이나 이전의 노드와의 연결(참조) 정보를 가지고 있는 공간입니다.

  • 링크드 리스트의 마지막 노드를 제외한 모든 노드는 포인터에 메모리의 주소 값으로 매핑되어 있습니다.
    링크드 리스트의 마지막 노드는 메모리의 주소 값 대신 널 값이 매핑되어 있고, 이는 리스트의 끝을 의미합니다.

 

Ref - https://en.wikipedia.org/wiki/Linked_list)

 

단방향 링크드 리스트 예제

Node 구현

class Node:
  def __init__(self, data):
    self.data = data
    self.next = None

 

Linked List 구현

class LinkedList:
  def __init__(self, data):
    self.head = Node(data)
    self.next = None

  def append(self, data):
    cur = self.head
    while cur.next:
      cur = cur.next
    cur.next = Node(data)

  def showNodeAll(self):
    cur = self.head
    while cur:
      print(cur.data)
      cur = cur.next

  def insert(self, prev, data):
    cur = self.head
    isDataPos = True
    while isDataPos:
      if cur.data == prev:
        prevNode = cur
        nextNode = cur.next
        prevNode.next = Node(data)
        newNode = prevNode.next
        newNode.next = nextNode
        isDataPos = False
      else:
        cur = cur.next

  def delete(self, data):
    cur = self.head
    if cur == '':
      print('삭제할 요소가 존재하지 않습니다.')
      return

    if cur.data == data:
      temp = self.head
      self.head = self.head.next
      del temp

    else: 
      isDataPos = True
      while isDataPos:
        if cur.next.data == data:
          temp = cur.next
          cur.next = cur.next.next
          del temp
          isDataPos = False

        else:
          cur = cur.next

  def searchNode(self, data):
    idx = 1
    cur = self.head
    while cur:
      if cur.data == data:
        print("검색하신 데이터는",str(idx)+"번째 노드입니다.")
        return 
      else:
        idx += 1
        cur = cur.next

 

링크드 리스트, 노드 사이의 새로운 노드를 만들 때 일어나는 상황을 표현한 그림

Ref - https://en.wikipedia.org/wiki/Linked_list

 

링크드 리스트의 장단점 (배열 VS 링크드 리스트)

장점

  • 미리 데이터 공간을 할당하지 않아도 됩니다.
    *배열은 미리 데이터 공간을 할당해야 합니다.

 

단점

  • 연결(참조 주소)을 위한 별도 데이터 공간이 필요하므로, 저장공간 효율이 높지 않습니다.

  • 연결 정보(참조 주소)를 찾는 시간이 필요하므로 접근 속도가 비교적 느립니다.
    *배열은 인덱스 번호로 바로 접근이 가능합니다.

  • 중간 데이터 삭제 시, 앞뒤 데이터의 연결을 재구성해야 하는 부가적인 작업이 필요합니다.

 

더블 링크드 리스트(이중 연결 리스트)의 구조

  • 이중 연결리스트는 양방향으로 연결되어 있어서 노드 탐색이 양쪽으로 가능합니다.

Ref - https://en.wikipedia.org/wiki/Linked_list

 

더블 링크드 리스트(이중 연결 리스트)의 예제

Node 구현

class Node:
  def __init__(self,data):
    self.prev = None
    self.data = data
    self.next = None

 

Double Linked List 구현

class Node:
  def __init__(self,data):
    self.prev = None
    self.data = data
    self.next = None

class DoubleLinkedList:
  def __init__(self,data):
    self.head = Node(data)
    self.tail = self.head

  def append(self, data):
    cur = self.head
    while cur.next:
      cur = cur.next
    newNode = Node(data)
    cur.next = newNode
    newNode.prev = cur
    self.tail = newNode

  def insertPrev(self, prevData, data):
    cur = self.head
    while cur:
      if cur.data == prevData:
        prevNode = cur
        newNode = Node(data)
        nextNode = cur.next

        newNode.prev = prevNode
        newNode.next = nextNode

        nextNode.prev = newNode
        prevNode.next = newNode
        break
    else:
      cur = cur.next

  def insertNext(self, nextData, data):
    cur = self.head
    while cur:
      if cur.data == nextData:
        prevNode = cur
        newNode = Node(data)
        nextNode = cur.next

        newNode.prev = prevNode
        newNode.next = nextNode

        nextNode.prev = newNode
        prevNode.next = newNode
        break
      else:
        cur = cur.next    

  def searchFromHead(self,data):
    cur = self.head
    idx = 1

    while cur:
      if cur.data == data:
        print(f'데이터: {data}는 앞에서 {idx}번째 노드입니다.')
        break
      else:
        cur = cur.next
        idx += 1

  def searchFromTail(self,data):
    cur = self.tail
    idx = 1

    while cur:
      if cur.data == data:
        print(f'데이터: {data}는 뒤에서 {idx}번째 노드입니다.')
        break
      else:
        cur = cur.prev
        idx += 1

  def showNodeAll(self):
    cur = self.head
    while cur:
      print(cur.data)
      cur = cur.next

Reference

  • 코드 없는 알고리즘과 데이터 구조
  • 알고리즘 / 기술면접 완전 정복 올인원 패키지 Online.