분류 전체보기
- 오찌는 도찌입니까? 2024.08.02 1
- 오찌도찌 2023.04.20 39
- [C]이중연결리스트를 사용한 전화번호부 - 03 2018.03.30
- [C]이중연결리스트를 사용한 전화번호부 - 02 2018.03.30
- [C]이중연결리스트를 사용한 전화번호부 - 01 2018.03.30
오찌는 도찌입니까?
오찌도찌
오찌기 도찌기 옷도로 돗돗찌
'일기장' 카테고리의 다른 글
| 오찌는 도찌입니까? (1) | 2024.08.02 |
|---|
[C]이중연결리스트를 사용한 전화번호부 - 03
3. 이어서 함수 설명
[ findNode / printNode ]
void findNode(linkedList *L){
node *f = L->head;
int i, num;
printf("찾을 노드 번호를 입력하세요 : ");
scanf(" %d", &num);
if (L->cnt <= 0) {
printf("리스트가 비었음.\n");
returnMain(L);
}
else if (num > L->cnt) {
printf("검색 위치가 리스트의 길이보다 김.\n");
returnMain(L);
}
else {
for (i = 1; i < num; i++)
f = f->next;
printf("%d 번째 노드의 값 - 이름 : %s 전화번호 : %d\n", num, f->name, f->phone);
returnMain(L);
}
}
void printNode(linkedList *L){
node *f = L->head;
printf("리스트\n");
while (f != NULL) {
printf("이름 : %s 전화번호 : %d\n", f->name, f->phone);
f = f->next;
}
printf("\n노드 수 : %d\n", L->cnt);
returnMain(L);
}
- findNode에서도 삽입과 삭제할 때의 경우와 같이 원하는 위치로 찾아가야 한다.
더미노드 f 를 만들고 반복문으로 찾아간 후, 그 값을 출력한다.
- printNode에서는 모든 노드를 한번씩 찾아가서 값을 출력해야 하기 때문에, 리스트의 테일까지 찾아간다.
테일까지 찾아가면서 노드의 값들을 출력한다.
4. 전체 소스 코드
/* Phone Book (use Doubly Linked List) Coder : GGaShu LSW Date : 2018.03.30 Purpose : 이중연결리스트의 활용 */ #include#include #include typedef struct _Node { struct _Node *prev; struct _Node *next; int no; char name[20]; int phone; }node; typedef struct _linkedList { struct _Node *head; struct _Node *tail; int cnt; }linkedList; void printMain(linkedList *L); // 메인 메뉴 출력 void returnMain(linkedList *L); // 메인으로 돌아옴 void inputMenu(linkedList *L); // 메뉴 선택 void inputData(linkedList *L); // 데이터 입력 void Init(linkedList *L); // 리스트 초기화 void createNode(linkedList *L, char *ndata, int pdata, int num); // 노드 생성 void createLastNode(linkedList *L, char *ndata, int pdata); // 안씀 void deleteNode(linkedList *L); // 노드 삭제 void deleteLastNode(linkedList *L); // 안씀 void findNode(linkedList *L); // 노드 검색 void printNode(linkedList *L); // 리스트 출력 void main() { linkedList *L = (linkedList *)malloc(sizeof(linkedList)); Init(L); printMain(L); } void printMain(linkedList *L) { printf("1. 리스트\n"); printf("2. 검 색\n"); printf("3. 삽 입\n"); printf("4. 삭 제\n"); printf("5. 종 료\n"); printf("메뉴를 골라주세요 : "); inputMenu(L); } void returnMain(linkedList *L) { char c; printf("메인으로(Y/y) 종료(N/n) : "); // scanf 그냥 통과되는 문제 (버퍼를 비우자) // 이상하게 fflush(stdin)이 안먹혀서 한칸을 비우고 스캔하는 방법을 사용. scanf(" %c", &c); if (c == 'Y' || c == 'y') { system("cls"); printMain(L); } else if (c == 'N' || c == 'n') exit(1); else { printf("잘못 누름. 다시 입력 : "); returnMain(L); } } void inputMenu(linkedList *L) { int num = 0; scanf("%d", &num); if (num > 5 || num < 1) { printf("1부터 5까지 중에서 고르세요 : "); num = 0; scanf(" %d", &num); } else { switch (num) { case 1: printNode(L); break; case 2: findNode(L); break; case 3: inputData(L); break; case 4: deleteNode(L); break; case 5: exit(1); } } } void inputData(linkedList *L) { char name[20]; int phone, num; printf("순번 이름 전화번호 순으로 입력하세요 : "); scanf(" %d %s %d", &num, name, &phone); createNode(L, name, phone, num); } void Init(linkedList *L) { L->head = NULL; L->tail = NULL; L->cnt = 0; } void createNode(linkedList *L, char *ndata, int pdata, int num) { node *f = L->head; node *newNode = (node *)malloc(sizeof(node)); newNode->no = num; strcpy(newNode->name, ndata); newNode->phone = pdata; int i; if (num <= 0) { printf("삽입 위치가 리스트의 길이보다 짧음.\n"); exit(1); } else if (num == 1) { if (L->head == NULL && L->tail == NULL) { printf("헤드\n"); L->head = newNode; L->tail = newNode; newNode->next = NULL; printf("이름 : %s 전화번호 : %d\n", newNode->name, newNode->phone); L->cnt++; returnMain(L); } else { printf("헤드뺏기2\n"); newNode->next = L->head; L->head = newNode; L->head->next->prev = newNode; newNode->prev = L->head; printf("이름 : %s 전화번호 : %d\n", newNode->name, newNode->phone); L->cnt++; returnMain(L); } } else if (num == (L->cnt) + 1) { printf("테일\n"); newNode->prev = L->tail; L->tail->next = newNode; L->tail = newNode; newNode->next = NULL; printf("이름 : %s 전화번호 : %d\n", newNode->name, newNode->phone); L->cnt++; returnMain(L); } else { if (num > (L->cnt) + 2) { printf("삽입 위치가 리스트의 길이보다 길다\n"); exit(1); } else { for (i = 1; i < num - 1; i++) f = f->next; } newNode->next = f->next; f->next->prev = newNode; newNode->prev = f; f->next = newNode; printf("이름 : %s 전화번호 : %d\n", newNode->name, newNode->phone); L->cnt++; returnMain(L); } } void createLastNode(linkedList *L, char *ndata, int pdata){ // 일단 사용 안함 } void deleteNode(linkedList *L){ node *f = L->head; int i, num; printf("삭제할 노드 번호를 입력하세요 : "); scanf(" %d", &num); if (num <= 0) { printf("삭제 위치가 리스트의 길이보다 짧다\n"); deleteNode(L); } else if (num == 1) { L->head = L->head->next; printf("%d 번째 노드 삭제 완료\n", num); L->cnt--; returnMain(L); } else if (num == L->cnt) { L->tail = L->tail->prev; L->tail->next = NULL; printf("%d 번째 노드 삭제 완료\n", num); L->cnt--; returnMain(L); } else { if (num > (L->cnt) + 1) { printf("삭제 위치가 리스트의 길이보다 길다\n"); deleteNode(L); } else { for (i = 1; i < num; i++) f = f->next; } f->prev->next = f->next; f->next->prev = f->prev; printf("%d 번째 노드 삭제 완료\n", num); L->cnt--; returnMain(L); } } void deleteLastNode(linkedList *L){ // 일단 사용 안함. } void findNode(linkedList *L){ node *f = L->head; int i, num; printf("찾을 노드 번호를 입력하세요 : "); scanf(" %d", &num); if (L->cnt <= 0) { printf("리스트가 비었음.\n"); returnMain(L); } else if (num > L->cnt) { printf("검색 위치가 리스트의 길이보다 김.\n"); returnMain(L); } else { for (i = 1; i < num; i++) f = f->next; printf("%d 번째 노드의 값 - 이름 : %s 전화번호 : %d\n", num, f->name, f->phone); returnMain(L); } } void printNode(linkedList *L){ node *f = L->head; printf("리스트\n"); while (f != NULL) { printf("이름 : %s 전화번호 : %d\n", f->name, f->phone); f = f->next; } printf("\n노드 수 : %d\n", L->cnt); returnMain(L); }
5. 마치며
블로그에 글을 정말 오랬만에 쓴다.
자료구조나 다시 공부해볼 겸 프로그램을 짜고 나서, 갑자기 블로그가 있다는 사실이 생각나 올리게 되었다.
나도 아직 프로그래밍에 미숙하여 많이 공부중이지만 이 포스트가 다른 사람들에게 도움이 되었으면 좋겠다.
끝!
이 아니라 포스팅을 언제 또 다시 할지는 미정...
진짜 끝!
'개발 > C' 카테고리의 다른 글
| [C]이중연결리스트를 사용한 전화번호부 - 02 (0) | 2018.03.30 |
|---|---|
| [C]이중연결리스트를 사용한 전화번호부 - 01 (0) | 2018.03.30 |
[C]이중연결리스트를 사용한 전화번호부 - 02
3. 이어서 함수 설명
[ Init ]
void Init(linkedList *L) {
L->head = NULL;
L->tail = NULL;
L->cnt = 0;
}
- 리스트를 초기화 한다. 아직 아무런 값이 들어있지 않기 때문에 헤드와 테일을 각각 NULL로 초기화 하고, 카운트 값인 cnt는 0으로 초기화 한다.
[ createNode ]
void createNode(linkedList *L, char *ndata, int pdata, int num) {
node *f = L->head;
node *newNode = (node *)malloc(sizeof(node));
newNode->no = num;
strcpy(newNode->name, ndata);
newNode->phone = pdata;
int i;
if (num <= 0) {
printf("삽입 위치가 리스트의 길이보다 짧음.\n");
exit(1);
}
else if (num == 1) {
if (L->head == NULL && L->tail == NULL) {
printf("헤드\n");
L->head = newNode;
L->tail = newNode;
newNode->next = NULL;
printf("이름 : %s 전화번호 : %d\n", newNode->name, newNode->phone);
L->cnt++;
returnMain(L);
}
else {
printf("헤드뺏기2\n");
newNode->next = L->head;
L->head = newNode;
L->head->next->prev = newNode;
newNode->prev = L->head;
printf("이름 : %s 전화번호 : %d\n", newNode->name, newNode->phone);
L->cnt++;
returnMain(L);
}
}
else if (num == (L->cnt) + 1) {
printf("테일\n");
newNode->prev = L->tail;
L->tail->next = newNode;
L->tail = newNode;
newNode->next = NULL;
printf("이름 : %s 전화번호 : %d\n", newNode->name, newNode->phone);
L->cnt++;
returnMain(L);
}
else {
if (num > (L->cnt) + 2) {
printf("삽입 위치가 리스트의 길이보다 길다\n");
exit(1);
}
else {
for (i = 1; i < num - 1; i++)
f = f->next;
}
newNode->next = f->next;
f->next->prev = newNode;
newNode->prev = f;
f->next = newNode;
printf("이름 : %s 전화번호 : %d\n", newNode->name, newNode->phone);
L->cnt++;
returnMain(L);
}
}
- 함수에 사용되는 인자값으로 리스트 L과 이름 데이터 ndata, 핸드폰 번호 데이터 pdata, 노드위치 데이터인 num을 사용한다.
- 이름에 데이터를 넣을 때, strcpy를 사용하는 이유는 name변수가 배열로 선언되어 있기 때문에, 바로 넣을 수 없기 때문.
- 노드를 삽입하고 나면 cnt변수를 하나씩 증가시켜준다.
- else if (num == 1) 부분
-- 첫번째 노드로 삽입하고 싶을 때의 조건문이다.
-- 조건문 두개로 나뉘어져 있는데
[[ L->head == NULL && L->tail == NULL ]] 리스트에 아무것도 없고 처음 삽입할 경우이다.
헤드와 테일을 전부 새로 만든 노드로 지정해주고, 새 노드의 next에 NULL을 넣어준다. 다음 노드가 없기 때문.
-- 아래 else 부분은 리스트에 노드들이 들어 있는데, 첫 노드로 끼워넣고 싶을 때 사용된다.
헤드의 앞에 넣어야 되기 때문에, 새 노드의 next에 헤드를 넣고, 헤드를 새 노드로 바꾼다.
L->head->next 즉 원래 있던 헤드의 다음 노드의 prev에 새 노드를 넣는다.
마지막으로 새 노드의 prev에 헤드를 넣어준다.
- else if (num == (L->cnt) + 1) 부분
-- 마지막 노드로 십입하고 싶을 때의 조건문이다.
-- 새 노드의 prev에 테일을 넣어주고, 원래 테일의 next에 새 노드를 넣는다.
그리고 테일을 새 노드로 바꿔준다. 새 노드의 next엔 NULL을 넣는다. 테일이 리스트의 맨 끝이기 때문.
리스트의 연결 부분을 말로 하나씩 설명하려니 너무 어렵네.. 이후로는 리스트설명 안합니다!!
잘 이해가 안가시면 그림을 직접 그려보세요!! 아니면 다른 블로그 구글링 ㄱㄱ!!
- else 부분
-- 헤드와 테일 이외의 노드를 삽입할 때이다.
-- 넣을 위치를 먼저 찾아가야 하기 때문에, 더미 역할을 할 노드인 f를 선언하면서 리스트의 첫 위치인 헤드로 초기화 해준다.
-- for (i = 1; i < num - 1; i++) f = f->next;
원하는 위치까지 찾아가는 반복문이다.
[ deleteNode ]
void deleteNode(linkedList *L){
node *f = L->head;
int i, num;
printf("삭제할 노드 번호를 입력하세요 : ");
scanf(" %d", &num);
if (num <= 0) {
printf("삭제 위치가 리스트의 길이보다 짧다\n");
deleteNode(L);
}
else if (num == 1) {
L->head = L->head->next;
printf("%d 번째 노드 삭제 완료\n", num);
L->cnt--;
returnMain(L);
}
else if (num == L->cnt) {
L->tail = L->tail->prev;
L->tail->next = NULL;
printf("%d 번째 노드 삭제 완료\n", num);
L->cnt--;
returnMain(L);
}
else {
if (num > (L->cnt) + 1) {
printf("삭제 위치가 리스트의 길이보다 길다\n");
deleteNode(L);
}
else {
for (i = 1; i < num; i++)
f = f->next;
}
f->prev->next = f->next;
f->next->prev = f->prev;
printf("%d 번째 노드 삭제 완료\n", num);
L->cnt--;
returnMain(L);
}
}
- 삭제할 노드의 순번을 사용자에게 입력받기 때문에 함수 자체의 인자값은 리스트 L 하나만 들어간다.
- 노드를 삭제할 때 마다 cnt 값을 1씩 감소시킨다.
- else if (num == 1) 부분
-- 첫번째 노드를 삭제할 때의 조건문.
-- 헤드를 날려버리기만 하면 되기 때문에 간단하다. 헤드를 다음노드로 변경해준다.
- else if (num == L->cnt) 부분
-- 마지막 노드를 삭제할 때의 조건문.
-- 첫 노드와 마찬가지로 테일만 날려버리면 된다. 테일을 이전노드로 변경해주고, 테일의 다음값을 널로 설정한다.
- else 부분
-- 노드를 삽입할 때와 마찬가지로 더미노드 f를 만들어주고, 삭제할 위치까지 찾아간다.
-- 찾은 노드의 이전 노드와 다음 노드를 이어준다.
다음 글에서 검색과 출력함수 설명하겠음
'개발 > C' 카테고리의 다른 글
| [C]이중연결리스트를 사용한 전화번호부 - 03 (0) | 2018.03.30 |
|---|---|
| [C]이중연결리스트를 사용한 전화번호부 - 01 (0) | 2018.03.30 |
[C]이중연결리스트를 사용한 전화번호부 - 01
자료구조를 다시 공부할 겸 해서 이중연결리스트로 간단한 전화번호부를 만들어 보았다.
대충 만든거라 예상치 못한 에러가 있을 수 있음..
그래도 나름 웬만한 에러는 다 잡았다고 생각함
또한 내가 보려고 올리는거라 설명이 좀 부족할 수 있음
전체 코드는 마지막에 한꺼번에 올리도록 하겠음
1. 연결리스트를 위한 구조체 생성하기
typedef struct _Node {
struct _Node *prev;
struct _Node *next;
int no;
char name[20];
int phone;
}node;
typedef struct _linkedList {
struct _Node *head;
struct _Node *tail;
int cnt;
}linkedList;- 리스트에 들어갈 각 노드를 위한 구조체에는 이중연결리스트를 사용할 것이므로 앞 노드와 뒤 노드의 주소를 저장하는 변수를 생성함.
- 전화번호부에 들어갈 사용자 번호와 이름, 전화번호용 변수를 생성함. 근데 코딩하다보니 딱히 사용자 번호를 쓸 일이 없어서 안씀..
- 리스트용 구조체에는 리스트의 헤드와 테일을 저장하는 변수, 리스트의 총 갯수를 파악하기위한 cnt변수를 생성함.
2. 프로그램에서 사용할 함수 정의
void printMain(linkedList *L); // 메인 메뉴 출력 void returnMain(linkedList *L); // 메인으로 돌아옴 void inputMenu(linkedList *L); // 메뉴 선택 void inputData(linkedList *L); // 데이터 입력 void Init(linkedList *L); // 리스트 초기화 void createNode(linkedList *L, char *ndata, int pdata, int num); // 노드 생성 void createLastNode(linkedList *L, char *ndata, int pdata); // 안씀 void deleteNode(linkedList *L); // 노드 삭제 void deleteLastNode(linkedList *L); // 안씀 void findNode(linkedList *L); // 노드 검색 void printNode(linkedList *L); // 리스트 출력
- 프로그램에 사용되는 함수를 미리 정의. 각 내용들은 아래에 설명하겠음.
- LastNode함수는 단일연결리스트 테스트할때 쓰던 코드를 좀 가져오느라 같이 딸려옴..
3. 각 함수별 설명
[ printMain / returnMain / inputMenu / inputData ]
void printMain(linkedList *L) {
printf("1. 리스트\n");
printf("2. 검 색\n");
printf("3. 삽 입\n");
printf("4. 삭 제\n");
printf("5. 종 료\n");
printf("메뉴를 골라주세요 : ");
inputMenu(L);
}
void returnMain(linkedList *L) {
char c;
printf("메인으로(Y/y) 종료(N/n) : ");
// scanf 그냥 통과되는 문제(버퍼를 비우자)
// 이상하게 fflush(stdin)이 안먹혀서 한칸을 비우고 스캔하는 방법을 사용.
scanf(" %c", &c);
if (c == 'Y' || c == 'y') {
system("cls");
printMain(L);
}
else if (c == 'N' || c == 'n')
exit(1);
else {
printf("잘못 누름. 다시 입력 : ");
returnMain(L);
}
}
void inputMenu(linkedList *L) {
int num = 0;
scanf("%d", &num);
if (num > 5 || num < 1) {
printf("1부터 5까지 중에서 고르세요 : ");
num = 0;
scanf(" %d", &num);
}
else {
switch (num) {
case 1:
printNode(L);
break;
case 2:
findNode(L);
break;
case 3:
inputData(L);
break;
case 4:
deleteNode(L);
break;
case 5:
exit(1);
}
}
}
void inputData(linkedList *L) {
char name[20];
int phone, num;
printf("순번 이름 전화번호 순으로 입력하세요 : ");
scanf(" %d %s %d", &num, name, &phone);
createNode(L, name, phone, num);
}
- 별 거 없다. 간단한 메뉴를 위한 출력문과 데이터 입력을 받는 함수들이다.
- returnMain()에서 scanf()관련 주석을 설명하자면, scanf함수를 한번 이상 사용하게 되면, 입력 할 때 쓰는 엔터값이 버퍼에 저장되게 된다.
scanf함수는 stdin이라는 버퍼에 있는 값을 읽는데, 이 버퍼에 엔터키 값이 들어가는 것.
따라서 두번째 scanf함수 부터는 버퍼에 있는 엔터키 값이 자동으로 입력되어 그저 슥 지나가게 된다. (인식을 못 하는 것 처럼 보임)
해결방법으로 fflush(stdin)을 쓰는 방법이 있다. 말 그대로 stdin 버퍼에 있는 값을 다 날려버린다.
두번째로 scanf(" %c", c) 와 같이 한칸을 띄고 입력을 받는 방법인데, 한 칸을 띄우게 되면 버퍼의 첫번째 값을 무시하고 두번째 값부터 읽게 되어 엔터값을 무시할 수 있다.
다음 글부터 주요 함수들을 설명하겠음
'개발 > C' 카테고리의 다른 글
| [C]이중연결리스트를 사용한 전화번호부 - 03 (0) | 2018.03.30 |
|---|---|
| [C]이중연결리스트를 사용한 전화번호부 - 02 (0) | 2018.03.30 |