날짜 : 190521
주제 : 더블 링크드 리스트 구현
설명 : 싱글과 다르게 더블은 노드 구조체 안에 앞에 있는 노드와 뒤에 있는 노드를 모두 저장하고 있다. 따라서 노드를 뒤에서부터 순회할 수 있다.
#include <iostream>
using namespace std;
#define NAME_SIZE 32
/* 링크드 리스트 : 자료구조의 한 종류. 자료구조란 데이터를 저장하는 방법
링크드 리스트는 데이터 목록을 연결시켜서 접근할 수 있는 구조를 제공
특징 : 선형구조... 즉 배열처럼 특정요소에 바로 접근 불가. 무조건 앞에서부터 차례대로 들어가야한다.
노드를 추가할때 노드를 생성하고 마지막 노드에 연결. 따라서 개수의 제한이 없음.
노드 : 데이터를 저장하기 위한 공간
노드의 특징 : 다음노드에 연결가능(주소를 저장)
*/
/*
정렬 기능 추가... 기준은 학번 또는 평균
*/
enum MAIN_MENU
{
MM_NONE,
MM_INSERT,
MM_DELETE,
MM_SEARCH,
MM_PRINT,
MM_SORT,
MM_EXIT
};
enum PRINT_MENU
{
PM_NONE,
PM_FORWARDS,
PM_BACKWARDS,
PM_BACK
};
enum SORT_MENU
{
SM_NONE,
SM_NUMBER,
SM_AVERAGE,
SM_BACK
};
// 학생 정보 구조체
typedef struct _tagStudent
{
char name[NAME_SIZE];
int number;
int kor;
int eng;
int math;
int total;
float average;
}STUDENT, *PSTUDENT;
// 노드 구조체
typedef struct _tagNode
{
STUDENT studentData;
_tagNode* nextNode;
_tagNode* prevNode;
}NODE, *PNODE;
// 리스트 구조체
typedef struct _tagList
{
PNODE begin;
PNODE end;
int currentSize;
int studentNumberStandard;
}LIST, *PLIST;
void InitList(PLIST list)
{
// 포인터 초기화 방식
list->begin = NULL;
list->end = NULL;
list->currentSize = 0;
}
int InputInt()
{
int input;
cin >> input;
if (cin.fail())
{
cin.clear();
cin.ignore(1024, '\n');
return INT_MAX;
}
return input;
}
int PrintMenu()
{
system("cls");
cout << "1. 학생 추가" << endl;
cout << "2. 학생 삭제" << endl;
cout << "3. 학생 탐색" << endl;
cout << "4. 학생 출력" << endl;
cout << "5. 학생 정렬" << endl;
cout << "6. 종료" << endl << endl;
cout << "메뉴를 선택하세요 : " << endl;
int input = InputInt();
if (input <= MM_NONE || input > MM_EXIT)
{
return MM_NONE;
}
return input;
}
void InputString(char* string, int size)
{
cin.clear();
cin.ignore(1024, '\n');
cin.getline(string, size - 1);
}
void Insert(PLIST list)
{
system("cls");
cout << "========== 1. 학생 추가 ==========" << endl;
STUDENT student = {};
cout << "이름 : ";
InputString(student.name, NAME_SIZE);
cout << "국어 점수 : ";
student.kor = InputInt();
cout << "영어 점수 : ";
student.eng = InputInt();
cout << "수학 점수 : ";
student.math = InputInt();
student.total = student.kor + student.eng + student.math;
student.average = student.total / 3.f;
++list->studentNumberStandard;
++list->currentSize;
student.number = list->studentNumberStandard;
// 추가할 리스트 노드를 생성
PNODE node = new NODE;
// 마지막에 추가되는 노드이기 때문에 그 뒤에 노드는 없음
node->nextNode = NULL;
// 입력받은 데이터를 노드에 저장
node->studentData = student;
// 헤드노드가 비어있으면 새로 생성된 노드가 헤드노드
if (list->begin == NULL)
{
list->begin = node;
node->prevNode = NULL;
}
else
{
node->prevNode = list->end;
list->end->nextNode = node;
}
// 새로 생성된 노드가 마지막 노드
list->end = node;
}
//void InsertFront(PLIST list)
void ClearList(PLIST list)
{
PNODE node = list->begin;
while (node != NULL)
{
// 다음 노드 저장
PNODE next = node->nextNode;
// 현재 노드 삭제
delete node;
// 이제 다음 노드로
node = next;
}
// 마지막으로 모두 초기화
list->begin = NULL;
list->end = NULL;
list->currentSize = 0;
}
const void PrintStudentData(const PSTUDENT student)
{
cout << "이름 : " << student->name << "\t학번 : " << student->number << endl;
cout << "국어 점수 : " << student->kor << "\t영어 점수 : " << student->eng << endl;
cout << "수학 점수 : " << student->math << endl;
cout << "총 점 : " << student->total << "\t평 균 : " << student->average << endl << endl;
}
const void PrintListBackwards(const PLIST list)
{
PNODE node = list->end;
while (node != NULL)
{
PrintStudentData(&node->studentData);
node = node->prevNode;
}
cout << "총 학생 수 : " << list->currentSize << endl;
}
const void PrintListForwards(const PLIST list)
{
PNODE node = list->begin;
while (node != NULL)
{
PrintStudentData(&node->studentData);
node = node->nextNode;
}
cout << "총 학생 수 : " << list->currentSize << endl;
}
const void PrintList(const PLIST list)
{
while (true)
{
system("cls");
cout << "========== 4. 학생 정보 출력 ==========" << endl;
cout << "1. 정방향 출력" << endl;
cout << "2. 역방향 출력" << endl;
cout << "3. 뒤로 가기" << endl;
int menu = InputInt();
switch (menu)
{
case PM_FORWARDS:
PrintListForwards(list);
break;
case PM_BACKWARDS:
PrintListBackwards(list);
break;
case PM_BACK:
return;
break;
}
system("pause");
}
}
void SearchByName(PLIST list)
{
cout << "탐색할 이름을 입력하세요 : ";
char searchName[NAME_SIZE] = {};
InputString(searchName, NAME_SIZE);
PNODE node = list->begin;
while (node != NULL)
{
if (strcmp(node->studentData.name, searchName) == 0)
{
PrintStudentData(&node->studentData);
system("pause");
return;
}
node = node->nextNode;
}
cout << "ERROR : 일치하는 학생을 찾지 못했습니다." << endl;
system("pause");
}
void SearchByNumber(PLIST list)
{
cout << "탐색할 학번을 입력하세요 : ";
int searchNumber;
searchNumber = InputInt();
PNODE node = list->begin;
while (node != NULL)
{
if (node->studentData.number == searchNumber)
{
PrintStudentData(&node->studentData);
system("pause");
return;
}
node = node->nextNode;
}
cout << "ERROR : 일치하는 학생을 찾지 못했습니다." << endl;
system("pause");
}
void Search(PLIST list)
{
while (true)
{
system("cls");
cout << "========== 3. 학생 탐색 ==========" << endl;
cout << "1. 이름 검색" << endl;
cout << "2. 학번 검색" << endl;
cout << "3. 뒤로가기" << endl << endl;
cout << "메뉴를 선택하세요 : ";
int menu = InputInt();
switch (menu)
{
case 1:
SearchByName(list);
break;
case 2:
SearchByNumber(list);
break;
case 3:
break;
}
break;
}
}
void Delete(PLIST list)
{
system("cls");
cout << "========== 4. 학생 삭제 ==========" << endl;
cout << "삭제할 이름을 입력하세요 : ";
char searchName[NAME_SIZE] = {};
InputString(searchName, NAME_SIZE);
PNODE currNode = list->begin;
while (currNode != NULL)
{
if (strcmp(currNode->studentData.name, searchName) == 0)
{
cout << currNode->studentData.name << " 학생이 삭제되었습니다." << endl;
PNODE nextNode = currNode->nextNode;
PNODE prevNode = currNode->prevNode;
// 만약 이전 노드가 NULL이라면
// 즉 시작 노드라면
if (prevNode == NULL)
{
delete currNode;
list->begin = nextNode;
// 다음 노드가 헤드 노드가 된다.
nextNode->prevNode = NULL;
if (nextNode == NULL)
{
list->end = NULL;
}
}
// 만약 이전 노드가 NULL이 아니라면 이전노드의 다음을 다음 노드와 연결
else
{
delete currNode;
// 다음 노드가 존재한다면
if (nextNode != NULL)
{
nextNode->prevNode = prevNode;
prevNode->nextNode = nextNode;
}
else
{
list->end = prevNode;
prevNode->nextNode = NULL;
}
}
--list->currentSize;
system("pause");
return;
}
// 해당 학생이 아니라면 현재 노드가 이전 노드가 된다.
currNode = currNode->nextNode;
}
cout << "삭제할 학생을 찾을 수 없습니다." << endl;
system("pause");
}
void Sort(PLIST list)
{
system("cls");
cout << "========== 5. 정렬하기 ==========" << endl;
cout << "1. 학점 기준" << endl;
cout << "2. 평균 기준" << endl;
cout << "메뉴를 선택하세요. ";
int menu = InputInt();
if (menu <= SM_NONE || menu > SM_AVERAGE)
{
cout << "잘못 선택하였습니다." << endl;
system("pause");
return;
}
int i = 0;
while (i <= list->currentSize)
{
PNODE firstNode = list->begin;
PNODE secondNode = firstNode->nextNode;
while (secondNode != NULL)
{
bool swap = false;
switch (menu)
{
case SM_NUMBER:
if ((firstNode->studentData.number) > (secondNode->studentData.number))
{
swap = true;
}
break;
case SM_AVERAGE:
if ((firstNode->studentData.average) > (secondNode->studentData.average))
{
swap = true;
}
break;
}
if (swap == true)
{
PNODE firstPrev = firstNode->prevNode;
PNODE firstNext = firstNode->nextNode;
PNODE secondPrev = secondNode->prevNode;
PNODE secondNext = secondNode->nextNode;
// begin 설정
if (firstNode == list->begin)
{
list->begin = secondNode;
}
PNODE tempNode = firstNode;
firstNode = secondNode;
secondNode = tempNode;
// 앞앞 노드
if(firstPrev != NULL)
{
firstPrev->nextNode = firstNode;
}
// 뒤뒤 노드
if (secondNext != NULL)
{
secondNext->prevNode = secondNode;
}
// 2번째 노드
secondNode->nextNode = secondNext;
secondNode->prevNode = firstNode;
// 1번째 노드
firstNode->prevNode = firstPrev;
firstNode->nextNode = secondNode;
// end 설정
if (firstNext == list->end)
{
list->end = secondNode;
}
firstNode = secondNode;
secondNode = firstNode->nextNode;
}
else
{
firstNode = secondNode;
secondNode = firstNode->nextNode;
}
}
++i;
}
cout << "========= 정렬 되었습니다. =========" << endl;
PrintListForwards(list);
system("pause");
}
int main()
{
LIST list = {};
InitList(&list);
while (true)
{
int menu = PrintMenu();
if (menu == MM_EXIT)
{
break;
}
switch (menu)
{
case MM_INSERT:
Insert(&list);
break;
case MM_DELETE:
Delete(&list);
break;
case MM_SEARCH:
Search(&list);
break;
case MM_PRINT:
PrintList(&list);
break;
case MM_SORT:
Sort(&list);
break;
case MM_EXIT:
break;
}
}
ClearList(&list);
return 0;
}
'C++ 기초 강의 정리(YOUTUBE) ' 카테고리의 다른 글
C/C++ : 강의 61~69화 (마리오 게임 만들기) (0) | 2019.05.24 |
---|---|
C/C++ : 강의 51~53화 (파일 입출력 feat.미로 만들기) (0) | 2019.05.24 |
C/C++ : 강의 44화~46화 (Single Linked List) (0) | 2019.05.21 |
C/C++ 강의 : TextRPG (플레이어, 몬스터, 전투, 상점) [어소트락 유튜브] (0) | 2019.05.17 |
C/C++ 강의 20화 : 구조체와 문자열 함수 [어소트락 유튜브] (0) | 2019.05.17 |