별의 공부 블로그 🧑🏻‍💻
728x90
728x170

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

 

- 리스트의 마지막 노드의 링크가 첫 번째 노드를 가리키는 리스트.

-> 마지막 노드의 링크 필드가 NULL이 아닌 첫 번째 노드 주소가 되는 리스트.

- 한 노드에서 다른 모든 노드로의 접근이 가능하다는 장점이 있음.

- 노드이 삽입과 삭제가 단순 연결 리스트보다는 용이해짐.

- 삭제나 삽입 시에는 항상 선행 노드의 포인터가 필요함.

- 리스트의 끝에 노드를 삽입하는 연산이 단순 연결 리스트보다 효율적일 수 있음.

 

코드

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

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

typedef int element;
typedef struct ListNode {
    element data;
    struct ListNode *link;
} ListNode;

void error(char *message) {
    fprintf(stderr, "%s\n", message);
    exit(1);
}

// 노드를 동적으로 생성하는 프로그램
ListNode *create_node(element data, ListNode *link) {
    ListNode *new_node;
    new_node = (ListNode *)malloc(sizeof(ListNode));
    if (new_node == NULL) error("메모리 할당 에러");
    new_node->data = data;
    new_node->link = link;
    return(new_node);
}


// 리스트의 항목 출력 (처음 노드의 값부터 출력)
void display(ListNode *head) {
    ListNode *p;
    if (head == NULL) return;

    p = head->link;
    do {
        printf("%d->", p->data);
        p = p->link;
    } while (p != head->link);
}

// phead : 리스트의 헤드 포인터의 포인터
// node : 삽입될 노드

void insert_first(ListNode **phead, ListNode *node) {
    if (*phead == NULL) {            
        *phead = node;
        node->link = node;
    }
    else {
        node->link = (*phead)->link;
        (*phead)->link = node;
    }
}

void insert_last(ListNode **phead, ListNode *node) {
    if (*phead == NULL) {        
        *phead = node;
        node->link = node;
    }
    else {
        node->link = (*phead)->link;
        (*phead)->link = node;
        *phead = node;
    }
}

// 중간에 노드를 삽입
void insert_middle(ListNode **phead, ListNode *pre, ListNode *node) {
    if (*phead == NULL) {
        *phead = node;
        node->link = node;
    }
    else {
        node->link = pre->link;
        pre->link = node;
    }
}

// 리스트 내의 원소를 탐색
ListNode* search(ListNode *head, element x) {
    ListNode *p;
    p = head->link;
    do {
        if (p->data == x) return p;        // 탐색 성공
        p = p->link;
    } while (p != head->link);

    return NULL;        // 탐색 실패
}

// 두 리스트를 연결
ListNode* concat(ListNode *head1, ListNode *head2) {
    ListNode *p1, *p2;
    if (head1 == NULL) return head2;
    else if (head2 == NULL) return head1;
    else {
        p1 = head1->link;            // 시작 노드 주소값 저장
        p2 = head2->link;            
        head1->link = p2;            // 연결
        head2->link = p1;            // 마지막 노드 링크 필드에 첫 번째 노드 주소값 
        
        return head2;
    }
}

// 첫 번째 노드 삭제
void remove_first(ListNode **phead) {
    ListNode* removed;
    if (*phead == NULL) return;                    // 공백 리스트인 경우
    else if (*phead == (*phead)->link) {         // 노드가 하나인 경우
        removed = *phead;                        // 삭제할 노드
        *phead = NULL;                            // 공백리스트로 변경
    }
    else {                                                // 노드가 둘 이상인 경우
        removed = (*phead)->link;                // 시작 노드가 삭제될 노드
        (*phead)->link = removed->link;        // 마지막 노드의 링크 필드에 삭제할 노드 다음의 주소값 저장
    }
    free(removed);
}

// 마지막 노드 삭제
void remove_last(ListNode **phead) {
    ListNode* removed, *pre;                    // pre는 삭제할 노드의 선행자 노드
    if (*phead == NULL) return;                    // 공백 리스트인 경우
    else if (*phead == (*phead)->link) {         // 노드가 하나인 경우
        removed = *phead;                        // 삭제할 노드
        *phead = NULL;                            // 공백리스트로 변경
    }
    else {                                                // 노드가 둘 이상인 경우 (삭제할 노드의 선행자 노드를 찾아야 함)
        pre = (*phead)->link;                        // 시작 노드 주소를 먼저 저장
        while (pre->link != *phead) {            // phead의 선행자 노드 위치 탐색
            pre = pre->link;
        }
        removed = *phead;                        // phead가 삭제할 노드
        pre->link = removed->link;                // 시작 노드이 주소를 저장
        *phead = pre;                                // 선행자 노드가 마지막 노드로 변경    
    }            
    free(removed);
}

// 중간 노드 삭제
void remove_middle(ListNode **phead, ListNode *pre) {
    ListNode* removed;                    
    if (*phead == NULL) return;                    // 공백 리스트인 경우
    if (pre->link == *phead) {                     // 노드가 하나인 경우
        removed = *phead;                        
        pre->link = removed->link;
        *phead = pre;
    }
    else {                                                // 삭제할 노드가 시작 노드이거나 중간 노드인 경우
        removed = pre->link;
        pre->link = removed->link;
    }
    free(removed);
}

// 모든 노드 삭제
void remove_all(ListNode **phead) {
    ListNode* removed, *p;
    if (*phead == NULL) {
        p = (*phead)->link;                // 시작 노드 포인터 저장
        (*phead)->link = NULL;            // 단순 연결리스트로 변환
        while (p != NULL) {
            removed = p;
            printf("%d=>", removed->data);
            p = p->link;
            free(removed);
        }
    }
    printf("\n");
    *phead = NULL;        // 모든 노드 삭제 후 공백 리스트로 변경
}

// 노드 순서 반전
ListNode* reverse(ListNode *head) {
    ListNode *p, *q, *r;
    if (head == NULL || head->link = head) {        // 공백이거나 노드가 하나인 경우
        return head;
    }
    p = head->link;            // 시작 노드 주소 저장
    q = head;                    // q는 역순으로 만들 노드
    while (p != head) {
        r = q;                        // r은 역순으로 된 리스트, r은 q, q는 p를 차례로 따라감
        q = p;
        p = p->link;
        q->link = r;                // q의 링크방향을 변경
    }
    head = head->link;
    p->link = q;
    return head;
}

void main() {
    ListNode *list1 = NULL, *list2 = NULL;
    insert_first(&list1, create_node(10, NULL));
    insert_first(&list1, create_node(20, NULL));
    insert_first(&list1, create_node(30, NULL));
    insert_last(&list1, create_node(40, NULL));
    insert_last(&list1, create_node(50, NULL));
    insert_last(&list1, create_node(60, NULL));
    printf("list1 display--------------------------------------\n");
    display(list1);
    printf("\n");

    insert_middle(&list1, search(list1, 30), create_node(70, NULL));
    insert_middle(&list1, search(list1, 60), create_node(80, NULL));
    insert_middle(&list1, search(list1, 10), create_node(90, NULL));
    printf("list1 display after insert_middle----------------\n");
    display(list1);
    printf("\n");

    remove_first(&list1);
    printf("list1 display after remove_first-----------------\n");
    display(list1);
    printf("\n");

    remove_last(&list1);
    printf("list1 display after remove_last------------------\n");
    display(list1);
    printf("\n");

    remove_middle(&list1, search(list1, 20));            // 중간인 경우
    printf("list1 display after remove_middle(10)----------\n");
    display(list1);
    printf("\n");

    remove_middle(&list1, search(list1, 50));            // 첫 번째 노드인 경우
    printf("list1 display after remove_middle(50)----------\n");
    display(list1);
    printf("\n");

    remove_middle(&list1, search(list1, 40));            // 마지막 노드인 경우
    printf("list1 display after remove_middle(40)----------\n");
    display(list1);
    printf("\n");
    
    list1 = reverse(list1);
    printf("list1 display after reverse-----------------------\n");
    display(list1);
    printf("\n");
    
    insert_last(&list2, create_node(60, NULL));
    insert_last(&list2, create_node(10, NULL));
    insert_last(&list2, create_node(30, NULL));
    insert_last(&list2, create_node(50, NULL));
    printf("list2 display--------------------------------------\n");
    display(list2);
    printf("\n");

    list1 = concat(list1, list2);
    printf("list1 display after concat------------------------\n");
    display(list1);

    remove_all(&list1);
    printf("list1 display after remove_all------------------\n");
    display(list1);
    printf("\n");
}

 

내용 출처 : C언어로 쉽게 풀어쓴 자료구조 (천인국 외 지음, 생능출판사)

728x90
그리드형(광고전용)

'Computer Science > Data Structure' 카테고리의 다른 글

[C] 그래프(Graph)  (0) 2017.06.19
[C] 정렬(Sorting)  (0) 2017.06.18
[C] 우선순위 큐(Priority Queue)  (0) 2017.06.17
[C] 트리(Tree)  (0) 2017.06.01
[C] 큐(Queue)  (0) 2017.05.23
[C] 스택(Stack)  (0) 2017.05.11
[C] 이중 연결 리스트(Doubly Linked List)  (0) 2017.05.06
[C] 단순 연결 리스트(Singly Linked List)  (0) 2017.04.17
⚠️AdBlock이 감지되었습니다. 원할한 페이지 표시를 위해 AdBlock을 꺼주세요.⚠️
starrykss
starrykss
별의 공부 블로그 🧑🏻‍💻


📖 Contents 📖