컴퓨터 프로그래밍 공부/자료구조와 알고리즘

트리를 이용한 파일 시스템 자료 구조 만들기

뽀또치즈맛 2024. 10. 29. 00:00

 
1. FileSystemDataStrcut.h에 필요한 헤더 파일을 포함한다.

#pragma once
#include <iostream>
#include <vector>
#include <algorithm>

 
2. 디렉터리/파일 정보를 저장할 노드 구조체를 작성한다.

// 파일 시스템의 노드를 나타내는 구조체 정의
typedef struct nArrNode {
    string name;  // 파일 또는 디렉토리의 이름
    bool isDir;  // 이 노드가 디렉토리인지 여부 (true: 디렉토리, false: 파일)
    vector<nArrNode*> children;  // 자식 노드들을 가리키는 포인터들의 벡터 (파일 또는 서브디렉토리)
} nArrNode;

 
3. 사용하기 편하도록 nArrNode를 사용하여 트리를 구성한다.
그리고 현재 디렉터리를 저장할 변수를 추가한다.
 

struct FileSystem
{
    using node = nArrNode;  // nArrNode 구조체를 node라는 이름으로 별칭 정의
    using nodePtr = node*;  // nArrNode 포인터 타입을 nodePtr이라는 이름으로 별칭 정의

private:
    nodePtr root;  // 파일 시스템의 루트 디렉토리를 가리키는 포인터
    nodePtr cwd;  // 현재 작업 디렉토리를 가리키는 포인터

 
4. 생성자에서 루트 디렉터리를 만들고, 이를 현재 디렉터리로 설정한다.

//FileSystemDataStrcut.h

public:
    FileSystem();  // 파일 시스템 생성자, 루트 디렉토리 초기화
    


//FileSystemDataStrcut.cpp

// FileSystem 클래스 생성자: 루트 디렉토리를 초기화하고 현재 작업 디렉토리를 루트로 설정
FileSystem::FileSystem()
{
    root = new node{ "/", true, {} };  // 루트 디렉토리 생성 (name: "/", isDir: true, 자식 노드 없음)
    cwd = root;  // 현재 작업 디렉토리를 루트로 설정
}

 
5. 디렉터리/파일을 찾는 find() 함수를 추가한다.

// 경로에 해당하는 노드를 찾는 함수
FileSystem::nodePtr FileSystem::find(const string& path)
{
    if (path[0] == '/') {  // 절대 경로인 경우
        return FindImpl(root, path.substr(1));  // 루트에서 시작하여 탐색
    }
    else {  // 상대 경로인 경우
        return FindImpl(cwd, path);  // 현재 작업 디렉토리에서 시작하여 탐색
    }
}


// 주어진 디렉토리에서 경로를 재귀적으로 탐색하여 노드를 찾는 함수
FileSystem::nodePtr FileSystem::FindImpl(const nodePtr directory, const string& path)
{
    if (path.empty()) return directory;  // 경로가 비어 있으면 현재 디렉토리를 반환

    auto sep = path.find('/');  // 다음 경로 구분자 위치 찾기
    string currentPath = sep == string::npos ? path : path.substr(0, sep);  // 현재 탐색할 경로 부분
    string restPath = sep == string::npos ? "" : path.substr(sep + 1);  // 남은 경로 부분

    // 현재 디렉토리의 자식 노드에서 해당 이름을 가진 노드를 찾음
    auto found = find_if(directory->children.begin(), directory->children.end(),
        [&](const nodePtr child) {
            return child->name == currentPath;
        });

    if (found != directory->children.end()) {
        return FindImpl(*found, restPath);  // 찾은 경우, 나머지 경로에 대해 재귀적으로 탐색
    }

    return NULL;  // 찾지 못한 경우 NULL 반환
}

 
 
6. 디렉터리를 생성하는 add() 함수를 추가한다.
 

// 경로에 새 파일 또는 디렉토리를 추가하는 함수
bool FileSystem::add(const string& path, bool isDir)
{
    if (path[0] == '/') {  // 절대 경로인 경우
        return addImpl(root, path.substr(1), isDir);  // 루트에서 시작하여 추가
    }
    else {  // 상대 경로인 경우
        return addImpl(cwd, path, isDir);  // 현재 작업 디렉토리에서 시작하여 추가
    }
}

// 주어진 디렉토리에 경로에 따라 새 파일 또는 디렉토리를 추가하는 함수 (재귀적 구현)
bool FileSystem::addImpl(nodePtr directory, const string& path, bool isDir)
{
    if (not directory->isDir) {  // 현재 디렉토리가 파일인 경우
        cout << directory->name << "은(는) 파일입니다." << endl;
        return false;
    }

    auto sep = path.find('/');  // 다음 경로 구분자 위치 찾기

    if (sep == string::npos) {  // 마지막 경로 부분인 경우
        // 현재 디렉토리의 자식 노드 중 동일한 이름을 가진 노드가 있는지 확인
        auto found = find_if(directory->children.begin(), directory->children.end(),
            [&](const nodePtr child) {
                return child->name == path;
            });

        if (found != directory->children.end()) {  // 동일한 이름의 파일/디렉토리가 이미 있는 경우
            cout << directory->name << "에 이미 " << path << " 이름의 파일/디렉터리가 있습니다." << endl;
            return false;
        }

        // 새로운 파일 또는 디렉토리를 현재 디렉토리에 추가
        directory->children.push_back(new node{ path, isDir, {} });
        return true;
    }

    // 다음 경로 부분 추출
    string nextDir = path.substr(0, sep);
    // 현재 디렉토리의 자식 노드 중 다음 경로에 해당하는 디렉토리 찾기
    auto found = find_if(directory->children.begin(), directory->children.end(),
        [&](const nodePtr child) {
            return child->name == nextDir && child->isDir;
        });

    if (found != directory->children.end()) {  // 디렉토리를 찾은 경우, 나머지 경로에 대해 재귀적으로 추가
        return addImpl(*found, path.substr(sep + 1), isDir);
    }

    cout << directory->name << "에 " << nextDir << " 이름의 디렉터리가 없습니다." << endl;
    return false;
}

 
 
7. 디렉터리를 이동하는 changeDir() 함수를 추가한다.
이미 앞서 find()함수를 구현했기 때문에 ChangeDir()함수를 쉽게 구현할 수 있다.

// 현재 작업 디렉토리를 변경하는 함수
bool FileSystem::ChangeDir(const string path)
{
    auto found = find(path);  // 주어진 경로에 해당하는 노드를 찾음
    if (found && found->isDir) {  // 디렉토리인 경우
        cwd = found;  // 현재 작업 디렉토리를 변경
        cout << "현재 디렉터리를 " << cwd->name << "로 이동합니다." << endl;
        return true;
    }

    cout << path << " 경로를 찾을 수 없습니다." << endl;
    return false;
}

 
8. 이번에는 디렉터리와 파일 목록을 출력하는 ShowPath() 함수를 추가한다.
함수 인자로 파일이 전달되면 단순히 파일 이름을 출력하고,
디렉터리가 인자로 전달되면 해당 디렉터리의 하위 디렉터리와 파일을 모두 출력한다.
 


// 주어진 경로에 있는 파일 및 디렉토리들을 출력하는 함수
void FileSystem::ShowPath(const string& path)
{
    auto found = find(path);  // 주어진 경로에 해당하는 노드를 찾음
    if (not found) {  // 경로가 존재하지 않는 경우
        cout << path << " 경로가 존재하지 않습니다." << endl;
        return;
    }

    if (found->isDir) {  // 디렉토리인 경우, 자식 노드들을 출력
        for (auto child : found->children) {
            cout << (child->isDir ? "d " : "- ") << child->name << endl;
        }
    }
    else {  // 파일인 경우, 파일 이름만 출력
        cout << "- " << found->name << endl;
    }
}

'컴퓨터 프로그래밍 공부 > 자료구조와 알고리즘' 카테고리의 다른 글

힙을 이용한 중앙값 구하기  (0) 2024.11.04
  (0) 2024.10.31
해쉬 테이블 - Collison 문제 해결책  (1) 2024.10.15
테이블과 해쉬  (2) 2024.10.15
AVL  (0) 2024.09.21