IT개발및프로그래밍/자료구조

포인터와 구조체로 배우는 연결 리스트 기초

devgodmj 2024. 10. 29. 12:16

1. 연결 리스트 기본 구조

연결 리스트는 노드(Node)라는 단위로 구성되며, 각 노드는 데이터와 다음 노드의 주소를 담고 있는 포인터로 구성됩니다. 연결 리스트는 첫 번째 노드부터 순차적으로 링크를 따라가면서 다음 노드로 이동할 수 있습니다. C언어에서는 구조체와 포인터를 활용하여 이러한 연결 구조를 쉽게 구현할 수 있습니다.

 

  • 데이터를 동적으로 관리하는 자료구조
  • 각 노드는 데이터와 다음 노드를 가리키는 포인터(링크)로 구성
  • [데이터, 링크]의 형태의 노드를 기본 단위로 연결
    • 데이터 필드(data field): 표현하려는 값을 저장
    • 링크 필드(link field): 다음 노드의 주소를 저장
  • 노드의 구조 정의: 자기참조구조 사용
  • 노드 생성: malloc()함수 사용
  • 노드 삭제: free()함수 사용

typedef struct list_node *list_pointer;

struct list_node {
    int data;              // 데이터 필드
    list_pointer link;     // 다음 노드를 가리키는 포인터
};

 

위 구조에서 list_pointer는 list_node 구조체에 대한 포인터 타입으로, 연결 리스트 노드를 가리키는 데 사용됩니다.


2. 단순 연결 리스트 (Singly Linked List)

단순 연결 리스트는 각 노드가 하나의 링크 필드를 통해 다음 노드와 연결된 형태입니다. 마지막 노드의 링크는 NULL을 가리켜 리스트의 끝을 표시합니다. 노드의 삽입과 삭제가 용이하며, 한 방향으로만 이동이 가능합니다.

 

 

1) 단순 연결리스트 노드 삽입

  • 기본 구조체 정의
    먼저, 연결 리스트의 구조체와 포인터를 정의합니다.
#include <stdio.h>
#include <stdlib.h>

typedef struct list_node *list_pointer;

struct list_node {
    int data;              // 데이터 필드
    list_pointer link;     // 다음 노드를 가리키는 포인터
};

 

  • 리스트의 처음에 삽입
    리스트의 처음에 새로운 노드를 삽입하려면, 새 노드를 생성하고 기존 첫 번째 노드를 새 노드의 link로 설정한 후, 헤드 포인터를 새 노드로 갱신해야 합니다. (새로운 노드가 리스트의 첫 번째 노드가 되고, 기존의 첫 번째 노드는 이제 두 번째 노드로 바뀜)
    • 새로운 노드를 동적으로 할당한다.
    • 새로운 노드의 링크 필드를 현재 첫 번째 노드의 주소로 설정한다.
    • 리스트의 머리 포인터(head)를 새로운 노드로 변경한다.
void insert_first(list_pointer *head, int value) {
    list_pointer new_node = (list_pointer)malloc(sizeof(struct list_node));
    new_node->data = value;	// new_node를 생성하여 메모리를 할당받고, 데이터 필드에 value를 저장한다.
    new_node->link = *head;  // new_node->link를 현재 headr가 가리키고 있는 첫 번째 노드로 설정한다.
    *head = new_node;        // head를 new_node로 갱신하여 새 노드를 리스트의 처음에 추가한다.
}
  • 리스트의 중간에 삽입
    리스트의 중간에 삽입하려면, 삽입하려는 위치 바로 이전의 노드를 찾아서 그 노드의 link를 새 노드로 가리키도록 설정하고, 새 노도의 link는 삽입 위치의 다음 노드를 가리키도록 설정합니다.
    • 삽입할 위치 확인
    • 새 노드의 링크를 이전 노드의 다음 노드로 설정
    • 이전 노드의 링크를 새 노드로 연결
void insert_after(list_pointer prev, int value) {

//prev는 새 노드를 삽입하고자 하는 위치의 이전 노드를 가리키는 포인터

    if (prev == NULL) {
        printf("이전 노드가 NULL입니다. 삽입할 수 없습니다.\n");
        return;
    }
    
    list_pointer new_node = (list_pointer)malloc(sizeof(struct list_node)); //new_node 생성
    new_node->data = value;	//value를 데이터로 설정
    new_node->link = prev->link; // new_node->link를 prev->link로 설정하여, 새 노드가 이전 노드의 다음 노드를 가리키게 만든다.
    prev->link = new_node;       // prev->link를 new_node로 갱신하여 새 노드가 이전 노드 다음에 위치하게 한다.
}
  • 리스트의 끝에 삽입
    리스트의 끝에 노드를 삽입하려면, 리스트의 마지막 노드를 찾아서 그 노드의 link를 새 노드로 설정하고, 새 노드의 link를 NULL로 설정하여 끝임을 표시합니다.
    • 리스트의 끝까지 이동하여 마지막 노드를 찾음
    • 새로운 노드를 동적으로 생성하고 데이터 필드를 설정
    • 마지막 노드의 링크 필드를 새로운 노드를 가리키도록 설정
    • 새로운 노드의 링크 필드는 NULL로 설정하여 리스트의 끝임을 나타냄
void insert_last(list_pointer *head, int value) {
    list_pointer new_node = (list_pointer)malloc(sizeof(struct list_node)); //new_node를 생성하고 
    new_node->data = value; //value를 데이터로 저장하며
    new_node->link = NULL;  //link를 NULL로 설정하여 리스트의 끝임을 나타낸다.
    
    if (*head == NULL) {
        *head = new_node;  // 리스트가 비어 있으면 (*head가 NULL), head를 new_node로 설정하여 새 노드를 첫 번째 노드로 삽입
    } else {
        list_pointer temp = *head;
        while (temp->link != NULL) {
            temp = temp->link;  // 마지막 노드를 찾음
        }
        temp->link = new_node;  // 마지막 노드의 링크를 새 노드로 연결
        
        //그렇지 않으면, temp를 사용하여 리스트의 마지막 노드까지 이동한 후, 
        //마지막 노드의 link를 new_node로 설정하여 새 노드를 끝에 추가한다.
    }
}

 

단순 연결리스트 전체 코드 예제

아래는 리스트의 처음, 중간, 끝에 노드를 삽입하고 출력하는 예제 프로그램입니다.

int main() {
    list_pointer head = NULL;  // 초기에는 리스트가 비어 있음

    // 리스트의 처음에 노드 삽입
    insert_first(&head, 10);
    insert_first(&head, 20);

    // 리스트의 끝에 노드 삽입
    insert_last(&head, 30);
    
    // 중간에 노드 삽입 (두 번째 노드 뒤에 삽입)
    insert_after(head->link, 25);

    // 리스트 출력
    print_list(head);  // 예: "The list contains: 20 10 25 30"

    return 0;
}

 

 

2) 단순 연결리스트 노드 삭제

단순 연결 리스트에서 노드를 삭제하기 위해서는 특정 위치의 노드를 찾고, 그 노드를 연결에서 제거하여 이전 노드와 다음 노드를 연결하는 방식으로 이루어집니다. 이때, 삭제된 노드의 메모리는 free( )를 통해 해제해줍니다.

  • 첫 번째 노드를 삭제할 경우
    • 첫 번째 노드의 주소를 임시 포인터에 저장
    • 헤드 포인터를 두 번째 노드로 이동
    • 임시 포인터가 가리키는 첫 번째 노드를 메모리에서 해제
      (삭제할 노드의 메모리를 해제: 메모리 누수를 방지)
#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
    int data;            // 데이터 필드
    struct Node* next;   // 다음 노드를 가리키는 포인터
} Node;

typedef Node* NodePointer;

// 첫 번째 노드 삭제 함수
void delete_first_node(NodePointer *head) {
    if (*head == NULL) {
        printf("리스트가 비어 있습니다.\n");
        return;
    }

    NodePointer temp = *head;   // 첫 번째 노드를 임시로 저장
    *head = (*head)->next;      // 헤드를 두 번째 노드로 이동
    free(temp);                 // 첫 번째 노드 메모리 해제
    printf("첫 번째 노드가 삭제되었습니다.\n");
}

// 리스트 출력 함수
void print_list(NodePointer head) {
    while (head != NULL) {
        printf("%d -> ", head->data);
        head = head->next;
    }
    printf("NULL\n");
}

int main() {
    NodePointer head = (NodePointer)malloc(sizeof(Node));
    head->data = 10;
    head->next = (NodePointer)malloc(sizeof(Node));
    head->next->data = 20;
    head->next->next = (NodePointer)malloc(sizeof(Node));
    head->next->next->data = 30;
    head->next->next->next = NULL;

    printf("삭제 전 리스트: ");
    print_list(head);

    // 첫 번째 노드 삭제
    delete_first_node(&head);

    printf("삭제 후 리스트: ");
    print_list(head);

    // 남은 노드 메모리 해제
    while (head != NULL) {
        NodePointer temp = head;
        head = head->next;
        free(temp);
    }

    return 0;
}

 

삭제 전 리스트: 10 -> 20 -> 30 -> NULL
첫 번째 노드가 삭제되었습니다.
삭제 후 리스트: 20 -> 30 -> NULL

  • 리스트의 중간 부분에 삭제
    • 삭제할 노드의 이전 노드를 찾기
      • 중간에 있는 노드를 삭제하기 위해서는 삭제할 노드의 이전 노드를 알아야 합니다. 이전 노드의 next 필드를 삭제할 노드의 next로 변경하여 리스트에서 제거합니다.
    • 이전 노드의 next 필드를 삭제할 노드의 next로 변경
      • 삭제할 노드의 다음 노드를 연결하여, 중간에 있는 노드를 리스트에서 제외합니다.
    • 삭제할 노드의 메모리를 해제
      • 삭제할 노드가 더 이상 리스트와 연결되어 있지 않으므로 free() 함수를 사용하여 메모리를 해제합니다.
#include <stdio.h>
#include <stdlib.h>

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

typedef Node* NodePointer;

// 중간 노드 삭제 함수 (특정 값을 가진 노드 삭제)
void delete_node(NodePointer *head, int target) {
    if (*head == NULL) {
        printf("리스트가 비어 있습니다.\n");
        return;
    }
    
    NodePointer temp = *head;
    NodePointer prev = NULL;

    // 첫 번째 노드가 삭제 대상인 경우
    if (temp != NULL && temp->data == target) {
        *head = temp->next;  // 헤드를 두 번째 노드로 변경
        free(temp);          // 첫 번째 노드 삭제
        printf("노드 %d가 삭제되었습니다.\n", target);
        return;
    }

    // 삭제할 노드 찾기
    while (temp != NULL && temp->data != target) {
        prev = temp;
        temp = temp->next;
    }

    // 대상 노드가 없는 경우
    if (temp == NULL) {
        printf("노드 %d를 찾을 수 없습니다.\n", target);
        return;
    }

    // 이전 노드의 next를 삭제할 노드의 next로 변경
    prev->next = temp->next;
    free(temp);  // 대상 노드 삭제
    printf("노드 %d가 삭제되었습니다.\n", target);
}

// 리스트 출력 함수
void print_list(NodePointer head) {
    printf("리스트: ");
    while (head != NULL) {
        printf("%d -> ", head->data);
        head = head->next;
    }
    printf("NULL\n");
}

int main() {
    NodePointer head = (NodePointer)malloc(sizeof(Node));
    head->data = 10;
    head->next = (NodePointer)malloc(sizeof(Node));
    head->next->data = 20;
    head->next->next = (NodePointer)malloc(sizeof(Node));
    head->next->next->data = 30;
    head->next->next->next = (NodePointer)malloc(sizeof(Node));
    head->next->next->next->data = 40;
    head->next->next->next->next = NULL;

    printf("삭제 전 리스트:\n");
    print_list(head);

    // 중간에 있는 노드 삭제 (예: 값이 20인 노드)
    delete_node(&head, 20);
    printf("노드 20 삭제 후 리스트:\n");
    print_list(head);

    // 마지막 노드 삭제 (예: 값이 40인 노드)
    delete_node(&head, 40);
    printf("노드 40 삭제 후 리스트:\n");
    print_list(head);

    // 첫 번째 노드 삭제 (예: 값이 10인 노드)
    delete_node(&head, 10);
    printf("노드 10 삭제 후 리스트:\n");
    print_list(head);

    // 남은 노드 메모리 해제
    while (head != NULL) {
        NodePointer temp = head;
        head = head->next;
        free(temp);
    }

    return 0;
}
삭제 전 리스트:
리스트: 10 -> 20 -> 30 -> 40 -> NULL
노드 20가 삭제되었습니다.
노드 20 삭제 후 리스트:
리스트: 10 -> 30 -> 40 -> NULL
노드 40가 삭제되었습니다.
노드 40 삭제 후 리스트:
리스트: 10 -> 30 -> NULL
노드 10가 삭제되었습니다.
노드 10 삭제 후 리스트:
리스트: 30 -> NULL

  • 맨 뒤의 노드를 삭제
    • 리스트가 비어 있는지 확인
      • 리스트가 비어 있으면(즉, head가 NULL이면) 아무 작업도 할 필요가 없습니다.
    • 리스트에 노드가 하나뿐인지 확인
      • head 노드가 곧 삭제할 노드라면, 리스트가 하나의 노드로만 구성되어 있다는 뜻입니다. 이 경우 head를 NULL로 설정하고 해당 노드를 삭제합니다.
    • 리스트에 두 개 이상의 노드가 있는 경우
      • 마지막 노드 이전의 노드(즉, 두 번째 마지막 노드)를 찾아서 해당 노드의 next 필드를 NULL로 설정합니다.
      • 이후 마지막 노드의 메모리를 해제합니다.
#include <stdio.h>
#include <stdlib.h>

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

typedef Node* NodePointer;

// 맨 뒤 노드 삭제 함수
void delete_last_node(NodePointer *head) {
    if (*head == NULL) {
        printf("리스트가 비어 있습니다.\n");
        return;
    }

    // 리스트에 노드가 하나만 있는 경우
    if ((*head)->next == NULL) {
        free(*head);
        *head = NULL;
        printf("리스트에 있던 유일한 노드를 삭제했습니다.\n");
        return;
    }

    // 리스트에 두 개 이상의 노드가 있는 경우
    NodePointer temp = *head;
    while (temp->next->next != NULL) {  // 마지막에서 두 번째 노드까지 이동
        temp = temp->next;
    }

    free(temp->next);   // 마지막 노드 삭제
    temp->next = NULL;  // 마지막 노드의 이전 노드의 링크를 NULL로 설정
    printf("마지막 노드를 삭제했습니다.\n");
}

// 리스트 출력 함수
void print_list(NodePointer head) {
    printf("리스트: ");
    while (head != NULL) {
        printf("%d -> ", head->data);
        head = head->next;
    }
    printf("NULL\n");
}

int main() {
    NodePointer head = (NodePointer)malloc(sizeof(Node));
    head->data = 10;
    head->next = (NodePointer)malloc(sizeof(Node));
    head->next->data = 20;
    head->next->next = (NodePointer)malloc(sizeof(Node));
    head->next->next->data = 30;
    head->next->next->next = NULL;

    printf("삭제 전 리스트:\n");
    print_list(head);

    // 마지막 노드 삭제
    delete_last_node(&head);
    printf("마지막 노드 삭제 후 리스트:\n");
    print_list(head);

    // 다시 마지막 노드 삭제
    delete_last_node(&head);
    printf("마지막 노드 삭제 후 리스트:\n");
    print_list(head);

    // 모든 노드 삭제
    delete_last_node(&head);
    printf("모든 노드를 삭제한 후 리스트:\n");
    print_list(head);

    return 0;
}
삭제 전 리스트:
리스트: 10 -> 20 -> 30 -> NULL
마지막 노드를 삭제했습니다.
마지막 노드 삭제 후 리스트:
리스트: 10 -> 20 -> NULL
마지막 노드를 삭제했습니다.
마지막 노드 삭제 후 리스트:
리스트: 10 -> NULL
리스트에 있던 유일한 노드를 삭제했습니다.
모든 노드를 삭제한 후 리스트:
리스트: NULL

 


3. 원형 연결 리스트 (Circular Linked List)

원형 연결 리스트는 마지막 노드가 다시 첫 번째 노드를 가리키도록 연결되어 원형 형태를 이룹니다. 이러한 구조 덕분에 리스트의 끝에서 다시 처음으로 돌아갈 수 있어, 순환형 자료를 구현할 때 유리합니다. 다만, 원형 연결 리스트는 연결을 관리하기 복잡하며, 탐색 시 끝을 표시하는 NULL이 없어 주의가 필요합니다.

  • 마지막 노드의 링크가 첫 번째 노드(head node)를 가리키는 리스트
  • 한 노드에서 다른 모든 노드로의 접근이 가능
  • 검색할 때 무한루프에 빠지지 않도록 검색종료 시킬 조건을 정해야 함
  • 단점: 앞에 삽입하려면, 맨 뒤 원소까지 찾아가야 함
    • 보완: 시작노드를 맨 뒤 노드로 설정 -> 맨 앞에 삽입 시 편리하다.

원형 연결 리스트 생성 예시

void make_circular_list(list_pointer *head, int data) {
    list_pointer temp = (list_pointer) malloc(sizeof(struct list_node));
    temp->data = data;
    
    if (*head == NULL) {
        *head = temp;
        temp->link = *head;
    } else {
        list_pointer last = *head;
        while (last->link != *head) {
            last = last->link;
        }
        last->link = temp;
        temp->link = *head;
    }
}

 

위 함수는 원형 연결 리스트의 마지막 노드를 첫 번째 노드로 다시 연결하여 순환 구조를 만듭니다.


4. 이중 연결 리스트 (Doubly Linked List)

이중 연결 리스트는 각 노드가 이전 노드와 다음 노드를 가리키는 두 개의 포인터 필드를 가진 구조입니다. 양방향 탐색이 가능하며, 중간 노드의 삽입 및 삭제 시 더 빠르게 작업할 수 있습니다.

  • 헤드노드를 사용하여 연산을 쉽게 한다.
  • 헤드노드: 아무 정보 없이 프로그래밍을 편리하게하기 위해 존재하며 맨 앞 노드보다 앞에, 맨 뒤 노드보다 뒤에 있다고 가정
  • 원형 구조일 수도 있고 아닐 수도 있음
  • 각 노드는 적어도 세 개의 필드를 가짐
    • 왼쪽 링크 필드(llink), 데이터 필드(item), 오른쪽 링크 필드(rlink)

typedef struct d_node {
    int data;               // 데이터 필드
    struct d_node *prev;    // 이전 노드를 가리키는 포인터
    struct d_node *next;    // 다음 노드를 가리키는 포인터
} d_node;

 

1) 이중 연결 리스트에서 노드 삽입

이중 연결 리스트에 노드를 삽입하는 경우, 위치에 따라 다음과 같은 경우로 나뉩니다.

 

  • 리스트의 맨 앞에 삽입
    맨 앞에 새로운 노드를 삽입하는 과정은 다음과 같습니다.
void insert_front(d_node **head, int data) {
    d_node *new_node = (d_node *)malloc(sizeof(d_node));
    new_node->data = data;
    new_node->prev = NULL;
    new_node->next = *head;

    if (*head != NULL) {
        (*head)->prev = new_node;
    }
    *head = new_node;
}

 

  • 설명:
    • new_node를 생성하고 data를 저장합니다.
    • 새 노드의 next를 현재의 head로 설정하고, prev는 NULL로 설정합니다.
    • 기존 첫 번째 노드의 prev를 new_node로 변경합니다(기존 head가 있을 경우).
    • 마지막으로 head를 new_node로 갱신합니다.
  • 리스트의 특정 위치에 삽입
    리스트의 중간에 새로운 노드를 삽입하는 과정입니다.
void insert_after(d_node *node, int data) {
    if (node == NULL) return;

    d_node *new_node = (d_node *)malloc(sizeof(d_node));
    new_node->data = data;

    new_node->next = node->next;
    new_node->prev = node;

    if (node->next != NULL) {
        node->next->prev = new_node;
    }
    node->next = new_node;
}

 

  • 설명:
    • node의 다음에 new_node를 삽입합니다.
    • new_node->next는 node->next를 가리키고, new_node->prev는 node를 가리킵니다.
    • 기존 node->next가 있으면, 그 노드의 prev를 new_node로 연결합니다.
    • 마지막으로 node->next를 new_node로 설정하여 연결을 완성합니다.

2) 이중 연결 리스트에서 노드 삭제

이중 연결 리스트에서 노드를 삭제할 때는 연결을 끊어주고, 메모리를 해제하는 작업이 필요합니다.

  • 특정 노드를 삭제
    삭제할 노드 node가 주어졌을 때, 해당 노드를 삭제하는 함수입니다.
void delete_node(d_node **head, d_node *node) {
    if (*head == NULL || node == NULL) return;

    if (*head == node) {
        *head = node->next;
    }

    if (node->next != NULL) {
        node->next->prev = node->prev;
    }

    if (node->prev != NULL) {
        node->prev->next = node->next;
    }

    free(node);
}
  • 설명:
    • node가 head라면, head를 node->next로 변경합니다.
    • node->next가 NULL이 아니면, node->next->prev를 node->prev로 설정하여 node를 건너뛰도록 합니다.
    • node->prev가 NULL이 아니면, node->prev->next를 node->next로 설정하여 node를 건너뛰도록 합니다.
    • 마지막으로 node의 메모리를 해제합니다.

 

  • 리스트의 맨 뒤 노드를 삭제
    맨 마지막 노드를 삭제하는 함수입니다.
void delete_last(d_node **head) {
    if (*head == NULL) return;

    d_node *temp = *head;
    
    while (temp->next != NULL) {
        temp = temp->next;
    }

    if (temp->prev != NULL) {
        temp->prev->next = NULL;
    } else {
        *head = NULL; // 리스트에 노드가 하나만 있는 경우
    }

    free(temp);
}

 

  • 설명:
    • temp를 통해 마지막 노드까지 이동합니다(temp->next가 NULL인 노드).
    • 마지막 노드의 prev가 NULL이 아니라면, temp->prev->next를 NULL로 설정하여 temp를 리스트에서 제거합니다.
    • 리스트에 노드가 하나뿐이라면 *head를 NULL로 설정합니다.
    • 마지막으로 temp의 메모리를 해제하여 노드를 삭제합니다.

 

예제: 이중 연결 리스트 사용

다음은 이중 연결 리스트를 생성하고, 노드를 삽입 및 삭제하는 예제입니다.

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

typedef struct d_node {
    int data;
    struct d_node *prev;
    struct d_node *next;
} d_node;

// 함수 선언
void insert_front(d_node **head, int data);
void insert_after(d_node *node, int data);
void delete_node(d_node **head, d_node *node);
void delete_last(d_node **head);
void print_list(d_node *head);

int main() {
    d_node *head = NULL;

    insert_front(&head, 10);
    insert_front(&head, 20);
    insert_front(&head, 30);  // 리스트: 30 -> 20 -> 10

    printf("리스트 초기 상태: ");
    print_list(head);

    delete_last(&head);       // 맨 마지막 노드 삭제
    printf("마지막 노드 삭제 후: ");
    print_list(head);

    delete_node(&head, head->next);  // 중간 노드(20) 삭제
    printf("중간 노드 삭제 후: ");
    print_list(head);

    return 0;
}

// 각 함수의 구현은 위 설명과 동일합니다.

 


5. 연결 리스트 기본 기능 구현

연결 리스트의 주요 기능으로는 노드 생성, 노드 삽입, 노드 삭제, 리스트 출력이 있습니다.

 

노드 생성 예제

list_pointer make_node(int data) {
    list_pointer new_node = (list_pointer) malloc(sizeof(struct list_node));
    new_node->data = data;
    new_node->link = NULL;
    return new_node;
}

 

리스트 출력 예제

void print_list(list_pointer ptr) {
    printf("The list contains: ");
    while (ptr != NULL) {
        printf("%4d", ptr->data);
        ptr = ptr->link;
    }
    printf("\n");
}

 

노드 합계와 개수 계산

연결 리스트의 모든 노드를 탐색하며 합계와 개수를 계산할 수 있습니다.

int nodesum(list_pointer ptr) {
    int sum = 0;
    while (ptr != NULL) {
        sum += ptr->data;
        ptr = ptr->link;
    }
    return sum;
}

int nodenumber(list_pointer ptr) {
    int count = 0;
    while (ptr != NULL) {
        count++;
        ptr = ptr->link;
    }
    return count;
}

6. 연결 리스트 실습 예제 프로그램

아래 프로그램은 연결 리스트를 생성하고, 리스트의 데이터를 출력하며, 노드의 합계와 개수를 계산하는 코드입니다.

int main() {
    list_pointer ptr;
    
    // 연결 리스트 생성
    ptr = make_node(100);
    ptr->link = make_node(200);
    ptr->link->link = make_node(300);
    
    // 연결 리스트 출력
    print_list(ptr);
    
    // 노드 합계와 개수 출력
    printf("list안의 data 합: %d\n", nodesum(ptr));
    printf("list안의 node 수: %d\n", nodenumber(ptr));
    
    return 0;
}

 

이 프로그램은 연결 리스트의 생성, 출력, 합계 계산 및 노드 수를 세는 과정을 통해 연결 리스트의 기본 동작을 연습할 수 있도록 구성되어 있습니다.