[Data Structures] 연결리스트

배열은 우리가 가장 많이 사용하는 자료구조지만, 크기가 고정되어 있고 중간에 요소를 삽입하거나 삭제할 때 비효율적이다. 이런 배열의 단점을 해결하기 위해 등장한 것이 바로 연결리스트다.


🔗 연결리스트란?

📦 기본 구조

연결리스트는 노드(Node) 라는 단위로 구성된다. 각 노드는 데이터다음 노드를 가리키는 포인터를 가지고 있다.

  • 데이터 필드: 리스트의 원소, 즉 데이터 값을 저장하는 곳
  • 링크 필드: 다른 노드의 주소값을 저장하는 장소

linked-list-node

마치 기차처럼 각 칸(노드)이 다음 칸과 연결되어 있는 구조다. 첫 번째 칸을 알면 줄줄이 따라가서 모든 칸에 접근할 수 있다.

linked-list

class Node {
  constructor(data) {
    this.data = data; // 실제 저장할 데이터
    this.next = null; // 다음 노드를 가리키는 포인터
  }
}

// 연결리스트 예시
const node1 = new Node("첫번째");
const node2 = new Node("두번째");
const node3 = new Node("세번째");

node1.next = node2; // 첫번째 → 두번째
node2.next = node3; // 두번째 → 세번째
node3.next = null; // 세번째 → 끝

⚖️ 배열 vs 연결리스트

🗃️ 배열

배열은 메모리 공간에 데이터가 연속적으로 저장되는 자료구조다.

각 데이터는 인덱스로 빠르게 접근할 수 있어 조회 속도가 매우 빠르다.

하지만 크기가 고정되어 있어, 크기를 변경하려면 새 배열을 만들어야 한다는 단점이 있다.

🧵 연결리스트

연결리스트는 데이터가 메모리 상에 흩어져 저장되며, 각 데이터는 다음 데이터의 위치를 가리키는 포인터를 가지고 있다.

따라서 처음부터 순차적으로 하나씩 찾아가야 하기 때문에 조회 속도가 느리다.

하지만 데이터의 삽입과 삭제가 용이하며, 크기를 동적으로 조절할 수 있다는 장점이 있다.

💡 언제 사용할까?

연결리스트가 유리한 경우

  • 데이터의 개수를 미리 알 수 없을 때
  • 중간에 삽입/삭제가 자주 일어날 때
  • 메모리를 효율적으로 사용해야 할 때

배열이 유리한 경우

  • 특정 위치의 데이터에 자주 접근할 때
  • 데이터 크기가 고정되어 있을 때
  • 메모리 사용량을 예측해야 할 때

🧩 연결 리스트의 종류

➡️ 단순 연결 리스트

단순 연결 리스트는 각 노드가 오직 다음 노드만 가리키는 가장 기본적인 형태다.

singly-linked-list

  • 한 방향(앞→뒤)으로만 순회할 수 있다.

  • 구현이 간단하고, 메모리 사용량이 적다.

🔄 원형 연결 리스트

원형 연결 리스트는 마지막 노드가 다시 첫 번째 노드를 가리켜 원형을 이루는 구조다.

circular-linked-list

  • 리스트의 끝이 없기 때문에, 순환 구조가 필요할 때 유용하다.

🔁 이중 연결 리스트

이중 연결 리스트는 각 노드가 이전 노드와 다음 노드 모두를 가리키는 구조다.

doubly-linked-list

  • 양방향으로 순회할 수 있어 더 유연하다.

  • 삭제나 삽입 시 특정 노드를 더 쉽게 접근 가능하지만, 메모리 사용량이 더 많고 구현이 복잡하다.


✅ 연결리스트의 장단점

👍 장점

  • 동적으로 크기를 조절할 수 있어 유연하다.

  • 중간이나 앞부분에서 삽입/삭제가 빠르게 일어난다.

  • 메모리가 연속적으로 할당되지 않아도 되어 효율적으로 사용할 수 있다.

👎 단점

  • 특정 위치에 접근하려면 처음부터 순차적으로 탐색해야 하므로 느리다.

  • 각 노드마다 포인터를 저장해야 하므로 메모리 사용이 증가한다.

  • 메모리 상에 흩어져 저장되므로 캐시 효율성이 떨어질 수 있다.

Leave a comment