SyntaxHighlighter.all();

안녕하세요 ㅎㅎ 


많이 사용하는 자료구조중 하나인 tree 구조의 순회법인 이진탐색을 이용해서 메모장을 만들어 보았습니다.



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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
// 이진 탐색 트리를 이용한 메모 저장 프로그램.
#include <stdio.h>
#include <stdlib.h> // malloc
#include <string.h> // srcmp
#include <conio.h>  // _getch()
#define MAX_NAME 50   // 최대 제목 길이 50
#define MAX_TEXT 300  // 최대 내용 길이 300
 
/** 메모 데이터 정의(데이터노드) **/
typedef struct DataType
{
    char Name[MAX_NAME]; // 메모의 제목
    char Text[MAX_TEXT]; // 메모의 내용
}DataType;
 
/** 메모장 구조 정의(트리) **/
typedef struct MyMemo {
    DataType Memo;
    struct MyMemo* left;
    struct MyMemo* right;
}MyMemo;
 
/** 문자열 비교 함수 **/
int Compare(DataType A, DataType B) //strcmp 를 한번에 할수 없기 때문에 비교결과를 반환하는 함수를 만듦.
{
    return strcmp(A.Name, B.Name); // 각 문자열의 아스키코드 값을 비교
}
 
/** 메모 삽입 함수 **/
void AddMemo(MyMemo** Root, DataType Memo)
{
    MyMemo* Current = (*Root); // 현재노드. 처음엔 루트를 넣음
    MyMemo* Parent = NULL;     // 부모노드
    MyMemo* NewNode = NULL;    // 새로운 노드
 
    while (Current != NULL) // 자식이 없는 노드를 찾는 알고리즘
    {
        if (Compare(Memo, Current->Memo) == 0)
        {
            printf("  > 메모 생성 실패. 동일한 제목이 존재합니다.\n");
            return;
        }
        Parent = Current;
        if (Compare(Memo, Current->Memo) < 0//작으면 왼쪽
            Current = Current->left;
        else
            Current = Current->right;  // 크면 오른쪽
    }
 
    NewNode = (MyMemo*)malloc(sizeof(MyMemo)); // 새로운 노드 생성!
    if (NewNode == NULL)
        return;
    NewNode->Memo = Memo;
    NewNode->left = NULL;
    NewNode->right = NULL;
 
    if (Parent != NULL) // 위 알고리즘에서 부모를 찾은 경우
    {
        if (Compare(Memo, Parent->Memo) < 0)
            Parent->left = NewNode;
        else
            Parent->right = NewNode;
    }
    else // 부모노드를 못찾은 경우는 새 노드가 루트가 된다.
        *Root = NewNode;
}
 
/** 메모 삭제 함수 **/
void DeleteMemo(MyMemo** Root, DataType Target) // 아니왜삭제가안돼개짜증나게
{
 
    MyMemo* Current = (*Root);
    MyMemo* Parent = NULL;
    MyMemo* Child;
    MyMemo* succ;
    MyMemo* succ_p;
 
    while (Current != NULL && Compare(Current->Memo, Target) != 0// 타켓 노드의 바로 위까지 검색!
    {
        Parent = Current; // 삭제하고자 하는 노드의 부모를 찾는다.
 
        if (Compare(Current->Memo, Target) < 0// 노드가 비교대상 보다 작으면 -1, 크면 1
            Current = Current->right;
        else
            Current = Current->left;
    }
    if (Current == NULL) {// 예외
        //printf(" :: 메모가 존재하지 않습니다!\n\n");
        return;
    }
 
    // 자식 노드가 없는 경우 -> Parent 는 Current 의 부모노드이다.
    if ((Current->left == NULL) && (Current->right == NULL)) //and연산 -> 지우고자 하는 Current 노드의 자식이 없는 경우.
    {
        if (Parent != NULL)
        {
            if (Parent->left == Current)
                Parent->left = NULL;
            else
                Parent->right = NULL;
        }
        else // 부모 노드가 없으므로 루트노드이다.
            *Root = NULL;
    }
 
    //하나의 자식 노드가 있는 경우
    else if ((Current->left == NULL) || (Current->right == NULL)) //or연산
    {
        if (Current->left != NULL) // 왼쪽, 오른쪽 노드 중 존재하는 노드를 자식으로 대입.
            Child = Current->left;
        else
            Child = Current->right;
 
        if (Parent != NULL)
        {
            if (Parent->left == Current) // 현재 노드의 자식을 부모에게 연결한다.
                Parent->left = Child;
            else
                Parent->right = Child;
        }
        else
            *Root = Child; // 부모가 없는 경우 자식이 루트로 된다.
    }
 
    // 자식이 2개인 경우. 
    else
    {
        succ_p = Current;
        succ = Current->right;
 
        while (succ->left != NULL)
        {
            succ_p = succ;
            succ = succ->left;
        }
        if (succ_p->left = succ)
            succ_p->left = succ->right;
        else
            succ_p->right = succ->right;
 
        Current->Memo = succ->Memo;
        Current = succ;
    }
    printf("\n * ─────────────────── *\n");
    printf(" :: %s > 삭제완료 \n\n", Current->Memo.Name);
    free(Current); // 노드 공간 반환.
}
 
/** 전체 메모 출력(제목만 출력됨) **/
int PrintMemo(MyMemo* Root)
{
    MyMemo* Current = Root;
    if (Current != NULL)
    {
        printf(" > %s\n", Current->Memo.Name); // 전위순회
 
        if (Current->left != NULL)
            PrintMemo(Current->left);
        if (Current->right != NULL)
            PrintMemo(Current->right);
    }
    else
    {
        printf(" > 메모가 존재하지 않습니다!\n\n");
        return 0;
    }
    return 1;
}
 
/** 전위 출력**/
void Preorder(MyMemo* Root)
{
    MyMemo* Current = Root;
    if (Current != NULL)
    {
        printf(" > %s\n", Current->Memo.Name);
        Preorder(Current->left);
        Preorder(Current->right);
    }
}
/** 중위 출력**/
void Inorder(MyMemo* Root)
{
    MyMemo* Current = Root;
    if (Current != NULL)
    {
        Preorder(Current->left);
        printf(" > %s\n", Current->Memo.Name);
        Preorder(Current->right);
    }
}
/** 후위 출력**/
void Postorder(MyMemo* Root)
{
    MyMemo* Current = Root;
    if (Current != NULL)
    {
        Preorder(Current->left);
        Preorder(Current->right);
        printf(" > %s\n", Current->Memo.Name);
    }
}
 
/** 메모 검색(제목입력 -> 본문출력) **/
MyMemo* SerchMemo(MyMemo* Root, DataType Target)
{
    MyMemo* Current = Root;
 
    if (Root = NULL)
        return Root;
 
    while (Current != NULL)
    {
        switch (Compare(Current->Memo, Target))
        {
        case 1:
            Current = Current->left; //노드 값이 더 크면 왼쪽.
            break;
        case 0:
            return Current;
            break;
        case -1:
            Current = Current->right; // 노드값이 더 작으면 오른쪽.
            break;
        }
    }
}
 
/** 메모 개수 카운트 **/
int CountMemo(MyMemo* Root)
{
    MyMemo* Current = Root;
    int Count = 0;
 
    if (Current != NULL)
        Count = + CountMemo(Current->left) + CountMemo(Current->right);
 
    return Count;
}
 
/** 화면 정리 대기 **/
void CLS()
{
    printf("\n\n 메뉴로 돌아가려면 Enter 입력.");
    _getch(); // Enter 을 입력받으면 화면을 지운다.
    system("cls"); // 화면을 지우는 명령어.
}
 
int main(void)
{
 
    DataType MemoData;   // 메모의 데이터
    MyMemo* Root = NULL; // 트리 생성 
    MyMemo* Temp;        // 메모의 데이터를 임시 저장하는 노드.
    FILE* file;
    int UserSelect, exit = 0// 스위치 변수, 메뉴 종료 변수.
    while (exit != 1)
    {
        fflush(stdin); // 버퍼비움.
        printf(" *────  메모장 ────*\n");
        printf("│    1.메모작성    │\n");
        printf("│    2.메모삭제    │\n");
        printf("│    3.메모검색    │\n");
        printf("│    4.전체메모    │\n");
        printf("│    5.메모개수    │\n");
        printf("│    6.순회출력    │\n");
        printf("│    7.내보내기    │\n");
        printf("│    8.종료        │\n");
        printf(" *─────────────────*\n");
        printf(" :: 명령입력 > ");
        scanf_s("%d"&UserSelect);
        putchar('\n');
        switch (UserSelect)
        {
        case 1// 메모작성
            getchar(); // 버퍼를 비워준다.
            printf(" :: 메모를 작성합니다. \n\n");
            printf(" :: 제목 > ");
            gets(MemoData.Name);
            printf("\n :: 내용 > ");
            gets(MemoData.Text);
            AddMemo(&Root, MemoData);
            printf(" * ─────────────────── *\n");
            printf(" :: 제목 >   [%s]\n\n", MemoData.Name);
            printf(" :: 내용 >   %s", MemoData.Text);
            CLS();
            break;
        case 2// 메모 삭제
            getchar();
            printf("\n :: 메모를 삭제합니다. \n\n");
            if (PrintMemo(Root))
            {
                printf("\n :: 제목 > ");
                gets(MemoData.Name);
                DeleteMemo(&Root, MemoData);
            }
            CLS();
            break;
        case 3// 메모 검색(내용보기)
            getchar();
            if (PrintMemo(Root)) // PrintMemo -> 보여줄 메모가 있으면 1을 반환. 없으면 0을 반환.
            {// 검색 전 모든 메모를 보여준다.
                printf("\n :: 검색할 메모의 제목 입력 > ");
                gets(MemoData.Name);
                Temp = SerchMemo(Root, MemoData);
                if (Temp != NULL) //예외처리 조건문. 함수에서 오류메세지를 빼냄.
                {
                    printf("\n * ────  %s ──── *\n", Temp->Memo.Name);
                    printf(" %s\n\n", Temp->Memo.Text);
                }
            }
            CLS();
            break;
        case 4// 메모 전체 출력
            getchar();
            PrintMemo(Root);
            CLS();
            break;
        case 5// 메모 개수 카운트
            getchar();
            printf(" :: 메모의 개수 > %d", CountMemo(Root));
            CLS();
            break;
        case 6// 출력 순회 변경
            getchar();
            printf(" *───  출력순회 ───*\n");
            printf("  :: 1.전위순회\n");
            printf("  :: 2.중위순회\n");
            printf("  :: 3.후위순회\n");
            printf(" *─────────────────*\n");
            printf(" :: 명령입력 > ");
            scanf("%d"&UserSelect);
            putchar('\n');
            if (UserSelect == 1)
                Preorder(Root);
            else if (UserSelect == 2)
                Inorder(Root);
            else if (UserSelect == 3)
                Postorder(Root);
            else
                printf(" :: 올바른 메뉴를 입력하세요!\n");
            CLS();
            break;
        case 7// 파일 출력
            getchar();
            if (PrintMemo(Root)) 
            {
                printf("\n :: 파일로 만들 메모의 제목 입력 > ");
                gets(MemoData.Name);
                Temp = SerchMemo(Root, MemoData);
                if (Temp != NULL)
                {
                    file = fopen(Temp->Memo.Name, "w");
                    fprintf(file,Temp->Memo.Text);
                    printf("\n :: %s < 저장성공!\n",Temp->Memo.Name);
                    fclose(file);
                }
                else
                    printf(" :: 내용이 없습니다!\n");
            }
            CLS();
            break;
        case 8// 종료
            getchar();
            printf(" :: 프로그램을 종료합니다. \n\n");
            exit = 1;
            return 0;
        default// 예외
            getchar();
            printf(" :: 올바른 메뉴를 입력하세요!\n");
            CLS();
            break;
        }
    }
}
cs

코드는 대부분 주석을 달아놓아서 이해가 안되시는 부분은 없을거라 생각합니다.


제가 공부를 더 해서 코드던져놓기 말고 자료구조에 대해 포스팅하는 기회도 생기면 좋겠습니다.  ㅎㅎ 

반응형

+ Recent posts