공부 중 메모/수업 예제 (KGCA)

LinkedList 단방향 리스트 예제 <Head가 포인터가 아닌 리스트>

라이피 (Lypi) 2018. 7. 19. 16:22
반응형
//////////////////////////////////////////////////////////////
// 헤드노드(g_pNodeHead) Next부터 실제 데이터를 저장하는 연결리스트
// 사전에 헤드노드를 실제 노드로 생성해 두고 처리한다. (실제 노드지만 데이터는 저장 안 함)
// InsertLink_H : 새로운 노드가 헤드의 Next에 연결되는 전위 연결.
// InsertLink_T : 새로운 노드가 테일의 Next에 연결되는 후위 연결.
// 주) 단방향 연결리스트이므로 기준 노드의 앞쪽으로 연결하는 건 불가능하다.
//    (이전 노드 -> 기준 노드!  -> 신규 노드!! -> 다음 노드) <  가능!>
//    (이전 노드 -> 신규 노드!! -> 기준 노드!  -> 다음 노드) <불가능!> 
//////////////////////////////////////////////////////////////


header.h

#pragma once
//#include <stdio.h>
//#include <string.h>
//#include <stdlib.h> //rand(), srand()
#include <conio.h>
#include <time.h> // time()


#include <iostream> // +<cstdio> +<cstdlib> 
#include <fstream>
#include <string>

using std::cout;
using std::cin;
using std::endl;

using std::getline;

using std::ifstream;
using std::ofstream;

using std::string;

const int RandStd = 5;

list.h

#pragma once
#include "header.h"

//////////////////////////////////////////////////////////////
// 헤드노드(g_pNodeHead) Next부터 실제 데이터를 저장하는 연결리스트
// 사전에 헤드노드를 실제 노드로 생성해 두고 처리한다. (실제 노드지만 데이터는 저장 안 함)
// InsertLink_H : 새로운 노드가 헤드의 Next에 연결되는 전위 연결.
// InsertLink_T : 새로운 노드가 테일의 Next에 연결되는 후위 연결.
// 주) 단방향 연결리스트이므로 기준 노드의 앞쪽으로 연결하는 건 불가능하다.
//    (이전 노드 -> 기준 노드!  -> 신규 노드!! -> 다음 노드) <  가능!>
//    (이전 노드 -> 신규 노드!! -> 기준 노드!  -> 다음 노드) <불가능!> 
//////////////////////////////////////////////////////////////

class node
{
	struct data {
		string	m_strName;
		int		m_iAge;

		data*   pNext;
	};

	data*   pHead;
	data*   pTail;
	data*   pFind;

	int     m_iCount;

public:
	node();

	void    NewLink(string name, int age);     // 신규 노드 생성 및 연결리스트 연결
	void    RandData();                        // 초기 연결리스트 구축

	void    FindName(string pFindName);        // pFindName이름의 노드를 반환한다.
	bool    PrintData();                       // pFindNode를 출력한다.
	bool    InsertLink_H();                      // g_pFindNode 노드 앞에 삽입한다.
	bool    InsertLink_T();                      // g_pFindNode 노드 뒤에 삽입한다.
	


	void    PrintAllData();                    // 전체 연결리스트를 출력한다.

	void    DelLink();                         // pDelNode를 연결리스트에서 삭제
	void    AllDeleteLink();                   // 전체 연결리스트 삭제

	void    LoadLink(string pFileName);       // 파일로부터 로드 및 연결리스트 구축
	void    SaveData(string pFileName);       // 연결리스트 전체를 파일로 저장.
	
	void    MenuClear();
};



list.cpp

#include "list.h"

node::node()
{
	pHead = new data;
	memset(pHead, 0, sizeof(node));
	pTail = pHead;

	pHead->pNext = nullptr;
	pFind = pHead;

	m_iCount = 0;
}

void  node::NewLink(string name, int age)
{
	data*   pNewData = new data;
	{
		pNewData->m_strName = name;
		pNewData->m_iAge = age;
		pNewData->pNext = nullptr;
	}

	pTail -> pNext = pNewData;
	pTail = pNewData;

	m_iCount++;

}// 신규 노드 생성 및 연결리스트 연결

void  node::RandData()
{
	srand(time(NULL));
	for (int iStd = 0; iStd < RandStd; iStd++) {
		string name ="";
		name += 65 + rand() % 26; //A(65), a(97)
		name += 65 + rand() % 26;
		name += 65 + rand() % 26;
	
		NewLink(name, 20 + rand() % 10);
	}

}// 초기 연결리스트 구축

void  node::FindName(string pFindName)
{
	for (data* nodeWrite = pHead; nodeWrite != nullptr; nodeWrite = nodeWrite->pNext) {
		if(nodeWrite->pNext != nullptr && nodeWrite->pNext->m_strName == pFindName) {
			pFind = nodeWrite->pNext;
			return;
		}
	}
	pFind = nullptr;
	return;

}// pFindName이름의 노드를 반환한다.

bool  node::PrintData()
{
	if (pFind == nullptr) {
		cout << "검색 오류!" << endl;
		return false;
	}
	cout << "이름 : " << pFind->m_strName << " 나이 : " << pFind->m_iAge << endl;

	return true;
}// pFindNode를 출력한다.

bool   node::InsertLink_H()
{
	string name = "";
	name += 65 + rand() % 26; //A(65), a(97)
	name += 65 + rand() % 26;
	name += 65 + rand() % 26;

	data* pNewData = new data;

	pNewData->m_strName = name;
	pNewData->m_iAge = 20 + rand() % 10;

	pNewData->pNext = pHead->pNext;
	pHead->pNext = pNewData;

	return true;
}// pHead 노드 뒤에 삽입한다. (맨 앞에 데이터를 추가한다.)

bool   node::InsertLink_T()
{

	if (pFind == nullptr) {
		cout << "검색 오류!" << endl;
		return false;
	}

	string name = "";
	name += 65 + rand() % 26; //A(65), a(97)
	name += 65 + rand() % 26;
	name += 65 + rand() % 26;

	data* pNewData = new data;

	pNewData->m_strName = name;
	pNewData->m_iAge = 20 + rand() % 10;
	pNewData->pNext = pFind->pNext;
	pFind->pNext = pNewData;

	return true;
}// pFind 노드 뒤에 삽입한다.

void   node::PrintAllData()
{
	pFind = pHead->pNext;
	if (pFind == nullptr) {
		cout << "데이터 없음!!!" << endl;
		return;
	}

	while (pFind != nullptr) {
		PrintData();
		pFind = pFind->pNext;

	}
}// 전체 연결리스트를 출력한다.

void   node::DelLink()
{
	data* pPrevNode = pFind;

	data* pDelNode = pPrevNode->pNext;
	if (pHead->pNext == pTail && pTail == pDelNode) {
		pTail = pHead;
		pHead->pNext = nullptr;
	}

	if (pHead == pTail) {
		return;
	}

	data* pNextNode = pDelNode->pNext;
	delete pDelNode;
	m_iCount--;

	pPrevNode->pNext = pNextNode;

	return;
}
// pDelNode를 연결리스트에서 삭제

void   node::AllDeleteLink()
{
	pFind = pHead;
	while (pHead->pNext != nullptr) {
		if (pHead == pTail) {
			return;
		}
		DelLink();
	}
	pTail = pHead;
}// 전체 연결리스트 삭제

void   node::SaveData(string pFileName)
{
	ofstream os;
	os.open(pFileName);

	for (data* nodeWrite = pHead; nodeWrite->pNext != nullptr; nodeWrite = nodeWrite->pNext) {
		os << nodeWrite->pNext->m_strName << endl;
		os << nodeWrite->pNext->m_iAge << endl;
	}
	os.close();

}// 연결리스트 전체를 파일로 저장.


void   node::LoadLink(string pFileName)
{
	ifstream is;
	is.open(pFileName);

	AllDeleteLink();
	
	string ch;

	data* nodeWrite = pHead;
	pFind = pHead;

	while (true) {
		nodeWrite->pNext = new data;
		is >> nodeWrite->pNext->m_strName;
		is >> nodeWrite->pNext->m_iAge;
		
		if (is.eof()) {
			pTail = nodeWrite;
			pTail->pNext = nullptr;
			break;
		}
		nodeWrite = nodeWrite->pNext;
	}
	is.close();

}// 파일로 부터 로드 및 연결리스트 구축


void   node::MenuClear()
{
	system("cls");
	printf("\n=========================================");
	printf("\n============ 성적관리프로그램============");
	printf("\n=========================================");
	cout << endl;
}

main.cpp

#include "list.h"

int main()
{
	node a;
	
	bool bRunning = true;

	while (bRunning) {

		int iWork = 0;
		cout << "생성(0),출력(1),검색(2),맨 앞에 데이터 추가(3), 저장(4),불러오기(5),종료(그외) : " << endl;
		cin >> iWork;

		string FName = "";
		int iWork_2 = 0;

		switch (iWork)
		{
		case 0: //초기데이터 생성 
			a.MenuClear();
			a.RandData();
		break;
		
		case 1: //화면 출력
			a.MenuClear();
			a.PrintAllData();
		break;

		case 2: // 검색
			a.MenuClear();

			cout << "이름을 입력하세요 " << endl;
			cin >> FName;

			a.FindName(FName);

			if(a.PrintData()) {
				cout << "검색한 데이터 뒤에 새로운 데이터 추가(1), 데이터 삭제(2), 돌아가기(그외) : " << endl;
				cin >> iWork_2;

				switch (iWork_2)
				{
				case 1:
					a.MenuClear();
					a.InsertLink_T();
				break;

				case 2:
					a.MenuClear();
					a.DelLink();
				break;

				default:
				break;
				}
			}
		break;

		case 3:
			a.MenuClear();
			a.InsertLink_H();
		break;

		case 4:
			a.MenuClear();
			a.SaveData("save.txt");
		break;

		case 5:
			a.MenuClear();
			a.LoadLink("save.txt");
		break;

		default:
			cout << "아무키나 누르시면 종료합니다" << endl;
			_getch();
			return 0;
		break;
		}
	}
}


반응형