文件目录结构的树形显示(数据结构课程设计,树、队列,C语言描述)

一、要解决的问题

    给出某一个操作系统下目录和文件信息,输入的数据第一行为根目录节点。若是目录节点,那么它的孩子节点将在第二行中被列出,同时用一对圆括号“()”界定。同样,如果这些孩子节点中某一个也是目录的话,那么这个目录所包含的内容将在随后的一行中列出,由一对圆括号“()”界定。目录的输入输入格式为:*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)

 

posted @ 2012-11-05 00:18  Estrong  阅读(5241)  评论(0编辑  收藏  举报