컴퓨터공학 💻 도서관📚

단일 연결 리스트 본문

💯🌊자료구조&알고리즘/C언어

단일 연결 리스트

들판속초록풀 2025. 3. 31. 21:07

* 단일 연결 리스트의 구조

typedef struct Node {               // (정체성 : struct Node)
    int data;          // 데이터 저장   (정체성 : int)
    struct Node* next; // 다음 노드를 가리키는 포인터  (정체성 : struct Node *)
} Node;

 

 

* 단일 연결 리스트의 기본 연산

1.노드 추가(Append)  :  리스트의 끝에 새로운 노드를 추가하는 기능

 

 

2. 노드 삭제(Delete)  :  특정 값을 가진 노드를 삭제하는 기능

 

3. 노드 탐색(Search)  :  특정 값을 가진 노드를 찾는 기능

 

4. 노드 출력(Display)  :  리스트의 모든 노드를 순차적으로 출력하는 기능

 

 

 

* 단일 연결 리스트의 장점과 단점

장점

  • 동적 메모리 할당을 통해 크기를 유동적으로 조절 가능
  • 노드 삽입 및 삭제가 빠름 (배열과 달리 요소를 이동할 필요 없음)

단점

  • 임의 접근(random access)이 불가능하여 탐색 속도가 느림
  • 추가적인 메모리 공간(next 포인터)이 필요

 

 

[ (void) insert_end 함수 (list , data) ]
createnode 함수가 따로 없고 append 함수에서 새 노드를 할당한다

(새 노드)  새 노드를 선언하고 할당하고
(초기화)   바로 초기화화기

(case 1)   if문으로 노드가 없는 경우
                head노드와 new_node 연결해서 새로운 노드 추가하기

(case 2)   temp 노드 만들고 while문으로 끝노드까지 이동한후
                new_node와 연결해서 새로운 노드 추가하기


여기에서는 끝노드에 노드추가를 하는데
중간에 노드를 추가할 때는

코드 순서가 중요하다

 

new_node->next = temp->next;              // 무조건 new_node 포인터를 먼저 연결한다고 생각하면 편하다

temp->next = new_node;


첫번째 위치에 삽입과   중간 위치에 삽입은 무조건 코드가 다를 수 밖에 없다
영향을 받는 노드의 개수부터가 차이가 나기 때문에
2가지 경우는 무조건 따로 분류해야 한다


[ (void) delete 함수 (list, key) ]

(case 1)  노드가 없는 경우 예외처리

(서포터 변수)  도우미 변수 temp, prev 선언 후 초기화

(case 2)    삭제할 노드가 1번째 노드인 경우
                  head가 temp 다음 노드를 가리키게 하고,  temp 메모리 해제

(case 3-1)  삭제할 노드가 2~N번째인 경우
                   while문으로 순회해서 key를 이용해 삭제할 노드 찾기 --> prev에 계속 전 노드를 담아두기
          
(case 4)    삭제할 노드가 없는 경우  -->  return;

(case 3-2)   prev가 temp 다음 노드를 가리키게 하고,  temp 메모리 해제

 

 

단일연결리스트의 1번째 위치 삭제에서는
prev노드가 없기 때문에

head 와 temp 포인로 삭제를 한다


단일연결리스트의  중간 위치의 삭제연산에서는
prev로 연결을 하고
temp는 해제를 위해 찾아야 한다


[ (Node *) search 함수 (list, key) ]

(서포터 변수)   temp 를 head로 초기화

(case 1)   while문으로 temp가  NULL일때까지  temp = temp->next; 로 순회해서 key를 찾으면 temp를 반환

(case 2)   찾는 노드가 없는 경우  return NULL;


[ (void) display 함수 (list) ]

(서포터 변수) temp 를 head 로 초기화

(순회)  while문으로 temp 가  NULL일 때까지 출력하고   temp = temp->next;  로 순회하기

(가독성)  printf("NULL\n");  해서 가독성 높이기

 

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

typedef struct Node {     // 노드 구조체
    int data;
    struct Node* next;
} Node;

typedef struct LinkedList {   // 단일 연결 리스트 구조체
    Node* head;                // head 노드
} LinkedList;

void insert_end(LinkedList* list, int data) {
    Node* new_node = (Node*)malloc(sizeof(Node));   // 새 노드 메모리 동적할당
    new_node->data = data;
    new_node->next = NULL;

    if (list->head == NULL) {     // 노드가 없을 때
        list->head = new_node;
        return;
    }
    
    Node* temp = list->head;
    while (temp->next != NULL) {   // 끝노드까지 이동
        temp = temp->next;
    }
    temp->next = new_node;
}

void delete(LinkedList* list, int key) {
    if (list->head == NULL) return; // 리스트가 비었을 때 예외 처리 (방어코드)
    
    Node* temp = list->head;   // temp를 head노드로 초기화
    Node* prev = NULL;
    
    if (temp != NULL && temp->data == key) {  // 삭제할 노드가 리스트의 첫 번째 노드일 때(head 노드일 때)
        list->head = temp->next;  // 리스트의 head를 temp->next로 이동 -> 즉, head를 두 번째 노드로 변경
        free(temp);
        return;
    }
    
    while (temp != NULL && temp->data != key) {  // 삭제할 노드가 2~N번째 노드일 때
        prev = temp;          // prev에 temp 담아두기
        temp = temp->next;    // 이 코드가 prev = temp; 다음에 나와야 함
    }
    
    if (temp == NULL) return;  // 삭제할 노드가 없는 경우
    
    prev->next = temp->next;
    free(temp);
}

Node* search(LinkedList* list, int key) {
    Node* temp = list->head;
    while (temp != NULL) {
        if (temp->data == key) {
            return temp;
        }
        temp = temp->next;
    }
    return NULL;
}

void display(LinkedList* list) {
    Node* temp = list->head;
    while (temp != NULL) {
        printf("%d -> ", temp->data);
        temp = temp->next;
    }
    printf("NULL\n");
}

int main() {
    LinkedList list;
    list.head = NULL;

    append(&list, 1);
    append(&list, 2);
    append(&list, 3);
    display(&list);  // 1 -> 2 -> 3 -> NULL
    
    delete(&list, 2);
    display(&list);  // 1 -> 3 -> NULL
    
    Node* found = search(&list, 3);
    if (found) {
        printf("노드 %d 찾음\n", found->data);
    } else {
        printf("노드 찾을 수 없음\n");
    }
    
    return 0;
}

 


 

void append(LinkedList* list, int data) {
    Node* new_node = (Node*)malloc(sizeof(Node));   // 새 노드 메모리 동적할당
    new_node->data = data;
    new_node->next = NULL;

    if (list->head == NULL) {     // 1번째 노드일때
        list->head = new_node;
        return;
    }
    
    Node* temp = list->head;
    
    while (temp->next != NULL) {   // 끝노드까지 이동
        temp = temp->next;
    }
    temp->next = new_node;
}

 

 


 

 

궁금증 : new_node 는 메모리를 할당할 때 동적할당으로 밖에 못하나?  다른 방법은 없나?

 

 


 

더 완성도 있는 코드를 작성하려면~

 

'💯🌊자료구조&알고리즘 > C언어' 카테고리의 다른 글

이중연결리스트 (C언어)  (0) 2025.04.04
하노이 탑 (재귀함수)  (0) 2025.03.25
재귀함수 (C언어)  (0) 2025.02.12
Comments