티스토리 뷰

자료구조

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

취뽀가자!! 2018. 11. 25. 22:44

원형 연결 리스트

개념

단순 연결리스트는 마지막 노드는 NULL을 가리켰다. 이 마지막 노드를 다시 첫 번째 노드를 가리키게 하면 그게 바로 원형 연결 리스트이다.

여기서 새 노드를 머리에 추가해 보겠다. 그러면 리스트는 다음의 형태가 된다.

이번엔 반대로 꼬리에 추가해보면 다음과 같다.

두 경우를 비교해보면 머리에 추가하든 꼬리에 추가하든 둘 다 2가 저장된 노드를 가리킨다는 것을 알 수 있다. 이러한 특성 때문에 head를 없애고 tail만 둔 변형된 연결 리스트가 나왔다. 형태는 아래와 같다.(보통 원형 연결 리스트라고 하면 변형된 원형 연결 리스트를 뜻함)

여기서 꼬리를 가리키는 포인터 변수는 tail이고, 머리를 가리키는 포인터 변수는 tail->next이다. 이로 인해 머리와 꼬리에 새로운 노드를 추가 할 수 있게 되었다.


원형 연결 리스트의 구현

CLinkedList.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#ifndef __C_LINKED_LIST_H__
#define __C_LINKED_LIST_H__
 
#define TRUE    1
#define FALSE    0
 
typedef int Data;
 
typedef struct _node
{
    Data data;
    struct _node * next;
} Node;
 
typedef struct _CLL
{
    Node * tail;
    Node * cur;
    Node * before;
    int numOfData;
} CList;
 
 
typedef CList List;
 
void ListInit(List * plist);
void LInsert(List * plist, Data data);    //꼬리에 노드를 추가
void LInsertFront(List * plist, Data data);    //머리에 노드를 
 
int LFirst(List * plist, Data * pdata);
int LNext(List * plist, Data * pdata);
Data LRemove(List * plist);
int LCount(List * plist);
 
#endif
cs

CLinkedList.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <stdio.h>
#include <stdlib.h>
#include "CLinkedList.h"
 
void ListInit(List * plist)
{
    plist->tail = NULL;
    plist->cur = NULL;
    plist->before = NULL;
    plist->numOfData = 0;
}
 
void LInsertFront(List * plist, Data data) //두 번째 노드부터는 머리에 추가
{
    Node * newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
 
    if(plist->tail == NULL)  //노드가 아무것도 없을 경우
    {
        plist->tail = newNode;    //tail이 첫 번째 노드를 가리킴
        newNode->next = newNode; //첫 번째 노드는 자기 자신을 가리킴
    }
    else
    {
        newNode->next = plist->tail->next; //노드를 머리에 추가
        plist->tail->next = newNode;    //맨 뒤 노드가 맨 앞 노드를 가리킴
    }
 
    (plist->numOfData)++;
}
 
void LInsert(List * plist, Data data) //노드를 꼬리에 추가
{
    Node * newNode = (Node*)malloc(sizeof(Node));    
    newNode->data = data;
 
    if(plist->tail == NULL
    {
        plist->tail = newNode;
        newNode->next = newNode;
    }
    else 
    {
        newNode->next = plist->tail->next;
        plist->tail->next = newNode;
        plist->tail = newNode; //꼬리를 한칸 앞으로 옮겨줌
    }
 
    (plist->numOfData)++;
}
 
int LFirst(List * plist, Data * pdata)
{
    if(plist->tail == NULL)    // 저장된 노드가 없다면
        return FALSE;
 
    plist->before = plist->tail;    
    plist->cur = plist->tail->next;
 
    *pdata = plist->cur->data;
    return TRUE;
}
 
int LNext(List * plist, Data * pdata)
{
    if(plist->tail == NULL)    // 저장된 노드가 없다면
        return FALSE;
 
    plist->before = plist->cur;
    plist->cur = plist->cur->next;
 
    *pdata = plist->cur->data;
    return TRUE;
}
 
Data LRemove(List * plist)
{
    Node * rpos = plist->cur;
    Data rdata = rpos->data;
 
    if(rpos == plist->tail)    // 삭제 대상을 tail이 가리킨다면
    {
        if(plist->tail == plist->tail->next)    // 그리고 마지막 남은 노드라면
            plist->tail = NULL;
        else
            plist->tail = plist->before;  //tail의 위치를 before로 옮겨줌
    }
 
    plist->before->next = plist->cur->next; //삭제하는 노드의 앞 노드와 삭제하는 노드의 다음 노드를 연결
    plist->cur = plist->before;    //cur의 위치를 before로 옮겨줌
 
    free(rpos);
    (plist->numOfData)--;
    return rdata;
}
 
int LCount(List * plist)
{
    return plist->numOfData;
}
cs


CLinkedListMain.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <stdio.h>
#include "CLinkedList.h"
 
int main(void)
{
    // 원형 연결 리스트의 생성 및 초기화 ///////
    List list;
    int data, i, nodeNum;
    ListInit(&list);
 
    // 리스트에 5개의 데이터를 저장 /////// 
    LInsert(&list, 3);
    LInsert(&list, 4);
    LInsert(&list, 5);
    LInsertFront(&list, 2);
    LInsertFront(&list, 1);
    
    // 리스트에 저장된 데이터를 연속 3회 출력 ///////
    if(LFirst(&list, &data))
    {
        printf("%d ", data);
        
        for(i=0; i<LCount(&list)*3-1; i++)
        {
            if(LNext(&list, &data))
                printf("%d ", data);
        }
    }
    printf("\n");
 
    // 2의 배수를 찾아서 모두 삭제 ///////
    nodeNum = LCount(&list);
 
    if(nodeNum != 0)
    {
        LFirst(&list, &data);
        if(data%2 == 0)
            LRemove(&list);
        
        for(i=0; i < nodeNum-1; i++)
        {
            LNext(&list, &data);
            if(data%2 == 0)
                LRemove(&list);
        }
    }
 
    // 전체 데이터 1회 출력 ///////
    if(LFirst(&list, &data))
    {
        printf("%d ", data);
        
        for(i=0; i<LCount(&list)-1; i++)
        {
            if(LNext(&list, &data))
                printf("%d ", data);
        }
    }
    return 0;
}
cs





---------------------------------------------------

이 글은 열혈 자료구조를 읽고 정리한 글입니다.

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

수식 트리(Expression Tree)의 구현  (0) 2019.03.06
큐(Queue)  (0) 2019.03.06
단순 연결 리스트(2/2)  (0) 2018.11.10
단순 연결 리스트(1/2)  (0) 2018.11.10
하노이타워(재귀적 구현)  (0) 2018.10.03
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함