一、要解決的問題
給出某一個操作系統下目錄和文件信息,輸入的數據第一行為根目錄節點。若是目錄節點,那么它的孩子節點將在第二行中被列出,同時用一對圓括號“()”界定。同樣,如果這些孩子節點中某一個也是目錄的話,那么這個目錄所包含的內容將在隨后的一行中列出,由一對圓括號“()”界定。目錄的輸入輸入格式為:*name size,文件的輸入輸入格式為:name size。Name為一串不超過10個字符組成,並且字符串中不能有‘(’,‘)’,‘[‘,’]’和’*’。Size是該文件/目錄的大小,文件的size輸入值為該文件的大小,目錄的size輸入值都為1。樹結構最多10層,每一層最多2個文件/目錄。
要求編程實現將其排列成一棵有一定縮進的樹,輸出要求:第d層的文件/目錄名前面需要縮進8*d個空格,兄弟節點要在同一列上。並計算每一個目錄大小,目錄大小為所包含的所有子目錄和文件大小以及自身大小的總和。
例如輸入:
*/usr 1
(*mark 1 *alex 1)
(hw.c 3 *course 1) (hw.c 5)
(aa.txt 12)
輸出
|_*/usr[24]
|_*mark[17]
| |_hw.c[3]
| |_*course[13]
| |_aa.txt[12]
|_*alex[6]
|_hw.c[3]
二、算法基本思想描述:
采用孩子兄弟雙親鏈表的數據存儲結構建立二叉樹,再先序遍歷該二叉樹輸出所有節點。輸出時,通過parent節點的第一個孩子是否有兄弟節點控制縮進輸出” | ”或” ”;目錄的大小為該目錄左子樹(以其第一個孩子為根的樹)所有節點的size和加上它本身大小。
三、設計
1. 數據結構的設計和說明
在一開始設計要采用的數據結構時,雖然課題只要求“樹結構最多10層(樹的深度),每一層最多2個文件/目錄”,考慮到問題的實際意義,我決定把它優化消除這一限制,於是采用孩子兄弟的數據結構,后來由於縮進輸出的需要又增加了parent域。
2. 關鍵算法的設計
(1)輸入處理:從外部文件每讀入一行處理一行,數據結構的構造與讀入同時進行,提取節點的name[]域和size域建立該行所有節點。其間,利用隊列設立parentArray[]用來記錄所有的目錄節點地址,設置兩個虛擬指針rear和head,每增加一個目錄rear+1,head標記可作為當前節點parent域的目錄,每遇到一個‘)’ head+1處理下一個目錄包含的節點。當輸入文件結束時所采用的孩子兄弟雙親鏈表二叉樹也就建立完成。
(2)輸出處理:先序遍歷所建立的二叉樹,每個節點輸出一行,都是先通過其parent節點的第一個孩子是否有兄弟節點標記flag[0]~flag[i],然后從flag[i]~flag[0]控制輸出縮進符” | ”或” ”后再輸出該節點信息。
3. 數據結構圖:
四、源程序清單(Win7系統WinTC環境下編譯運行通過):
/*
========================================================
課題:文件目錄結構的顯示
Author:Estrong. All Rights Reserved.
指導老師:LinFang
2011年1月7日寫於福建工程學院.
========================================================
*/
#include "stdio.h"
#include "string.h"
#define Null 0
#define MAX 200
/*輸入文件每行應不超過MAX個字符*/
typedef struct node /*采用孩子兄弟雙親鏈表的存儲結構*/
{
char name[12];
unsigned int size;
struct node *parent,*first_child,*next_sibling;
}BinTNode,*BinTree;
/* 添加新節點 */
BinTree New_BinTNode(char str[],int *I,BinTree parentArray[],int *head,int *rear)
{ int i=0;
BinTree bt;
bt=(BinTNode *)malloc(sizeof(BinTNode));
bt->parent=parentArray[*head]; /*鏈接雙親結點確定歸屬目錄*/
bt->first_child=Null;
bt->next_sibling=Null;
if(str[*I]=='*')
{(*rear)++; parentArray[*rear]=bt;}
while(str[*I]!=' ')
{
bt->name[i]=str[*I];
(*I)++;i++;
}
bt->name[i]='\0';(*I)++;
bt->size=str[*I]-'0';(*I)++;
while ((str[*I]!=' ')&&(str[*I]!=')')&&((*I)<strlen(str)-1)) /*條件(*I)<strlen(str)-1)是考慮到根節點沒有‘ ’和')'*/
{
bt->size=bt->size*10+(str[*I]-'0');
(*I)++;
}
return bt;
}
/* 創建數據(將輸入數據轉化為所采用的樹結構) */
BinTree Create_BinTree(FILE *input)
{ int I=0,rear=0,head=1; /*parentArray[head]用來記錄當前節點應指向的parent目錄節點*/
/*parentArray[rear]用來記錄最后一個目錄節點*/
BinTree parentArray[MAX];/*parentArray[]用來記錄所有的目錄節點地址*/
BinTree root,bt,pbt;
char str[MAX];
fgets(str,MAX,input);
root=New_BinTNode(str,&I,parentArray,&head,&rear);
root->parent=Null; /* 在創建根節點時其parent的賦值是隨機的,這里給它賦回空 */
while(!feof(input))
{I=1; /*I是輸入文件每行字符串中的下標,貫穿該行字符處理始末*/
fgets(str,MAX,input);
while(I<=(strlen(str)-1))
{
if(str[I]!=')')
{
bt=New_BinTNode(str,&I,parentArray,&head,&rear);
parentArray[head]->first_child=bt;
pbt=bt;
do /*創建並鏈接一對括號里的所有兄弟節點*/
{
if(str[I]==' ')
{
I++;
pbt->next_sibling=New_BinTNode(str,&I,parentArray,&head,&rear); /*創建兄弟節點*/
pbt=pbt->next_sibling;
}
}while(str[I]!=')') ;
head++; I=I+3; /* 此時遇到右括號head+1處理下一個目錄;I+3跳過") (" */
}
else
{head++ ; I=I+3;} /* 此時也遇到右括號 */
}
}
return root;
}
/* 求目錄大小 */
int SIZE(BinTree bt) /*返回當前目錄左子樹的大小(未加上原目錄大小)*/
{ int size;
if(bt)
size=bt->size+SIZE(bt->first_child)+SIZE(bt->next_sibling);
else size=0;
return size;
}
/* 輸出單個節點 */
void out(BinTree bt,FILE *output)
{ char size_str[10];
BinTree pbt=bt->parent;
int i=-1,j=0,k;
int flag[11]; /*flag[i]用來控制縮進,子目錄深度可以設置,目前設為11*/
for(k=0;k<11;k++) flag[k]=0;
if(bt->name[0]=='*') bt->size=bt->size+SIZE(bt->first_child);
/*目錄的大小為該目錄本身大小及其左子樹(以其第一個孩子為根的樹)所有節點的size和*/
while(pbt!=Null)
{
i++;
if(pbt->next_sibling) flag[j]=1; /*輸出時flag[i]=1縮進"| " */
else flag[j]=0; /*輸出時flag[i]=0縮進" " */
pbt=pbt->parent;
j++;
}
while(i>=0)
{
if(flag[i]) {printf("| ");fprintf(output,"| ");}
else {printf(" ");fprintf(output," ");}
i--;
}
printf("|_%s[%d]\n",bt->name,bt->size);
fprintf(output,"|_%s[%d]\n",bt->name,bt->size);
}
/* 先序遍歷輸出整棵樹 */
void OUTPUT(BinTree bt,FILE *output)
{
if(bt)
{
out(bt,output);
OUTPUT(bt->first_child,output);
OUTPUT(bt->next_sibling,output);
}
}
/* 主函數 */
main()
{ FILE *input,*output;
BinTree root;
if((input=fopen("input.txt","r"))==NULL)
{
printf("Cannot find the file! Strike any key to exit!");
getch();
exit(1);
}
output=fopen("output.txt","w");
root=Create_BinTree(input);
OUTPUT(root,output);
getch();
fclose(input);fclose(output);
}
五、測試數據及測試結果:
(注:以下測試數據置於外部文件input.txt里)
*/kqss 1
(*mark 1 *alex 1 *course 1 aa.txt 12 hw.c 5 hjh.c 4 gffg.c 5)
() (kkhw.c 3 *course 1) (ghw.c 5 *test 1 abcd.exe 13 *fdg 1 hw.c 5 hjh.c 4)
(aa.txt 2 kqss.c 100 hgfgsdf.h 35 ghgjh.mp3 7) () (arfe.txt 12 kqss.c 100 fdfs.h 35)