1简单目录管理系统的设计与实现

利用树型结构设计并实现一个简单的目录管理系统,该系统可以对所有目录进行管理,如目录的新建、删除、查询、目录名称修改、按某种顺序输出所有目录(树的遍历操作)、以树型结构输出所有目录等功能。

到底用C语言还是C#?C语言可以用win32 api和windows的TreeControl

  • 这个问题的回答你可以参考下: https://ask.csdn.net/questions/267572
  • 我还给你找了一篇非常好的博客,你可以看看是否有帮助,链接:多态、使用父类类型作为参数、向上转型和向下转型、使用父类类型作为返回类型、简单工厂模式、抽象类的多态应用
  • 除此之外, 这篇博客: C语言小游戏:扫雷;展开、标记雷、第一步不死,踩到雷后游戏结束并且打印出雷区中的 代码详细解释都在代码块里,大家可以按流程看,有什么问题可以在下面留言 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • 下面是game.h文件,存放一些声明 :

    #ifndef _GAME_H
    #define _GAME_H
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <string.h>
    #define ROW 9//小棋盘行
    #define COL 9//小棋盘列
    #define ROWS ROW+2//大棋盘行
    #define COLS COL+2//大棋盘列
    #define COUNT 10//定义随机布置的雷的个数
    
    void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret);//初始化棋盘
    void DisplayBoard(char board[ROWS][COLS], int rows, int cols);//打印棋盘
    void SetMine(char board[ROWS][COLS], int row, int col);//布雷
    void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);//扫雷
    int GetMine(char a[ROWS][COLS], int x, int y);//获得周围八个格子雷的个数
    void SpreadBoard(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y);//展开函数
    void RemarkBoard(char show[ROWS][COLS], int row, int col);//标记函数
    
    void test();//测试函数
    void game();//游戏功能实现
    void menu();//菜单函数
    
    #endif //_GAME_H
    

    下面是test.c文件 :

    #define _CRT_SECURE_NO_WARNINGS 1
    #include "game.h"
    
    //扫雷
    //简单分析:首先要做一个9*9的棋盘,就是放雷的棋盘。可是,当你要排查雷的时候,肯定是要找某个坐标的周围
    //八个坐标是不是雷,那么问题来了,如果是要排查棋盘边边上的坐标,排查的话,数组的下标肯定会越界
    //所以可以在外边多打印一圈,置为0,排查的话就当做是没有雷对待;
    //所以,初始化一个11*11的大棋盘,玩家跟电脑随机布置的雷都在这个小的棋盘里进行
    //注意!!!:函数传参的时候注意传的是大棋盘还是小棋盘的参数!!!
    int main()
    {
    	test();//游戏检测函数
    	system("pause");
    	return 0;
    }
    

    下面是game.c文件 :
    这个文件里的函数太多,我分布描述吧,首先是第一个测试函数,功能:打印菜单;玩家选择开始或退出游戏;

    void test()
    {
    	srand((unsigned int)time(NULL));//调用rand()函数之前调用的,srand是一个产生随机数种子的函数
    	int input = 0;///////////////////time(NULL)的意思是以现在的系统时间作为随机的种子来产生随机数
    	menu();/////////////////////////至于NULL这个参数,只有设置成NULL才能获得系统的时间
    	printf("请选择1或者0开始或者结束游戏:->  ");
    	do
    	{
    		scanf("%d", &input);
    		switch (input)
    		{
    		case 1:
    			game();
    			break;
    		case 0:
    			printf("退出游戏!\n");
    			break;
    		default:
    			printf("输入错误,请重新输入! ->");
    			break;
    		}
    	} while (input);
    }
    void menu()//打印菜单函数
    {
    	printf("*****************************************\n");
    	printf("***************    1.play   *************\n");
    	printf("***************    0.exit   *************\n");
    	printf("*****************************************\n");
    }
    

    接下来就是游戏函数game()了
    游戏函数里面包含了很多函数,我详细说一下:首先,定义两个二维数组,也就是大小棋盘;然后,初始化棋盘,一个棋盘将要存放雷的信息,不向玩家展示;另一个全部初始化为星号,准备向玩家展示;接下来随机布置雷;接着开始扫雷,扫雷函数里面还有几个函数,后面我接着解释吧;

    void game()
    {
    	char mine[ROWS][COLS] = { 0 };//用来存放雷的信息
    	char show[ROWS][COLS] = { 0 };//用来向玩家展示的棋盘
    	InitBoard(mine, ROWS, COLS, '0');//mine棋盘81个字符全部初始化为字符0;
    	InitBoard(show, ROWS, COLS, '*');//show棋盘全部初始化为字符‘*’(玩家看到的只有*)
    	SetMine(mine, ROW, COL);//放入雷的信息,雷只保存在mine棋盘中;
    	//DisplayBoard(mine, ROW, COL);////正式游戏不必打印存放雷的信息;此条语句不用打印
    	DisplayBoard(show, ROW, COL);
    	printf("--------------------------------\n");
    	FindMine(mine, show, ROW, COL);//开始扫雷
    }
    

    初始化棋盘

    void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret)//这里的形参rows\cols,区别:
    //初始化是初始化11*11的棋盘,全部初始化为接收到的字符
    {
    	memset(&(board[0][0]),ret, rows*cols*sizeof(board[0][0]));//memset()函数需要#include<stdlib.h>这个头文件
    }
    

    打印棋盘,顺便看看棋盘有木有初始化好

    void DisplayBoard(char board[ROWS][COLS], int row, int col)//打印棋盘,row和col,用来确定打印的字符,仅仅在中间
    //9*9的棋盘打印字符,所以这里接受9用row和col;
    {
    	int i = 0;
    	int j = 0;
    	for (i = 0; i <= col; i++)
    	{
    		printf("%d ", i);
    	}
    	printf("\n");
    	for ( i = 1; i <= row; i++)
    	{
    		printf("%d", i);
    		for ( j = 1; j <= col; j++)
    		{
    			printf(" %c", board[i][j]);
    		}
    		printf("\n");
    	}	
    }
    

    接下来布雷;注意这是给哪个棋盘布雷(不给玩家展示的那个棋盘)

    void SetMine(char board[ROWS][COLS], int row, int col)//布雷
    {
    	int x = 0;
    	int y = 0;
    	int count = COUNT;
    	while (count)
    	{
    		x = rand() % row + 1;
    		y = rand() % col + 1;
    		if (board[x][y] == '0')//每成功布下一个雷,count就自减一
    		{
    			board[x][y] = '1';
    			count--;
    		}
    	}
    }
    

    下面这个是扫雷函数
    我简单分析以下吧。系统随机布雷后,玩家就开始扫雷了;这个函数要具有这些功能:1、第一次不能被炸死 2、走的位置四周如果没有雷就 展开,有雷就显示雷的个数 3、每走一步都要选择是否继续走或者是标记一下;标记功能可以写一个函数,统计周围雷的个数也可以写一个函数

    void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//开始排雷
    {
    	int x = 0;
    	int y = 0;
    	int win = 0;
    	int input = 0;
    	printf("请输入要走的第一个坐标:");
    	while (win<row*col-COUNT)//循环终止条件:扫出的雷等于布下的雷;
    	{
    		scanf("%d%d", &x, &y);
    		printf("--------------------------------\n");
    		if (x >= 1 && x <= row && y >= 1 && y <= col)
    		{
    			if (mine[x][y] == '1'&& win == 0)//此入口只有一个功能:第一次不被炸死;
    				//第一次如果是雷,就随机在棋盘别的地方加一个雷,把当前坐标的雷改为无雷
    				//这样雷的总数没变,随机分布也没变,第一次也没有炸死
    			{
    				int num = 1;
    				while (num)
    				{
    					int i = rand() % row + 1;
    					int j = rand() % col + 1;
    					if (mine[i][j] == '0')
    					{
    						mine[i][j] = '1';
    						num--;
    					}
    				}
    				mine[x][y] = '0';
    				SpreadBoard(mine, show,row,col,x,y);
    				int count = GetMine(mine, x, y);
    				show[x][y] = count + '0';
    				DisplayBoard(show, ROW, COL);
    				//DisplayBoard(mine, ROW, COL);//正式游戏不必打印存放雷的信息;此条语句不用打印
    				printf("--------------------------------\n");
    				do
    				{
    					printf("请选择1或者0选择标记雷点或者接着走下一步->\n");
    					scanf("%d", &input);
    						switch (input)
    					{
    						case 1:
    							RemarkBoard(show, row, col);
    							DisplayBoard(show, ROW, COL);
    							break;
    						case 0:
    							printf("请选择走下一步 --> ");
    							break;
    						default:
    							printf("输入错误,请重新输入! ->");
    							break;
    					}	
    				} while (input);	
    				win++;
    			}
    		    else if (mine[x][y] == '1')
    			{
    				printf("You was died !!!!\n");
    				DisplayBoard(mine, ROW, COL);
    				printf("请重新选择1或者0开始或者结束游戏:->  ");
    				break;
    			}
    			else
    			{
    				//如果没有踩中雷,排查该坐标周围的雷
    				int count = GetMine(mine, x, y);
    				show[x][y] = count + '0';
    				SpreadBoard(mine, show,row,col,x,y);
    				DisplayBoard(show, ROW, COL);
    				//DisplayBoard(mine, ROW, COL); 正式游戏不必打印存放雷的信息;此条语句不用打印
    				printf("--------------------------------\n");
    				//printf("请选择走下一步 --> ");
    				do
    				{
    					printf("请选择1或者0选择标记雷点或者接着走下一步->\n");
    					scanf("%d", &input);
    					switch (input)
    					{
    					case 1:
    						RemarkBoard(show, row, col);
    						DisplayBoard(show, ROW, COL);
    						break;
    					case 0:
    						printf("请选择走下一步 --> ");
    						break;
    					default:
    						printf("输入错误,请重新输入! ->");
    						break;
    					}
    				} while (input);
    				win++;
    			}
    		}
    	}
    	if (win == row*col - COUNT)
    	{
    		printf("You are Winner!!!!!\n");
    		DisplayBoard(show, ROW, COL);
    		DisplayBoard(mine, ROW, COL);
    		printf("--------------------------------\n");
    		printf("请重新选择1或者0开始或者结束游戏:->  ");
    	}
    }
    

    统计雷个数

    nt GetMine(char a[ROWS][COLS], int x, int y)//函数GetMine()统计改坐标周围的雷的个数
    {
    	return
    		a[x - 1][y - 1] + a[x - 1][y] + a[x - 1][y + 1]
    		+ a[x][y - 1] + a[x][y + 1]
    		+ a[x + 1][y - 1] + a[x + 1][y] + a[x + 1][y + 1] - 8*'0';
    		//数字字符减去数字字符‘0’就等于对应的数字
    }
    

    棋盘展开

    //展开函数SpreadBoard(),如果某个坐标周围没有雷,则展开包括改坐标在内的九个坐标
    //然后,继续以该座标周围的八个没有雷的坐标为起点继续排查,如果周围八个坐标中,
    //有雷存在,那么不展开,直接输出雷的个数;依次类推;
    //这种思想为递归的思想,一层一层的展开;
    //递归的终止条件就是count!=0输出雷的个数,就不会调用了;
    void SpreadBoard(char mine[ROWS][COLS], char show[ROWS][COLS],int row,int col, int x, int y)
    {
    	int count = 0;
    	count = GetMine(mine, x, y);
    	int i = 0;
    	int j = 0;
    	if (count == 0)
    	{
    		show[x][y] = ' ';
    		if (x + 1 <= row && y - 1 > 0 && show[x + 1][y - 1] == '*')
    		{
    			SpreadBoard(mine, show, row, col, x + 1, y - 1);
    		}
    		if (x + 1 <= row && show[x + 1][y] == '*')
    		{
    			SpreadBoard(mine, show, row, col, x + 1, y);
    		}
    		if (x + 1 <= row && y + 1 <= col && show[x + 1][y + 1] == '*')
    		{
    			SpreadBoard(mine, show, row, col, x + 1, y + 1);
    		}
    		if (y - 1 > 0 && show[x][y - 1] == '*')
    		{
    			SpreadBoard(mine, show, row, col, x, y - 1);
    		}
    		if (y + 1 <= col &&show[x][y + 1] == '*')
    		{
    			SpreadBoard(mine, show, row, col, x, y + 1);
    		}
    		if (x - 1 > 0 && y - 1 > 0 && show[x - 1][y - 1] == '*')
    		{
    			SpreadBoard(mine, show, row, col, x - 1, y - 1);
    		}
    		if (x - 1 > 0 && show[x - 1][y] == '*')
    		{
    			SpreadBoard(mine, show, row, col, x - 1, y);
    		}
    		if (x - 1 > 0 && y + 1 <= col && show[x - 1][y + 1] == '*')
    		{
    			SpreadBoard(mine, show, row, col, x - 1, y + 1);
    		}
    	}
    	else
    	{
    		show[x][y] = count + '0';
    	}
    }
    //标记函数RamarkBoard(),这个函数传参只传要打印给玩家的那个棋盘就行
    //也就是初始化全是字符'*'的那个棋盘,玩家自己标记了后该坐标变成感叹号
    

    标记函数;注意,这里标记的是玩家给看到的棋盘

    //标记函数RamarkBoard(),这个函数传参只传要打印给玩家的那个棋盘就行
    //也就是初始化全是字符'*'的那个棋盘,玩家自己标记了后该坐标变成感叹号
    void RemarkBoard(char show[ROWS][COLS], int row, int col)//标记函数;
    {
    	int x = 0;
    	int y = 0;
    	int flag = 1;
    	printf("请输入您要标记的坐标:-> ");
    	scanf("%d %d", &x, &y);
    	while (flag)
    	{
    		if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
    		{
    			if (show[x][y] == '*')
    			{
    				show[x][y] = '!';
    				flag = 0;
    			}
    		}
    		else
    		{
    			printf("输入错误,重新输入!");
    		}
    	}
    }
    //本程序还是有个bug:就是玩家可以继续走已经标记的那一步棋,游戏依旧会判断是否踩雷
    //游戏依旧按照mine棋盘,也就是存储雷的信息的那个棋盘;
    //这个bug......游戏未完待续......
    

    到这里整个扫雷游戏基本上就算是完成了,各个功能都有了
    下面是运行实例
    在这里插入图片描述
    在这里插入图片描述

  • 您还可以看一下 董洪伟老师的算法设计与分析课程中的 暴力破解密码、百钱买百鸡、背包问题小节, 巩固相关知识点
  • 以下回答由chatgpt基于相关博客总结生成:

    设计并实现一个简单的目录管理系统

    1.首先我们需要定义一个目录结构体,结构体中包括目录的名字、父目录、子目录和大小等信息。

    struct Directory{ string name; //目录名 Directory* parent; //父目录指针 vector child; //子目录指针 int size; //目录大小 };

    2.之后,我们需要定义一个目录管理类,提供创建、删除、查询、修改、遍历等操作。

    class DirectoryManager{ public: DirectoryManager(string rootName){ //构造函数 root = new Directory; root->name = rootName; root->parent = NULL; root->size = 0; }

    ~DirectoryManager(){                //析构函数
        delete root;
    }
    
    Directory* createDirectory(string name, Directory* parent){  //创建目录
        Directory* newDir = new Directory;
        newDir->name = name;
        newDir->parent = parent;
        newDir->size = 0;
        parent->child.push_back(newDir);
        return newDir;
    }
    
    bool deleteDirectory(Directory* dir){    //删除目录
        if(dir->child.size() != 0){          //有子目录不能删除
            return false;
        }
        Directory* parent = dir->parent;
        for(vector<Directory*>::iterator it = parent->child.begin(); it != parent->child.end(); it++){
            if(*it == dir){
                parent->child.erase(it);
                delete dir;
                return true;
            }
        }
        return false;                        //未找到需要删除的目录
    }
    
    Directory* getDirectory(Directory* currentDir, string name){ //查找目录
        for(vector<Directory*>::iterator it = currentDir->child.begin(); it != currentDir->child.end(); it++){
            if((*it)->name == name){
                return *it;
            }
        }
        return NULL;                 //未找到需要查找的目录
    }
    
    bool modifyDirectoryName(Directory* dir, string newName){ //修改目录名字
        for(vector<Directory*>::iterator it = dir->parent->child.begin(); it != dir->parent->child.end(); it++){
            if((*it) != dir && (*it)->name == newName){   //新名字已存在
                return false;
            }
        }
        dir->name = newName;
        return true;
    }
    
    void treeTraversal(Directory* root){  //树的遍历
        if(root != NULL){
            cout<<root->name<<endl;
            for(vector<Directory*>::iterator it = root->child.begin(); it != root->child.end(); it++){
                treeTraversal(*it);
            }
        }
    }
    
    void printDirectory(Directory* dir, int depth){  //以树型结构输出所有目录
        if(dir != NULL){
            string prefix(depth, '\t');
            cout<<prefix<<dir->name<<endl;
            for(vector<Directory*>::iterator it = dir->child.begin(); it != dir->child.end(); it++){
                printDirectory(*it, depth+1);
            }
        }
    }
    

    private: Directory* root; };

    3.接下来,我们可以在main函数中创建一个根目录,并实现各种目录操作。

    int main(){ DirectoryManager manager("root"); //创建根目录 Directory curDir = manager.getDirectory(manager.root, "root"); //获取当前目录 Directory dir1 = manager.createDirectory("dir1", curDir); //在当前目录下创建目录dir1 Directory dir2 = manager.createDirectory("dir2", curDir); //在当前目录下创建目录dir2 Directory subDir = manager.createDirectory("subDir", dir1); //在目录dir1下创建子目录subDir manager.modifyDirectoryName(dir1, "newDir1"); //修改目录名为newDir1 manager.treeTraversal(curDir); //遍历当前目录及子目录 manager.printDirectory(curDir, 0); //以树型结构输出当前目录及子目录 manager.deleteDirectory(subDir); //删除子目录subDir return 0; }