1) 이중 연결 리스트(doubly linked list) 구조
- 연결 포인터 2개 사용(prev : 이전 연결 포인터, next : 다음 연결 포인터)
- HEAD 노드는 next 연결 포인터만 사용하며, 첫 번째 노드를 가리킴
- 첫 번째 노드는 next 연결 포인터만 사용하며, 두 번째 노드를 가리킴
- 마지막 노드는 prev 연결 포인터만 사용
2) 사용 라이브러리
헤더파일 | 설명 | 사용함수 |
---|---|---|
<stdio.h> | 표준 입출력 라이브러리 | printf(), scanf_s(), getchar() |
<stdlib.h> | 표준 라이브러리(동적 메모리 관리, 난수발생 등 | calloc(), free() |
<string.h> | 문자열 라이브러리 | strcmp() |
헤더파일 | 설명 | 사용 함수 |
---|---|---|
"DLL.h" | 사용자 정의 라이브러리(이중 연결 리스트 구현 | initialize_DLL(), printf_node(), new_node(), append_node(), insert_node(), delete_node(), search_node() |
함수 | 설명 |
---|---|
initailize_DLL() | 이중 연결 리스트의 head 노드 생성 |
print_node() | 이중 연결 리스트의 모든 노드를 화면에 출력 |
new_node() | 새로운 노드 생성 |
append_node() | 새로운 노드를 이중 연결 리스트에 추가 |
insert_node() | 새로운 노드를 이중 연결 리스트에 삽입 |
delete_node() | 이중 연결 리스트에서 노드 삭제 |
search_node() | 이중 연결 리스트에서 노드 검색 |
1) 구현 개요
- 이중 연결 리스트 활용하여 구현
- 파일 저장 및 읽어오기 기능 구현
- 노드의 순차적 검색 기능 구현
- 노드를 수정하는 기능 구현
소스 | 함수 | 설명 |
---|---|---|
read_book() | 파일에서 도서자료를 읽어와 이중 연결 리스트 생성 | |
projectBook.c | write_book() | 이중 연결 리스트를 파일로 저장 |
update_book() | 이중 연결 리스트의 등록, 수정, 삭제, 검색 메뉴 실행 | |
"bookDLL.h" | print_one_node() | 하나의 노드를 화면에 출력 |
1) 이중 연결 리스트를 이용한 회원관리 프로그램을 활용하여 실행화면처럼 수정하시오.
2) 도서관리 프로그램과 동일한 기능을 하도록 수정하시오.
- (1) 회원 자료 파일을 읽어오거나 저장하는 기능 추가
- (2) 회원 자료를 순차적으로 검색하는 기능 추가
- (3) 회원 정보를 수정하는 기능 추가
enum MAIN_MENU { END, READ, LIST, UPDATE, WRITE };
enum MAIN_MENU main_select;
enum UPDATE_MENU { EXIT, PREV, NEXT, INSERT, MODIFY, DELETE, SEARCH };
enum UPDATE_MENU update_select;
#include "DLLtotal.h"
void read_member();
void update_member();
void write_member();
char member_name[20] ="member.txt";
int main()
{
NODE_t* data = NULL;
initialize_DLL(); // 연결 리스트 생성(head 생성)
while (head != NULL) { // 연결 리스트가 생성되었으면 반복
system("cls"); // 화면 지우기
printf("=======================================================\n");
printf("\t\t 회원관리 프로그램\n");
printf("=======================================================\n");
printf("1 : 회원 자료 읽어 오기\n");
printf("2 : 회원 현황 보기\n");
printf("3 : 회원 관리 하기\n");
printf("4 : 회원 자료 저장 하기\n");
printf("0 : 종료\n");
printf(">> ");
scanf_s("%d", &main_select); // 메뉴선택
getchar();
if (main_select == END) break;
switch (main_select) {
case READ: // 회원 자료 읽어 오기
read_member();
getchar();
break;
case LIST: // 회원 현황 보기
print_node();
getchar();
break;
case UPDATE: // 회원 관리하기
update_member();
break;
case WRITE: // 회원 자료 저장 하기
write_member();
getchar();
break;
}
}
}
void read_member() {
printf("읽어올 회원 자료 파일 이름을 입력하세요 : ");
scanf_s("%s", member_name, sizeof(member_name));
getchar();
NODE_t* data;
FILE* file;
if (fopen_s(&file, member_name, "rt") == 0) { // 파일을 읽기 모드로 오픈
int count = 0;
while (1) {
data = (NODE_t*)calloc(1, sizeof(NODE_t));
int result = fscanf_s(file, "%s %d %s", data->name, sizeof(data->name), &data->age, data->phone, sizeof(data->phone));
if (result != EOF) { // 읽기 성공시 데이터 개수, 실패시 -1(EOF)
append_node(data);
count++;
printf("%s %d %s\n", data->name, data->age, data->phone);
}
else break;
}
fclose(file);
printf("[ %d ]개의 데이터를 읽었습니다.\n", count);
}
else {
printf("%s 파일을 읽어오지 못했습니다.\n", member_name);
}
}
void write_member() {
NODE_t* data = head;
FILE* file;
if (fopen_s(&file, member_name, "wt") == 0) { // 파일을 쓰기모드로 오픈
int count = 0;
while (data->next != NULL) {
data = data->next;
fprintf(file, "%s %d %s\n", data->name, data->age, data->phone);
count++;
}
fclose(file);
printf("[ %d ]개의 데이터를 저장하였습니다.\n", count);
}
else {
printf("%s 파일을 저장하지 못했습니다.\n", member_name);
}
}
void update_member() {
NODE_t* data;
current = head->next; // 첫번째 회원을 현재 화면에 보는 회원으로 설정
while (head != NULL) { // 연결 리스트가 생성되었으면 반복
system("cls"); // 화면 지우기
printf("=======================================================\n");
printf("\t\t 회원 관리 하기\n");
printf("=======================================================\n");
if (current != NULL) print_one_node(current); // 현재 회원 화면 출력
printf("1 : 이전 회원\n");
printf("2 : 다음 회원\n");
printf("3 : 회원 등록\n");
printf("4 : 회원 수정\n");
printf("5 : 회원 삭제\n");
printf("6 : 회원 검색\n");
printf("0 : 주 메뉴로 돌아가기\n");
printf(">> ");
scanf_s("%d", &update_select); // 메뉴선택
if (update_select == EXIT) break;
if (current == NULL) { // 출력할 노드가 없으면 "이전","다음","수정","삭제", "검색" 기능 선택안되게 함.
switch (update_select) { // "등록", "주메뉴로 돌아가기"는 가능
case PREV:
case NEXT:
case MODIFY:
case DELETE:
case SEARCH:
continue;
}
}
switch (update_select) {
case PREV: // 이전 회원
if (current->prev != NULL) current = current->prev;
break;
case NEXT: // 다음 회원
if (current->next != NULL) current = current->next;
break;
case INSERT: // 회원 등록
data = new_node(); // 새로운 노드 입력받아서 생성
if (head->next == NULL) append_node(data); // 첫노드 추가
else insert_node(data); // 새로운 노드 삽입
current = data;
break;
case MODIFY: // 회원 수정
data = new_node(); // 새로운 노드 입력받아서 생성
current->age = data->age;
strcpy_s(current->phone, sizeof(current->phone), data->phone);
free(data);
break;
case DELETE: // 회원 삭제
delete_node();
break;
case SEARCH: // 회원 검색
search_node();
break;
}
}
}
---------------------------------------------------------------------
#pragma once
#includ<stdio.h>
#includ<stdlib.h>
#includ<string.h>
typedef struct MEMBER {
char name[20];
int age;
char phone[20];
struct MEMBER* prev; // 이전 노드 연결 포인터
struct MEMBER* next; // 다음 노드 연결 포인터
} NODE_t;
NODE_t* head; // 연결 리스트의 head
NODE_t* current; // 현재 화면에 표시되는 노드
void initialize_DLL() { // head 노드 생성
head = (NODE_t*)calloc(1, sizeof(NODE_t));
if (head == NULL) {
printf("이중 연결 리스트를 생성하지 못했습니다!!\n");
getchar();
}
}
void print_node() { // 이중 연결 리스트 전체 출력
NODE_t* p = head;
if (p->next != NULL) {
printf("=======================================================\n");
printf("이름\t\t나이\t전화번호\n");
printf("=======================================================\n");
do {
p = p->next;
printf("%-10s\t%4d\t%-s\n", p->name, p->age, p->phone);
} while (p->next != NULL);
printf("=======================================================\n");
}
else {
printf("출력할 자료가 없습니다.\n");
}
}
void print_one_node(NODE_t* data) { // 하나의 노드만 출력
if (data != NULL) {
printf("=======================================================\n");
printf("%10s [ %s ]\n", "이름", data->name);
printf("%10s [ %d ]\n", "나이", data->age);
printf("%10s [ %s ]\n", "전화번호", data->phone);
printf("=======================================================\n");
}
}
NODE_t* new_node() { // 데이터 생성
NODE_t* data = (NODE_t*)calloc(1, sizeof(NODE_t));
if (data != NULL) {
switch (update_select) {
case INSERT: // 회원 등록인 경우에만 회원 이름을 입력받음.
printf("회원 이름을 입력하세요 : ");
scanf_s("%s", data->name, sizeof(data->name));
case MODIFY: // 회원 수정인 경우에는 회원 이름을 입력받지 않음
printf("나이를 입력하세요 : ");
scanf_s("%d", &data->age);
printf("전화번호를 입력하세요 : ");
scanf_s("%s", data->phone, sizeof(data->phone));
break;
}
}
else {
printf("메모리 할당 실패!\n");
getchar();
}
return data;
}
void append_node(NODE_t* data) { // 데이터 추가
NODE_t* p = head;
while (p->next != NULL)
p = p->next;
p->next = data;
if (p != head) data->prev = p; // 노드가 하나도 없을 경우에는 실행 안됨. 처음 추가되는 노드인 경우에는 NULL
}
void insert_node(NODE_t* data) { // 데이터 삽입
NODE_t* p = head;
while (p->next != NULL) { // 현재 위치 다음으로 삽입
p = p->next;
if (p == current) break;
}
if (p == head) { // 첫노드로 삽입하는 경우
data->next = p->next;
data->next->prev = data;
p->next = data;
}
else if (p->next == NULL) { // 마지막노드로 삽입하는 경우
data->prev = p;
p->next = data;
}
else { // 중간 노드로 삽입하는 경우
data->next = p->next;
data->next->prev = data;
p->next = data;
data->prev = p;
}
}
void delete_node() { // 데이터 삭제
NODE_t* p = current;
if (current->next != NULL) current = current->next; // 현재 위치를 다음 노드로 설정
else {
if (current->prev != NULL) current = current->prev; // 현재 위치를 이전 노드로 설정
else current = NULL; // 현재 위치를 설정 안함.(연결리스트에 노드가 없는 경우)
}
if (p->next == NULL && p->prev == NULL) { // 노드가 한개인 경우
head->next = NULL;
}
else if (p->next == NULL && p->prev != NULL) { // 마지막 노드이면
p->prev->next = NULL;
}
else if (p->prev == NULL && p->next != NULL) { // 처음 노드이면
p->next->prev = NULL;
head->next = p->next;
}
else { // 중간 노드이면
p->next->prev = p->prev;
p->prev->next = p->next;
}
free(p);
}
void search_node() { // 데이터 검색
char name[20];
printf("검색하고자 하는 이름을 입력하세요 : ");
scanf_s("%s", name, sizeof(name));
getchar();
NODE_t* p = head;
while (p->next != NULL) {
p = p->next;
if (!strcmp(p->name, name)) { // 이름으로 해당 노드 찾기
current = p; // 현재 찾은 노드를 현재 노드로 설정
break;
}
}
}
<Result>