List

  • 리스트(List) : 순서가 있는 데이터의 모음(Sequence of items)
  • 각 요소가 고유한 위치를 가지고 있음.

 

1. Array-based List (배열 기반 리스트)

  • 배열에 데이터를 순서대로 저장하는 방식.
  • 데이터가 메모리상에 연속된 공간에 저장됨.
  • C에서는 배열을 통해 순차 리스트를 구현할 수 있음

 

  • 인덱스를 이용한 빠른 접근 가능: O(1)
  • 하지만 삽입/삭제 시 요소를 이동해야 하므로 O(n)
  • 리스트 크기가 고정되어 있어 유연성이 떨어짐

배열 기반 리스트에서 삽입/삭제 시의 변화 예시)

연산 설명 [5, 12, 23, 14, 13] 
삽입 중간에 데이터를 넣기 위해 뒤의 요소들을 한 칸씩 이동 Insert 10 at index 3 → [5, 12, 23, 10, 14, 13] 
삭제 삭제 후 남은 요소들을 한 칸씩 앞으로 당김 Delete index 2 → [5, 12, 10, 14, 13]
 

📉 시간복잡도

  • 평균: O(n/2)
  • 최악(맨 앞 삽입): O(n)

이처럼 배열은 랜덤 접근은 빠르지만, 삽입·삭제는 비효율적임.


이를 해결하기 위한 구조가 바로 Linked List 


2. Pointer-based List (Linked List)

  • 연결 리스트는 각 데이터를 노드(Node) 단위로 저장하고, 각 노드가 다음 노드의 주소를 포인터로 연결하는 구조
  • 즉, 데이터들이 메모리상에 연속적으로 위치할 필요가 없음.
  • 필요할 때마다 동적으로 노드를 생성하여 연결할 수 있
  • = 삽입/삭제 시 포인터만 수정하면 되므로 배열보다 유연함.

 

구조

각 노드는 다음 두 가지 정보를 가짐:

  1. data – 실제 값
  2. link – 다음 노드의 주소(pointer)

리스트의 첫 번째 노드는 head(또는 first)가 가리키며,

  (첫 Node가 어디에 저장되어있는지를 알아야하므로 head pointer 필요함.)
마지막 노드는 NULL을 가리켜 리스트의 끝을 의미함.

 

구현 예시 (C)

typedef struct Node {
    int data;
    struct Node* link;
} Node;

Node* head = NULL;
 

노드 생성

Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = 10;
newNode->link = NULL;
 
 

삽입 (맨 앞, 중간, 맨 뒤)

중간에 삽입할 경우 삽입하고자 하는 앞의 link 와 삽입할 data를 연결, 삽입할 data의 link와 다음에 올 data를 연결하면 됨.

// 새 노드를 기존 노드 뒤에 연결
newNode->link = head;
head = newNode;

 

삭제

특정 노드를 삭제하려면 이전 노드의 링크를 다음 노드로 변경하면 됨

prev->link = target->link;
free(target);

 

출력

void printList(Node *head) {
    for (Node *cur = head; cur != NULL; cur = cur->next)
        printf("%d -> ", cur->data);
    printf("NULL\n");
}

 

특징

  • 장점: 삽입/삭제 O(1) (위치만 알면 됨), 크기 동적 조절 가능
  • 단점: 인덱스 접근 불가(O(n)), 추가 메모리(포인터) 필요

정리하자면, 

항목 array list linked list
메모리 구조 연속된 공간 불연속적, 동적 할당
접근 속도 빠름 (O(1)) 느림 (O(n))
삽입/삭제 느림 (O(n)) 빠름 (O(1))
크기 조절 불가능 가능
추가 메모리 없음 포인터 저장 필요

 == 삽입/삭제가 빈번하고 데이터 크기가 동적으로 변한다면 Linked List가 유리하다.


3. Linked Array & Linked Queue & Linked Stack

- Linked Array

  • 배열 + 연결 리스트의 절충형.
  • 구조는 배열이지만, 배열 내 각 원소가 다음 인덱스를 가리키는 링크를 가짐.
  • 메모리 풀(memory pool) 방식으로 구현해 메모리 단편화 최소화.
typedef struct {
    int data;
    int next; // 다음 요소의 인덱스
} Node;

Node node[MAX];
int head = -1;
int avail = 0;
  • head는 첫 노드의 인덱스를,
  • avail은 사용 가능한 다음 빈 공간을 나타냄.
  • 실제로는 배열 안에 링크 정보를 저장하므로,
    메모리 연속성 + 동적 연결의 장점을 일부 가짐.

이 방식은 주로 임베디드 환경이나 메모리 제약 시스템에서 사용됨.

 

- Linked Queue

  • 연결 리스트를 사용하여 큐(Queue) 를 구현한 구조
  • 큐(Queue): FIFO (First In First Out) 구조.
  • 배열 기반 큐는 공간이 꽉 차면 이동 필요 → 비효율적.
  • 연결 리스트 기반 큐 는 노드 추가/삭제가 유연함.
  • 크기 제한 없음 (동적 노드 생성 가능)
  • 삽입/삭제 모두 O(1)
  • 포인터 관리 필요 (메모리 누수 주의)

 

구조 정의

typedef struct Node {
    int data;
    struct Node* link;
} Node;

typedef struct {
    Node* front;
    Node* rear;
} LinkedQueue;

 

주요 연산

// 초기화
void initQueue(LinkedQueue* q) {
    q->front = q->rear = NULL;
}

// 삽입(enqueue)
void enqueue(LinkedQueue* q, int val) {
    Node* newNode = malloc(sizeof(Node));
    newNode->data = val;
    newNode->link = NULL;
    if (q->rear == NULL)
        q->front = q->rear = newNode;
    else {
        q->rear->link = newNode;
        q->rear = newNode;
    }
}

// 삭제(dequeue)
int dequeue(LinkedQueue* q) {
    if (q->front == NULL) return -1;
    Node* tmp = q->front;
    int val = tmp->data;
    q->front = q->front->link;
    if (q->front == NULL)
        q->rear = NULL;
    free(tmp);
    return val;
}

 

- Linked Stack

  • 연결 리스트를 사용하여 스택(Stack) 를 구현한 구조
  • 스택(Stack): LIFO (Last In, First Out) 구조.
  • 크기 제한 없음 (동적 노드 생성 가능)
  • 삽입/삭제 모두 O(1)
Top → [30] → [20] → [10] → NULL

 

  • push: 새 노드를 head(Top) 앞에 삽입
  • pop: head를 삭제

 

구조 정의

typedef struct Node {
    int data;
    struct Node *link;
} Node;

typedef struct {
    Node *top;
} LinkedStack;

 

주요 연산

// 초기화
void init(LinkedStack *s) {
    s->top = NULL;
}

// 삽입
void push(LinkedStack *s, int val) {
    Node *newNode = malloc(sizeof(Node));
    newNode->data = val;
    newNode->link = s->top;
    s->top = newNode;
}

// 삭제
int pop(LinkedStack *s) {
    if (s->top == NULL) return -1; // underflow
    Node *temp = s->top;
    int val = temp->data;
    s->top = temp->link;
    free(temp);
    return val;
}

// peek
int peek(LinkedStack *s) {
    if (s->top == NULL) return -1;
    return s->top->data;
}

 

 

구현방식 구조 장점 단점
Array-based List 배열로 구현 빠른 접근 삽입/삭제 느림
Linked List 포인터 연결 삽입/삭제 빠름, 크기 유연 접근 느림
Linked Array 배열 + 포인터 혼합 메모리 관리 용이 구현 복잡
Linked Queue 리스트 기반 큐 동적 확장, O(1) 연산 포인터 관리 필요
Linked Stack 리스트 기반 스택 동적 확장, 크기 제한 없음 malloc/free 관리 필요

'이론공부 > 자료구조, 알고리즘' 카테고리의 다른 글

4. Linked List (3) - 복잡한 구조 표현  (0) 2025.11.07
4. Linked List (2) - 활용  (0) 2025.11.07
3. Stack & Queue (2) - 활용  (0) 2025.11.07
3. Stack & Queue (1)  (1) 2025.11.07
2. Arrays & Structures (2) - 활용  (0) 2025.11.06

+ Recent posts