회원 관리 프로젝트 (이중 연결 리스트)
2022. 3. 10. 10:11ㆍ프로젝트
회원 관리 프로그램을 이중 연결 리스트 구조로 구현했습니다. 기본적으로 회원 정보에 접근할 때 전화번호를 사용했습니다. 이름은 동명이인 문제가 있고 순번은 회원 삽입, 삭제 시 마다 항상 변경되는 문제가 있습니다. 또한 전화번호가 같은 경우는 거의 없기 때문에 검색에 유용합니다.
또한 이중연결리스트를 구성할 때 첫번째 노드의 prev포인터도 head를 가르키도록 했으며, tail 노드를 추가하여 마지막 노드와도 이중 연결이 가능하도록 했습니다. 나중에 다수의 회원 정보를 시작 부분 , 마지막 부분에 삽입할 수 있도록 하기 위함입니다. 그에 따른 기능은 아직 구현중입니다.
시연 영상
이중 연결리스트는 구조체에 두개의 포인터(prev,next)로 각 데이터를 앞과 뒤를 연결합니다. 헤드 노드와 테일 노드 사이에 데이터들이 삽입되며 데이터 등록, 삽입 ,삭제 기능은 모두 구조체 안의 prev포인터,next포인터를 이용하여 처리됩니다.
main 함수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#include "DLL.h"
int main()
{
//프로그램 실행 시 양식을 출력합니다.
printf("=================================================\n"); // = 이 49개입니다.
printf("\t\t회원관리 프로그램\t\t\n");
printf("=================================================\n");
New_initialize_DLL(); //이중 연결 리스트를 초기화합니다.
New_print_Guide(); // 회원 관리 기능 안내 문구가 출력됩니다. 사용자의 입력에 따라 기능이 구현됩니다.
return 0;
}
|
cs |
DLL.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
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
|
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//프로그램 기능들을 작동시키는 상수를 열거형으로 정의합니다.
enum SELECTOR
{
END, APPEND, INSERT, DELETE, SEARCH, PRINT, PRINTN, CHECK
}selector;
//회원 삽입 시 위치를 지정해주는 상수를 열거형으로 정의합니다.
enum INSERT_POSITION
{
BEFORE, AFTER
}insert_position;
//회원 정보 구조체를 정의합니다. 이중 연결 리스트이기 때문에 포인터는 prev, next 두개입니다.
typedef struct MEM
{
char name[20];
int age;
char phone[20];
struct MEM* prev;
struct MEM* next;
}NODE_t;
//이중 연결 리스트에서 head(시작점)과 tail(끝점)을 포인터로 선언합니다. 이 사이에 회원 정보들이 연결됩니다.
NODE_t* head;
NODE_t* tail;
//head와 tail에 메모리 할당 및 서로 연결합니다. head는 next, tail은 prev만 연결됩니다.
void New_initialize_DLL()
{
head = (NODE_t*)calloc(1, sizeof(NODE_t)); //메모리 할당 및 초기화
tail = (NODE_t*)calloc(1, sizeof(NODE_t));
head->next = tail; //head와 tail 연결
tail->prev = head;
if (head == NULL || tail == NULL)//메모리 할당 실패 시 실패 메세지 출력
{
printf("head,tail Node 메모리 할당 실패\n");
}
else // 성공 여부 확인이 필요없으면 지워주세요.
{
printf("head,tail Node 메모리 할당 성공\n");
}
}
NODE_t* new_Node() //회원 정보가 들어갈 메모리를 할당하고 내용을 입력한 뒤 그 주소를 반환하는 함수
{
//인자에 메모리 할당 실행
NODE_t* ptr = (NODE_t*)calloc(1, sizeof(NODE_t));
if (ptr == NULL) // 메모리 할당에 실패하면 NULL을 반환합니다.
{
printf("new Node 메모리 할당 실패\n");
return NULL;
}
else // 성공 여부 확인이 필요없으면 지워주세요.
{
printf("new Node 메모리 할당 성공\n");
}
//리스트 1개를 생성하자마자 정보를 입력합니다.
printf("이름을 입력하세요:");
scanf_s("%s", ptr->name, sizeof(ptr->name));
printf("나이를 입력하세요:");
scanf_s("%d", &ptr->age);
printf("전화번호를 입력하세요:");
scanf_s("%s", ptr->phone, sizeof(ptr->phone));
// 입력한 정보를 확인하도록 입력 내용을 바로 출력합니다.
printf("입력하신 정보를 확인해주세요.\n");
printf("===============================================================\n"); // = 이 63개입니다.
printf("이름:[%s]\t나이:[%d]\t전화번호:[%s]\n", ptr->name, ptr->age, ptr->phone);
printf("===============================================================\n");
return ptr; // 회원 정보가 들어있는 메모리의 포인터를 반환합니다.
}
void New_append_Node(NODE_t* data) //회원 정보들을 연결시켜주는 함수. prev와 next를 이용해 연결합니다.
{
NODE_t* ptr = head;
while (ptr->next != tail) // head부터 시작하여 그 안의 next포인터의 값이 tail의 주소일때까지 ptr이 이동합니다.
{
ptr = ptr->next;
}
ptr->next = data; //위의 검색에서 tail을 만나는 위치에서 next 포인터를 data에 연결합니다.
data->prev = ptr; //data의 prev를 검색 위치에 연결합니다.
data->next = tail;//data의 next는 tail입니다.
tail->prev = data; // tail의prev는 data와 연결됩니다.
}
void New_delete_Node(NODE_t* data) //삭제할 data의 이전, 이후 노드를 연결한 뒤 data 메모리 할당을 해제합니다.
{
data->prev->next = data->next; //data 이전의 next는 data다음의 노드와 연결됩니다.
data->next->prev = data->prev; //data 이후의 prev는 data의 이전 노드와 연결됩니다.
free(data); // data의 메모리 할당을 해제합니다.
}
void New_Connection_check() // 노드, next,prev에 저장된 주소값을 출력해주는 함수
{
NODE_t* ptr = head;
printf("===============================================================\n");
printf("NODE | [ prev ] [ NODEADDRESSS ] [ next ]\n"); //양식 출력
printf("head : [%p] [%p] [%p]\n", head->prev, head, head->next); //head를 따로 출력합니다.
int i = 0;
while (ptr->next != tail) //data에 인덱스를 붙여 출력합니다. 이는 tail전 노드까지 출력됩니다.
{
i++;
ptr = ptr->next;
printf("data%d: [%p] [%p] [%p]\n", i, ptr->prev, ptr, ptr->next);
}
printf("tail : [%p] [%p] [%p]\n", tail->prev, tail, tail->next); //tail을 따로 출력합니다.
printf("===============================================================\n");
}
void New_insert_Node(NODE_t* ptr, NODE_t* data, int x) //회원 정보를 기존 리스트에 추가해주는 함수, ptr이 삽입할 회원 정보, data가 기존 회원 정보입니다.
{
if (x == BEFORE) //x = BEFORE(0)이면 기존 회원 앞에 삽입합니다.
{
ptr->next = data;
ptr->prev = data->prev;
data->prev->next = ptr;
data->prev = ptr;
}
else if (x == AFTER)//x = AFTER(1)이면 기존 회원 뒤에 삽입합니다.
{
ptr->next = data->next;
ptr->prev = data;
data->next->prev = ptr;
data->next = ptr;
}
}
void print_Allnode() //저장된 모든 회원 정보들을 양식에 맞게 출력해주는 함수
{
NODE_t* ptr = head;
int i = 0; //순번을 저장할 변수입니다.
printf("===============================================================\n"); // = 이 63개입니다.
printf("순번\t이름\t나이\t전화번호\n");
printf("===============================================================\n"); // = 이 63개입니다.
while (ptr->next != tail)
{
i++;
ptr = ptr->next;
printf("[%d]\t%s\t%d\t%s\n", i, ptr->name, ptr->age, ptr->phone);
}
printf("===============================================================\n"); // = 이 63개입니다.
}
void print_Node(NODE_t* ptr) //ptr이 가르키는 회원 정보를 출력해주는 함수입니다.
{
if (ptr == head)
{
printf("===============================================================\n"); // = 이 63개입니다.
printf("%s\n", ptr->phone);
printf("===============================================================\n"); // = 이 63개입니다.
}
else
{
printf("===============================================================\n"); // = 이 63개입니다.
printf("%s\t%d\t%s\n", ptr->name, ptr->age, ptr->phone);
printf("===============================================================\n"); // = 이 63개입니다.
}
}
NODE_t* Search_Info(char string[20]) //전화번호를 비교하여 회원을 검색하는 함수입니다. 번호가 일치하면 그 회원 정보의 포인터를 반환합니다.
{
NODE_t* ptr = head;
char temp;
while (ptr->next != NULL)
{
ptr = ptr->next;
temp = strcmp(string, ptr->phone); //회원 정보들을 순차적으로 돌면서 전화번호를 입력값과 비교합니다.
if (temp == 0) //비교 결과가 참이면 그 때의 회원 정보의 주소값을 반환합니다.
{
return ptr;
break;
}
else //비교결과가 거짓이면 반복문을 계속해서 진행합니다.
{
continue;
}
}
return NULL; //tail까지 검색한 후에도 나오지 않는다면 NULL값을 반환합니다.
}
void New_print_Guide() //회원 관리 기능들의 안내문구 출력 및 작동시키는 함수입니다.
{
while (1) //프로그램 종료버튼(0)이 입력되기 전까지 계속해서 반복됩니다.
{
int insert_position = 0; //삽입 함수의 위치 지정값을 입력받을 변수입니다.
char phoneArray[20] = { 0 }; // 회원 정보 검색 함수에서 전화번호를 입력받을 배열입니다.
//각 함수들의 반환값을 받거나 인자로 사용될 포인터를 선언합니다.
NODE_t* append_ptr = NULL; //회원 정보 포인터를 받은 뒤 리스트에 연결하는 함수에 인자로 사용됩니다.
NODE_t* search_ptr = NULL; //회원 검색 후 일치하는 회원 정보의 포인터를 반환받습니다.
NODE_t* delete_ptr = NULL; //회원 삭제 시 사용됩니다.
NODE_t* insert_ptr = NULL; //회원 삽입 시 사용됩니다.
//기능 안내 문구입니다.
printf("1 : 회원 등록\n");
printf("2 : 회원 삽입\n");
printf("3 : 회원 삭제\n");
printf("4 : 회원 검색\n");
printf("5 : 전원 출력\n");
printf("6 : 개별 출력\n");
printf("7 : 연결 체크\n");
printf("0 : 프로그램 종료\n");
printf(">>");
scanf_s("%d", &selector); //기능 선택을 입력받습니다.
if (selector == END) //0 입력 시 무한 루프로부터 빠져나와 main함수가 종료됩니다.
{
printf("프로그램 종료");
break;
}
else
{
switch (selector)
{
default: //0~7 외에 값 입력 시 다시 안내문구가 출력됩니다.
break;
case APPEND:
append_ptr = new_Node(); //회원 정보를 저장할 메모리의 주소를 받습니다.
if (append_ptr != NULL) //할당에 실패하지 않으면 회원 정보를 head부터 연결합니다.
{
New_append_Node(append_ptr);
}
break;
case INSERT: //검색 함수를 이용해 회원 정보의 삽입 위치를 결정합니다.
insert_ptr = new_Node(); //회원 정보를 저장할 메모리의 주소를 받습니다.
printf("삽입하려는 위치의 전화번호를 입력하세요:");
getchar();
gets_s(phoneArray, 20); //검색할 회원의 전화번호를 입력받습니다.
search_ptr = Search_Info(phoneArray); //전화번호를 배열에 저장합니다.
printf("삽입할 위치를 입력하세요:");
scanf_s("%d", &insert_position); //기존 회원의 앞, 뒤에 삽입할지 입력받습니다.
if (search_ptr == NULL) //일치하는 회원이 없으면 오류 메세지를 출력하고 다시 안내문구를 출력합니다.
{
printf("입력하신 정보와 일치하는 고객이 없습니다.\n");
continue;
}
else //기존회원의 앞,뒤에 새 회원을 삽입합니다.
{
New_insert_Node(insert_ptr, search_ptr, insert_position);
break;
}
case DELETE: // 검색함수를 이용해 삭제할 회원 정보를 입력 받습니다.
getchar();
printf("삭제하려는 회원의 전화번호를 입력하세요:");
gets_s(phoneArray, 20);
delete_ptr = Search_Info(phoneArray);
if (delete_ptr == NULL)
{
printf("입력하신 정보와 일치하는 고객이 없습니다.\n");
continue;
}
else
{
printf("다음 회원이 삭제됐습니다.\n"); //삭제하기 전에 삭제되는 회원 정보를 출력합니다.
printf("===============================================================\n"); // = 이 63개입니다.
printf("이름:[%s]\t나이:[%d]\t전화번호:[%s]\n", delete_ptr->name, delete_ptr->age, delete_ptr->phone);
printf("===============================================================\n"); // = 이 63개입니다.
New_delete_Node(delete_ptr);
break;
}
case SEARCH: // 회원 정보 검색 기능입니다.
getchar();
printf("찾으려는 회원의 전화번호를 입력하세요:");
gets_s(phoneArray, 20);
search_ptr = Search_Info(phoneArray);
if (search_ptr == NULL)
{
printf("입력하신 정보와 일치하는 고객이 없습니다.\n");
continue;
}
else
{
printf("===============================================================\n"); // = 이 63개입니다.
printf("이름[%s]\t나이:[%d]\t전화번호:[%s]\n", search_ptr->name, search_ptr->age, search_ptr->phone);
printf("===============================================================\n"); // = 이 63개입니다.
break;
}
case PRINT: //모든 회원 정보를 출력하는 기능입니다.
print_Allnode();
break;
case PRINTN: //검색함수를 이용해 한명의 회원 정보를 출력합니다.
getchar();
printf("찾으려는 회원의 전화번호를 입력하세요:");
gets_s(phoneArray, 20);
search_ptr = Search_Info(phoneArray);
if (search_ptr == NULL)
{
printf("입력하신 정보와 일치하는 고객이 없습니다.\n");
continue;
}
else
{
print_Node(search_ptr);
break;
}
case CHECK: //각 노드간의 연결 상태를 확인하는 기능입니다.
New_Connection_check();
break;
}
}
}
}
|
cs |
'프로젝트' 카테고리의 다른 글
라즈베리파이 CCTV 프로젝트 (0) | 2022.06.09 |
---|