模拟文件目录系统-CatalogTree
模擬文件目錄系統(tǒng)-CatalogTree
使用樹(shù)結(jié)構(gòu)實(shí)現(xiàn)一個(gè)簡(jiǎn)單文件目錄系統(tǒng)的模擬程序
數(shù)據(jù)結(jié)構(gòu):目錄樹(shù)CatalogTree
代碼地址:Tcoder-l3est/DataStructureCourseProject: 山東大學(xué)數(shù)據(jù)結(jié)構(gòu)課設(shè) (github.com)
基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)
使用的數(shù)據(jù)結(jié)構(gòu)是
帶父節(jié)點(diǎn)指針的二叉樹(shù)—兄弟鏈表
每個(gè)節(jié)點(diǎn)是一個(gè)目錄項(xiàng),每個(gè)葉節(jié)點(diǎn)是一個(gè)文件(也有可能是空目錄)。
示意圖
結(jié)點(diǎn)結(jié)構(gòu)
struct Node {Node* parent;//每個(gè)節(jié)點(diǎn)都要記錄父節(jié)點(diǎn)Node* LeftChild;//只記錄第一個(gè)孩子Node* sibiling;//平級(jí)向后連int file_type;//0文件 1目錄string file_name;//文件或者目錄名字ll fnum;//子文件數(shù)目ll file_size;//該文件大小//針對(duì)目錄文件來(lái)說(shuō)的ll all_mx;//目錄配額 和 后代配額ll son_used;//所有的孩子占的大小char power;//權(quán)限Node(int type, string fname, ll size = 0) {file_type = type; file_size = size;fnum = 0;parent = NULL; LeftChild = NULL;sibiling = NULL;file_name = fname;all_mx = 0;son_used = 0;power = 'p';//r是管理員權(quán)限}~Node() { }bool pre_add_size(ll size) {//預(yù)分配 文件if (all_mx && son_used + size > all_mx)return false;return true;}void add_size(ll size) {//預(yù)分配成功才進(jìn)入這個(gè)son_used += size;}void get_size() {if (file_type == 0) {cout <<"文件大小: "<<file_size<<"\n";//文件}else{cout << "目錄配額大小: " << all_mx << " 使用了 " << son_used << "\n";}}bool set_size(ll all) {//分配一個(gè)配額 只對(duì)目錄有用if (all < son_used) return false;return true;}};定義指針指向父節(jié)點(diǎn)、左孩子、兄弟節(jié)點(diǎn)
定義文件或者目錄名字,以及類(lèi)型
針對(duì)目錄文件:實(shí)現(xiàn)帶配額的也就是模擬磁盤(pán)大小的功能,添加了目錄配額**all_mxall\_mxall_mx**
以及所有孩子占的磁盤(pán)大小 son_usedson\_usedson_used
**powerpowerpower**實(shí)現(xiàn)角色的權(quán)限控制
樹(shù)結(jié)構(gòu)
class CatalogTree { private:Node* root;Node* CurNode;//當(dāng)前位置char my_power; public:CatalogTree();~CatalogTree() { delete root; };string outname;string inname;ifstream ffin;ofstream ffout;int put_flag;//輸出在cmd 還是 file//基礎(chǔ)void dir();//列出當(dāng)前目錄下的所有子目錄和文件項(xiàng)void cd();//累出當(dāng)前目錄的絕對(duì)路徑void cd_recur(Node* now);void cd_back();//當(dāng)前目錄變?yōu)楫?dāng)前目錄的父目錄。void cdstr(string& str);//當(dāng)前目錄變?yōu)镾TR所表示路徑的目錄void mkdir(string& str);//在當(dāng)前目錄下創(chuàng)建一個(gè)子目錄str,如果存在則不進(jìn)行任何操作void mkfile(string& str);//在當(dāng)前目錄下創(chuàng)建一個(gè)文件,若存在不進(jìn)行。void delet(string& str);//刪除當(dāng)前目錄下名字為STR的目錄或者文件,如果不存在,不進(jìn)行操作void deletenode(Node* now);void save(string& str);//將從根節(jié)點(diǎn)開(kāi)始的目錄樹(shù)結(jié)構(gòu)保存到文件中void save_recur(ofstream& fout, Node* now, int depth);//遞歸保存void load(string& str);//從文件STR中讀取之前保存的目錄樹(shù)結(jié)構(gòu),并且根據(jù)其重新建立當(dāng)前的目錄樹(shù)void load_recur(ifstream& fin, int depth);void read_data(int num);//sizevoid mkfile_size(string& str, ll size);//make file with 大小限制 str相對(duì)路徑void setdir_size(ll all_mx);//給當(dāng)前 原有的 目錄文件設(shè)置配額void remove_size(string& str);//刪除文件或者目錄//其他void cd_root();//回到rootvoid mkdir_p(string& str);//自行創(chuàng)建多層目錄void put_size() { CurNode->get_size(); }//獲取當(dāng)前目錄的配額//權(quán)限void _r() { my_power = 'r'; }void _p() { my_power = 'p'; }void mkdir_r(string& str);//創(chuàng)建帶權(quán)限的目錄void mkfile_r(string& str);//創(chuàng)建帶權(quán)限的文件void delet_r(string& str);//拓展文件操作//剪切void mv_a2b(string &a,string &b);//從a移動(dòng)到b//復(fù)制void cp_a2b(string& a, string& b);//把當(dāng)前目錄下的a 復(fù)制到b下 b下不能有重名的void cp_r(Node *t);//遞歸拷貝節(jié)點(diǎn) };私有成員
? 包括根節(jié)點(diǎn)、定義了一個(gè)CurNodeCurNodeCurNode來(lái)表示當(dāng)前正在哪個(gè)目錄下,哪個(gè)節(jié)點(diǎn)中,以及一個(gè)my_power 來(lái)檢查處于文件系統(tǒng)的角色的權(quán)限是什么樣的。
公有成員
? outname、innameoutname、innameoutname、inname是用來(lái)輸入輸出的,配合ffin和ffoutffin和ffoutffin和ffout使用,putflagput_flagputf?lag是決定輸出在cmdcmdcmd 還是$ file$
實(shí)現(xiàn)了以下指令:
基礎(chǔ)
-
dir —— 列出當(dāng)前目錄下的所有子目錄與文件項(xiàng),所有文件項(xiàng)后加*表示“這是一個(gè)文件”,沒(méi)有則不輸出;
-
cd —— 列出當(dāng)前目錄的絕對(duì)路徑。
-
cd .. —— 當(dāng)前目錄變?yōu)楫?dāng)前目錄的父目錄 。
-
cd str —— 當(dāng)前目錄變?yōu)?str 所表示路徑的目錄。
-
mkdir str ——在(當(dāng)前目錄下)創(chuàng)建一個(gè)子目錄(名為 str),若存在則不進(jìn)行任何操作。
-
mkfile str ——在(當(dāng)前目錄下)創(chuàng)建一個(gè)文件(名為 str) ,若存在則不進(jìn)行任何操作。
-
delete str ——?jiǎng)h除(當(dāng)前目錄下)名為 str 的目錄或文件,若不存在則不進(jìn)行任何操作。
-
save str—— 將從根節(jié)點(diǎn)開(kāi)始的目錄樹(shù)結(jié)構(gòu)保存到文件(名為str)中。
-
load str —— 從名為的文件str中讀取之前保存的目錄樹(shù)結(jié)構(gòu),并根據(jù)其重新建立當(dāng)前目錄樹(shù),并進(jìn)行后續(xù)操作
-
quit —— 退出程序
拓展
權(quán)限操作:
-
-r —— 系統(tǒng)權(quán)限變?yōu)閞oot
-
-p—— 系統(tǒng)權(quán)限變?yōu)閜
-
mkdir-r—— 創(chuàng)建一個(gè)權(quán)限為R的目錄
-
-mkfile-r str—— 當(dāng)前目錄下創(chuàng)建一個(gè)名為str目錄,權(quán)限為r
-
-delete-r str—— 以root權(quán)限,刪除當(dāng)前目錄下名為str的目錄或文件
配額操作:
-
mkfile-s str—— 在當(dāng)前下創(chuàng)建大小為size,名為str的文件
-
Q size—— 在當(dāng)前下創(chuàng)建大小為size,名為str的文件
-
remove str—— 刪除絕對(duì)路徑str最后一個(gè)文件以及目錄
-
show—— 展示當(dāng)前目錄的配額大小以及使用情況或文件的大小
文件操作:
-
mv a b—— 把當(dāng)前路徑下的a剪切到絕對(duì)路徑b下
-
cp a b—— 把當(dāng)前路徑下的a復(fù)制到絕對(duì)路徑b下
其他操作:
- mkdir-m str—— 根據(jù)輸入的str絕對(duì)路徑,生成多級(jí)目錄(類(lèi)似于touch)
部分實(shí)現(xiàn)思路
基礎(chǔ)
void dir()的設(shè)計(jì)思路:
列出當(dāng)前目錄下的所有子目錄和文件項(xiàng),只需要對(duì)當(dāng)前路徑的子節(jié)點(diǎn)掃描一遍輸出即可。void cd()的設(shè)計(jì)思路:
列出當(dāng)前目錄的絕對(duì)路徑,需要遞歸實(shí)現(xiàn),首先迭代到根節(jié)點(diǎn),開(kāi)始輸出文件名稱(chēng),之后遞歸回來(lái),就完成了路徑的輸出!
void cd_back()的設(shè)計(jì)思路:
進(jìn)入當(dāng)前路徑的父節(jié)點(diǎn)即可實(shí)現(xiàn)后退操作。
Void cdstr(string& str)的設(shè)計(jì)思路:
當(dāng)前目錄變?yōu)镾TR所表示路徑的目錄,首先判斷是絕對(duì)路徑還是相對(duì)路徑,絕對(duì)路徑從根開(kāi)始進(jìn)入即可,相對(duì)路徑返回父節(jié)點(diǎn)后再進(jìn)入就行。
void mkfile/mkdir(string& str)的設(shè)計(jì)思路:
當(dāng)前目錄下創(chuàng)建一個(gè)目錄或者文件節(jié)點(diǎn),只需要先檢查是否已經(jīng)存在該種目錄或者文件,如果沒(méi)有則新建節(jié)點(diǎn),設(shè)置大小后,插入即可。
void delet(string& str)的設(shè)計(jì)思路:
刪除當(dāng)前目錄下名字為STR的目錄或者文件,如果不存在,不進(jìn)行操作.
先掃描找到該節(jié)點(diǎn),之后如果是文件直接刪除并且修改指針,如果是目錄就遞歸刪除,所有子目錄子文件.
void save(string& str)的設(shè)計(jì)思路:
將從根節(jié)點(diǎn)開(kāi)始的目錄樹(shù)結(jié)構(gòu)保存到文件中,借鑒windows里面 tree命令,進(jìn)行遞歸存儲(chǔ),即從根節(jié)點(diǎn)開(kāi)始,如果有目錄就進(jìn)入目錄遞歸保存,根據(jù)不同的level 前面加不同個(gè)’|’ 來(lái)標(biāo)志,如果是目錄則儲(chǔ)存為 |后加’-’表示為目錄.
最后保存CUR表示當(dāng)前節(jié)點(diǎn),之后存END表示結(jié)束標(biāo)識(shí)符
下圖是windows Tree命令 以及 模擬的Tree命令
void load(string& str)的設(shè)計(jì)思路:
從文件讀入 把目錄樹(shù)建立起來(lái),與load思路相同,最后要設(shè)置curnode掃描節(jié)點(diǎn),讀到cur設(shè)置curnode,讀到end停止。
拓展
文件操作拓展
void mv_a2b(string &a,string &b)的設(shè)計(jì)思路:
? 進(jìn)行剪切文件的操作,傳入當(dāng)前目錄下的一個(gè)文件或者目錄a 然后絕對(duì)路徑b,把a(bǔ)移動(dòng)到b下面,如果是根則不能移動(dòng),如果有權(quán)限不符合的則直接返回權(quán)限不夠。文件可以直接移動(dòng),目錄遞歸移動(dòng),不需要?jiǎng)h除源節(jié)點(diǎn),只需要對(duì)指針進(jìn)行修改。
一定要拒絕父節(jié)點(diǎn) 剪切到子節(jié)點(diǎn)的操作!
void cp_a2b(string& a, string& b) 的設(shè)計(jì)思路:
? 進(jìn)行文件的復(fù)制操作,把當(dāng)前目錄下的a 復(fù)制到b下 b下不能有重名的,文件直接復(fù)制,目錄遞歸復(fù)制,如果是根則不能復(fù)制,如果有權(quán)限不符合的則直接返回權(quán)限不夠,最后不能簡(jiǎn)單修改指針,不然會(huì)導(dǎo)致紊亂,必須要新建節(jié)點(diǎn)。
權(quán)限拓展
void mkdir_r/mkfie_r(string& str)的設(shè)計(jì)思路:
創(chuàng)建一個(gè)權(quán)限為r(root)的目錄、文件,如果當(dāng)前權(quán)限不為r則無(wú)法刪除 或者進(jìn)行其他操作。
void delet_r(string& str)的設(shè)計(jì)思路:
利用以管理員身份刪除對(duì)應(yīng)文件或者目錄。
配額拓展
void mkfile_size(string& str, ll size)設(shè)計(jì)思路:
在當(dāng)前路徑下創(chuàng)建一個(gè)大小為size的文件,需要檢查是否滿(mǎn)足文件大小配額要求,所以需要檢查當(dāng)前目錄結(jié)構(gòu)是否有足夠的空間。其次檢查是否有重復(fù)文件。建立完成之后,加入該文件并且修改對(duì)應(yīng)的目錄的配額剩余。
void setdir_size(ll all_mx)思路:
給當(dāng)前 原有的 目錄文件設(shè)置配額,必須要滿(mǎn)足當(dāng)前文件是目錄文件并且分配的配額大小滿(mǎn)足最小的文件限制,否則就分配不成功。
void remove_size(string& str)設(shè)計(jì)思路:
先檢查刪除的是文件還是目錄,文件的話直接刪除,并且修改目錄的配額即可。
如果是目錄,則需要修改父目錄的配額,并且遞歸刪除所有文件、目錄。
其他拓展
void cd_root()的設(shè)計(jì)思路:
回到根目錄
void mkdir_p(string& str)的設(shè)計(jì)思路:
對(duì)于輸入的絕對(duì)路徑,如果走到了現(xiàn)在目錄的最后一個(gè)目錄仍有路徑?jīng)]有走完,則自動(dòng)創(chuàng)建對(duì)應(yīng)的目錄,自動(dòng)實(shí)現(xiàn)多層目錄的訪問(wèn)以及補(bǔ)全。
void put_size()
獲取當(dāng)前目錄的配額
分析
時(shí)間復(fù)雜度
對(duì)于從根向下進(jìn)行搜索的操作的復(fù)雜度都是平均O(logn),最差O(n)即一個(gè)鏈表的情況。
對(duì)于遞歸的操作則是O(n) 因?yàn)橐獙?duì)所有節(jié)點(diǎn)進(jìn)行操作。
要修改父目錄的配額,并且遞歸刪除所有文件、目錄。
其他拓展
void cd_root()的設(shè)計(jì)思路:
回到根目錄
void mkdir_p(string& str)的設(shè)計(jì)思路:
對(duì)于輸入的絕對(duì)路徑,如果走到了現(xiàn)在目錄的最后一個(gè)目錄仍有路徑?jīng)]有走完,則自動(dòng)創(chuàng)建對(duì)應(yīng)的目錄,自動(dòng)實(shí)現(xiàn)多層目錄的訪問(wèn)以及補(bǔ)全。
void put_size()
獲取當(dāng)前目錄的配額
總結(jié)
以上是生活随笔為你收集整理的模拟文件目录系统-CatalogTree的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 两个实打实干活的同事离职了,老板连谈都没
- 下一篇: java信息管理系统总结_java实现科