[자료구조] C로 연결 리스트 Linked List 구현하기

 
etc-image-0

서론

포인터를 적용해보고자 연결 리스트를 구현해보았습니다. 구현하면서 흐릿했던 포인터의 개념이 약간은 명확해졌습니다. 코드는 사람마다 다르기 때문에 흐름만 이해하고 직접 구현해보는 것을 추천합니다. (포인터, 구조체, 동적할당 개념 필요)

🔗 연결 리스트

데이터를 순서대로 저장하는 자료구조 중 하나입니다. 연결 리스트는 각각의 노드가 데이터와 다음 노드의 주소를 가지고 있는 방식으로 구현됩니다. 연결 리스트는 배열과 달리, 데이터가 메모리 상에서 연속적으로 위치하지 않기 때문에 삽입, 삭제가 용이하고 데이터 크기를 동적으로 조절할 수 있습니다.

삽입

int insertion(nval) {
  struct node *newNodeptr = (struct node *)malloc(sizeof(struct node));
  newNodeptr->data = nval;
  newNodeptr->nextNode = NULL;
  if (headptr == NULL) {
    headptr = newNodeptr;
  } else {
    tailptr->nextNode = newNodeptr;
  }
  tailptr = newNodeptr;
  return 0;
};
etc-image-1
  1. 새로운 노드가 들어갈 수 있도록 struct node 타입 크기만큼의 메모리를 할당합니다.
  2. newNodeptr이 가리키는 노드의 data에 nval을 대입합니다. newNodeptr이 가리키는 노드의 nextNode에 NULL을 대입합니다.
  3. 현재 빈 연결리스트라면 headptr이 새 노드를 가리키도록 합니다.
    아니라면 tailptr가 가리키는 노드의 nextNode가 newNodeptr가 가리키는 곳을 가리키게 합니다.
  4. tailptr가 newNodeptr이랑 같은 곳을 가리키게 합니다.(새 노드)

삭제

int deletion(dval) {
  curptr = headptr;
  struct node *prevptr = NULL;
  while (curptr != NULL) {
    if (curptr->data == dval) {
      if (prevptr == NULL) {
        headptr = curptr->nextNode;
        free(curptr);
        return 0;
      }
      prevptr->nextNode = curptr->nextNode;
      free(curptr);
      return 0;
    } else {
      prevptr = curptr;
      curptr = curptr->nextNode;
    }
  }
  printf("%d를 가진 노드가 없습니다.", dval);
  return 0;
};
etc-image-2
  1. curptr이 headptr과 같은 곳을 가리키게 합니다.
  2. prevptr 포인터 변수를 선언합니다.
  3. curptr이 NULL이 될 때까지 노드를 이동하면서 삭제하고 싶은 값을 가진 노드를 찾습니다.
  4. 삭제할 노드를 찾았을 때,
    만약 그 노드가 첫번째 노드라면 headptr이 다음 노드를 가리키게 하고 찾은 노드에 할당된 메모리를 해제합니다.
    만약 그 노드가 첫번째 노드가 아니라면 prevptr이 curptr과 같은 곳을 가리키게 하고 curptr을 해제합니다.
  5. 아직 찾지 못했다면 다음 노드를 가리키게 하여 다시 검사합니다.
  6. 전체 리스트를 다 탐색해도 해당 값의 노드가 없는 경우 문구를 출력합니다.

출력

int print_list(void) {
  curptr = headptr;
  printf("연결 리스트: ");
  while (curptr != NULL) {
    printf("%d ", curptr->data);
    curptr = curptr->nextNode;
  }
  printf("\n===============================\n");
  return 0;
};

headptr가 가리키는 곳부터 끝까지 curptr을 옮겨가며 출력합니다.

📄 전체 코드

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

// 노드 구조체 만들기
struct node {
  int data;              
  struct node *nextNode;
};

// 포인터 만들기
struct node *headptr = NULL;
struct node *tailptr = NULL;
struct node *curptr = NULL;

// 새 노드를 삽입하는 함수
int insertion(nval) {
  struct node *newNodeptr = (struct node *)malloc(sizeof(struct node));
  newNodeptr->data = nval;
  newNodeptr->nextNode = NULL;
  if (headptr == NULL) {
    headptr = newNodeptr;
  } else {
    tailptr->nextNode = newNodeptr;
  }
  tailptr = newNodeptr;
  return 0;
};

// 입력받은 값의 노드를 삭제하는 함수
int deletion(dval) {
  curptr = headptr;
  struct node *prevptr = NULL;
  while (curptr != NULL) {
    if (curptr->data == dval) {
      if (prevptr == NULL) {
        headptr = curptr->nextNode;
        free(curptr);
        return 0;
      }
      prevptr->nextNode = curptr->nextNode;
      free(curptr);
      return 0;
    } else {
      prevptr = curptr;
      curptr = curptr->nextNode;
    }
  }
  printf("%d를 가진 노드가 없습니다.", dval);
  return 0;
};

// 연결 리스트를 출력하는 함수
int print_list(void) {
  curptr = headptr;
  printf("연결 리스트: ");
  while (curptr != NULL) {
    printf("%d ", curptr->data);
    curptr = curptr->nextNode;
  }
  printf("\n===============================\n");
  return 0;
};

// 입력값을 받는 함수
int ask() {
  int answer;
  int newval; // 새로 받아오는 입력값(노드의 data 값)
  int delval; // 삭제하고 싶은 값
  // 만약 포인터가 어떠한 노드도 가리키고 있지 않다면
  if (headptr == NULL && tailptr == NULL) {
    printf("리스트가 비어있습니다.\n");
  }
  printf("하고 싶은 동작을 입력하세요.\n");
  printf("1. 삽입 2. 삭제\n");
  scanf("%d", &answer);
  if (answer == 1) {
    printf("추가하고 싶은 값을 입력하세요.\n");
    scanf("%d", &newval);
    insertion(newval);
  } else if (answer == 2) {
    printf("삭제하고 싶은 값을 입력하세요.\n");
    scanf("%d", &delval);
    deletion(delval);
  } else if (headptr != NULL && tailptr != NULL) {
    printf("첫 값: %d, 마지막 값: %d \n", headptr->data, tailptr->data);
  };
  print_list();
  return 0;
};

int main(void) {
  while (1) {
    ask();
  }
}

참고자료

  • <씹어먹는 C언어> - 이재범
  • <윤성우의 열혈 자료구조> - 윤성우

'자료구조' 카테고리의 다른 글

레드 블랙트리(The red black tree): 규칙, 회전, 삽입  (0) 2024.07.15