2020 CCSP【给他文件系统(GeetFS)】

题面描述:http://history.ccfccsp.org.cn/2020/0-tasks.pdf

这个题就是模仿Git实现一些简单文件操作功能:write、read、unlink、ls、commit、checkout、merge。

可以说按顺序,实现难度越来越高。后面的命令会影响前面命令的执行,所以为了得到后面测试点的分,前面写过的函数往往要做出很大的整改。

这是是我第一次写的大型模拟题。断断续续写了好多个小时,后面都是对着测试点的数据来写。现在还是cin和cout的输入输出,可能运行速度还是比较慢,但总归是答案都对上了。没有OJ可以测试,所以就先这样吧。由于开始没有特别认真,思路混乱就开始写了,导致调试起来也很慢。

总结一下经验:
1)面对大型模拟题,首先通读下整个题面,把需要注意的细节都标记出来。实际上它说什么,你就做什么基本就能得到正确答案,做完后再来想怎么减少时间复杂度。
2)在开始编程之前,把几个模块想好,要怎么划分。然后看测试点,按照测试点来对一个个功能进行实现,每做完一个测试点的模块就进行调试。如果这样有规律地执行应该能省很多时间。
3)把最简单的前半部分测试点实现之后,每多做一个测试点,都要记得备份一下,万一后面写糊涂了,把前面做好的搞没了就完蛋了。
4)特别注意使用的函数尽量不要用不熟悉的,如果非要用就必须对函数做些基本的测试,摸清这个函数对程序的影响。如果这里出了问题,在实际做题也找不到资料的话,基本上就卡死了。为了得分,笨笨地多写几行也比用不了解的函数要好的多。

现在我的观点是,这类题大概解决掉简单一些的测试点就可以跳过到下一题了,直到后面的题也到了难有进展的地步再回来死磕吧。心态真的很重要,要是头晕了就稍微歇一歇,活动一下身体。不舒服地继续做很可能会浪费许多时间。最后是,真的要自信,这种模拟题就是实现所有的细节,很累但不会说是很难。

#include <bits/stdc++.h>
using namespace std;

using RC = int;

#define OK         0
#define NOEXIT    -1
#define DELETED   -2

int static Time = 0;

class File {
public:
	File(string filename)
		: name(filename)
		, del(false) {}
	File(const File& file) {
		name = file.name;
		content = file.content;
		del = file.del;
		time = file.time;
	}
	~File(){}
	
	void write(int offset, int len, string input) {
		int l = content.length();
		if (l < offset + len) content.resize(offset + len);
		if (l <= offset) {
			content.insert(l, string(offset - l, '.'));
			content.resize(content.length() - (offset - l));
		}
		content.insert(offset, input);
		content.resize(content.length() - input.length());
	}
	void read(int offset, int len, string& output) {
		int l = content.length();
		if (l < offset + len) {
			int nl = offset + len; 
			content.resize(nl);
			content.insert(l, string(nl - l, '.'));
			content.resize(content.size() - (nl - l));
		}
		output = content.substr(offset, len);
	}
	void setRecover() {
		del = false;
	}
	void setDel() {
		del = true;
		content.clear();
	}
	bool getDel() {return del;}
	string getName() {return name;}
	void setTime(int t) {time = t;}
	int getTime() {return time;}
private:
	string name;
	string content;
	bool del;
	int time;
}; 

class Commit {
public:
	Commit(Commit* fa = nullptr, Commit* me = nullptr)
		: father(fa)
		, merge(me)
		, cmtname("uncommited")	{}
	~Commit(){
		for (int i = 0; i < files.size(); i++) {
			if (files[i] != nullptr)
				delete files[i];
		}
	}
	
	// uncommited无父节点, 在head里面找只要找最近的即可 
	RC query(string filename, File*& file) {
		for (int i = 0; i < files.size(); i++) {
			if (files[i]->getName() == filename) {
				file = files[i];
				if (files[i]->getDel()) return DELETED;
				return OK;
			}
		}
		RC rc1, rc2;
		if (father != nullptr) {
			rc1 = father->query(filename, file);
		}
		File* file2 = nullptr;
		if (merge != nullptr) {
			rc2 = merge->query(filename, file2);
		}
		if (file != nullptr && file2 != nullptr) {
			if (file->getTime() < file2->getTime()) {
				file = file2;
				return rc2;
			} else {
				return rc1;
			}
		}
		if (file != nullptr) return rc1;
		if (file2 != nullptr) {
			file = file2;
			return rc2;
		}
		return NOEXIT;
	}
	// GeetFS中已经对其他情况做过处理,确保如果head中可以找到一定会放入uncommited中 
	void write(string filename, int offset, int len, const string& input) {
		File* file = nullptr;
		int rc = query(filename, file);
		if (rc == NOEXIT) {
			file = new File(filename);
			files.push_back(file);
		}
		file->write(offset, len, input);
	}
	RC read(string filename, int offset, int len, string& output) {
		File* file = nullptr;
		RC rc = query(filename, file);
		if (rc != OK) return rc;
		file->read(offset, len, output);
		return OK;
	}
	// 仅对uncommited会有unlink操作,因此不用考虑其他节点的影响 
	void unlink(const string& filename) {
		File* file = nullptr;
		RC rc = query(filename, file);
		if (rc == OK) file->setDel();
	}
	void ls(vector<File>& tmpFile, map<string, int>& ID) {
		for (int i = 0; i < files.size(); i++) {
			if (!ID.count(files[i]->getName())) {
				ID[files[i]->getName()] = tmpFile.size();
				tmpFile.push_back(*files[i]);
			} else {
				int ind = ID[files[i]->getName()];
				if (tmpFile[ind].getTime() < files[i]->getTime()) {
					tmpFile[ind] = *files[i];
				}
			}
		}
		if (father != nullptr)
			father->ls(tmpFile, ID);
		if (merge != nullptr) 
			merge->ls(tmpFile, ID);
		return;
	}
	void Copy(const File& file) {
		files.push_back(new File(file));
	}
	void setName(const string& name) {
		cmtname = name;
	}
	string getName() {
		return cmtname;
	}
	void setParent(Commit* fa = nullptr, Commit* me = nullptr) {
		father = fa;
		merge = me;
	}
	bool isEmpty() {
		return files.empty();
	}
	void setTime(int time) {
		for (int i = 0; i < files.size(); i++)
			files[i]->setTime(time);
	}
private:
	Commit* father;
	Commit* merge;
	vector<File*> files;
	string cmtname;
};

class GeetFS {
public:
	GeetFS()
		: head(nullptr) {
			uncommited = new Commit();
		}
	~GeetFS() {
		for (int i = 0; i < cmts.size(); i++)
			delete cmts[i];
		delete uncommited;
	}
	
	void solve(const string& cmd) {
 		if (cmd == "write") {
			int offset, len;
			string filename, input;
			cin >> filename >> offset >> len;
			getline(cin, input);
			getline(cin, input);
			write(filename, offset, len, input);
		}
		else if (cmd == "read") {
			int offset, len;
			string filename, output;
			cin >> filename >> offset >> len;
			RC rc = uncommited->read(filename, offset, len, output);
			if (rc == NOEXIT) {
				if (head != nullptr) rc = head->read(filename, offset, len, output);
			}
			if (rc != OK) cout << string(len, '.') << endl;
			else cout << output << endl;
		}
		else if (cmd == "unlink") {
			string filename;
			cin >> filename;
			unlink(filename);
		}
		else if (cmd == "ls") {
			ls();
		}
		else if (cmd == "commit") {
			string cmtname;
			cin >> cmtname;
			commit(cmtname);
		}
		else if (cmd == "checkout") {
			string cmtname;
			cin >> cmtname;
			checkout(cmtname);
		}
		else if (cmd == "merge") {
			string me, cmtname;
			cin >> me >> cmtname;
			merge(me, cmtname);
		}
	}
	void write(string filename, int offset, int len, const string& input) {
		File* file = nullptr;
		RC rc = uncommited->query(filename, file);
		if (rc == DELETED) file->setRecover();
		if (rc == NOEXIT) {
			if (head != nullptr) rc = head->query(filename, file);
			if (rc == OK) uncommited->Copy(*file);
		}
		uncommited->write(filename, offset, len, input);
	}
	void unlink(const string& filename) {
		File* file = nullptr;
		RC rc = uncommited->query(filename, file);
		if (rc != OK && head != nullptr) {
			rc = head->query(filename, file);
			if (rc == OK) uncommited->Copy(*file);
		}
		uncommited->unlink(filename);
	}
	void ls() {
		map<string, int> ID;
		vector<File> tmpFile;
		uncommited->ls(tmpFile, ID);
		if (head != nullptr) {
			head->ls(tmpFile, ID);
		}
		int num = 0;
		string minStr = "", maxStr = "";
		for (int i = 0; i < tmpFile.size(); i++) {
			if(tmpFile[i].getDel()) continue;
			num++;
			if (minStr == "") minStr = tmpFile[i].getName();
			else minStr = min(minStr, tmpFile[i].getName());
			if (maxStr == "") maxStr = tmpFile[i].getName();
			else maxStr = max(maxStr, tmpFile[i].getName());
		}
		cout << num;
		if (num > 0)
			cout << " " << minStr << " " << maxStr;
		cout << endl;
	}
	Commit* query(const string& cmtname) {
		for (int i = 0; i < cmts.size(); i++) {
			if(cmts[i]->getName() == cmtname)
				return cmts[i];
		}
		return nullptr;
	}
	void commit(const string& cmtname) {
		if (uncommited->isEmpty() || nullptr != query(cmtname)) return;
		uncommited->setName(cmtname);
		uncommited->setParent(head);
		uncommited->setTime(++Time);
		cmts.push_back(uncommited);
		head = uncommited;
		uncommited = new Commit();
	}
	void checkout(const string& cmtname) {
		Commit* cmt = query(cmtname);
		if (!uncommited->isEmpty() || cmt == nullptr) return;
		head = cmt;
	}
	void merge(const string& me, const string& cmtname) {
		Commit* meCmt = query(me);
		if (!uncommited->isEmpty() || meCmt == nullptr || meCmt == head) return;
		uncommited->setName(cmtname);
		uncommited->setParent(head, meCmt);
		cmts.push_back(uncommited);
		head = uncommited;
		uncommited = new Commit();
	} 
private:
	Commit* head;
	Commit* uncommited;
	vector<Commit*> cmts;
};

int main(void) {
//	freopen("in.txt", "r", stdin);
//	freopen("out.txt", "w", stdout);
	GeetFS gt;
	int n;
	cin >> n;
	while (n--) {
		string cmd;
		cin >> cmd;
		gt.solve(cmd);
	}
	return 0;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JILIN.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值