[자료구조] 연결 리스트: 코딩

·

4 min read

[자료구조] 연결 리스트: 코딩

구조체를 이용하여 연결 리스트를 구현하고 사용해보자


#include <stdio.h>
#include <stdlib.h>

// 연결 리스트의 기본 단위가 되는 node 구조체를 정의한다.
typedef struct node 
{
  // node 안에서 정수형 값이 저장되는 변수를 name으로 지정한다.
  int number;

  // 다음 node의 주소를 가리키는 포인터를 *next로 지정한다.
  struct node *next;
}
node;

int main(void)
{
  // list라는 이름의 node 포인터를 정의한다. 연결 리스트의 가장 첫 번째 node를 가리킬 것이다.
  // 이 포인터는 현재 아무것도 가리키고 있지 않기 때문에 NULL로 초기화한다.
  node *list = NULL;

  // 새로운 node를 위해 메모리를 할당하고 포인터 *n으로 가리킨다.
  node *n = malloc(sizeof(node));
  if (n == NULL)
  {
    return 1;
  }

  // n의 number 필드에 1의 값을 저장한다. `n->number`는 `(*n).number`와 동일한 의미이다.
  // 즉, n이 가리키는 node의 number 필드를 의미하는 것이다.
  // 간단하게 화살표 표시 `->`로 사용할 수 있다. n의 number의 값을 1로 저장한다.
  n->number = 1;

  // n 다음에 정의된 node가 없으므로 NULL로 초기화한다.
  n->next = NULL;

  // 이제 첫번째 node를 정의했기 때문에 list 포인터를 n 포인터로 바꿔준다.
  list = n;

  // 이제 list에 다른 node를 더 연결하기 위해 n에 새로운 메모리를 다시 할당한다.
  n = malloc(sizeof(node));
  if (n == NULL)
  {
    return 1;
  }

  // n의 number와 next의 값을 각각 저장한다.
  n->number = 2;
  n->next = NULL; 

  // list가 가리키는 것은 첫 번째 node이다.
  // 이 node의 다음 node를 n 포인터로 지정한다.
  list->next = n;

  // 다시 한 번 n 포인터에 새로운 메모리를 할당하고 number와 next의 값을 저장한다.
  n = malloc(sizeof(node));
  if (n == NULL)
  {
    return 1;
  }

  n->number = 3;
  n->next = NULL;

  // 현재 list는 첫번째 node를 가리키고, 이는 두번째 node와 연결되어 있다.
  // 따라서 세 번째 node를 더 연결하기 위해 첫 번째 node(list)의
  // 다음 node(list->next)의 다음 node(list->next->next)를 n 포인터로 지정한다.
  list->next->next = n;

  // 이제 list에 연결된 node를 처음부터 방문하면서 각 number 값을 출력한다.
  // 마지막 node의 next에는 NULL이 저장되어 있을 것이기 때문에 이 것이 for 루프의 종료 조건이 된다.
  for (node *tmp = list; tmp != NULL; tmp = tmp->next)
{
  printf("%\n", tmp -> number);
}

  // 메모리를 해제해주기 위해 list에 연결된 node들을 처음부터 방문하면서 free 해준다.
  while (list != NULL)
  {
    node *tmp = list->next;
    free(list);
    list = tmp;
  }
}


생각해보기

연결 리스트의 중간에 node를 추가하거나 삭제하는 코드는 어떻게 작성할 수 있을까?

정답

  1. 노드를 추가하는 경우

    • 추가할 노드의 next포인터를 현재 노드가 가리키는 주소로 설정한다.
    • 현재 노드의 next포인터를 추가할 노드의 주소로 변경한다.
  2. 노드를 삭제하는 경우

    • 삭제할 노드의 이전 노드의 next포인터를 삭제할 노드의 next포인터로 변경한다.
    • 삭제할 노드를 메모리에서 해제한다.


Node를 중간에 추가하는 코드
#include <stdio.h>
#include <stdlib.h>

// Node 구조체 정의
typedef struct node
{
  int number;
  struct node *next;
} node;

// 중간에 노드를 추가하는 함수
void insert_after(node *prev, int value)
{
  // 새로운 노드를 위한 메모리를 할당
  node *n = malloc(sizeof(node));
  if (n == NULL)
  {
    exit(1);
  }

  // 새로운 노드에 값과 다음 포인터를 설정
  n->number = value;
  n->next = prev->next;

  // 이전 노드의 다음 포인터를 새로운 노드로 설정
  prev->next = n;
}

int main(void)
{
  // 초기 연결 리스트 생성
  node *list = malloc(sizeof(node));
  list->number = 1;
  list->next = malloc(sizeof(node));
  list->next->number = 2;
  list->next->next = NULL;

  // 두 번째 노드 뒤에 새로운 노드를 추가
  insert_after(list, 3);

  // 리스트 출력
  for (node *tmp = list; tmp != NULL; tmp = tmp->next)
  {
    printf("%d\n", tmp->number);
  }

  // 메모리 해제
  while (list != NULL)
  {
   node *tmp = list->next;
  free(list);
  list = tmp; 
  }
  return 0;
}


Node를 중간에서 삭제하는 코드
#include <stdio.h>
#include <stdlib.h>

// Node 구조체 정의
typedef struct node 
{
  int number;
  struct node *next;
} node;

// 중간에 노드를 삭제하는 함수
void delete_node(node *prev)
{
  if (prev == NULL || prev->next == NULL)
  {
    return;
  }

  // 삭제할 노드를 가리키는 포인터
  node *temp = prev->next;

  // 이전 노드의 다음 포인터를 삭제한 노드의 다음 노드로 설정
  prev->next = temp->next;

  // 삭제할 노드의 메모리를 해제
  free(temp);
}

int main(void)
{
  // 초기 연결 리스트 생성
  node *list = malloc(sizeof(node));
  list->number = 1;
  list->next = malloc(sizeof(node));
  list->next->number = 2;
  list->next->next = malloc(sizeof(node));
  list->next->next->number = 3;
  list->next->next->next = NULL;

  // 두 번째 노드를 삭제
  delete_node(list);

  // 리스트 출력
  for (node *tmp = list; tmp != NULL; tmp = tmp->next)
  {
    printf("%d\n", tmp->number);
  }

  // 메모리 해제
  while (list != NULL)
  {
    node *tmp = list->next;
    free(list);
    list = tmp;
  }
  return 0;
}