操作系统:文件系统——空闲块成组链接法的模拟

题目

文件系统——空闲块成组链接法的模拟

(1)设计合适的数据结构模拟磁盘空闲块的情况。

(2)模拟分配空闲块的过程。

(3)模拟回收空闲块的过程。

(4)模拟对所有空闲块进行分析、凑连续块 的维护过程。

思路

  • 构造空闲块成组链接+重构

用空闲块链接法可以节省内存,但实现效率低。改进方法是把所有空闲盘块按固定数量分组,我这里选用的是50个空闲块一组,组中的第1块为“组长”块。第1组的50个空闲块块号放在第2组的组长块中,而第2组的其余49块是完全空闲的。第2组的50个块号又放在第3组的组长块中。以此类推,组与组之间形成链接关系。最后一组的块号(可能不足50块),通常放在内存的一个专用栈(即文件系统超级块中的空闲块号栈),这里我是用一个一维数组来表示,长度是51,下标0存储超级块当前数据长度。这样,平常对盘块的分配和释放放在超级块中进行。

重构的思路主要是把剩下的空闲块的块号收集起来,我是用vector存储起来,然后排序(从小到大)。接着就是上面构造成组链接的过程,区别在于每次给空闲块块号赋值是用上面的排序结果。

  • 分配空闲块

当需要为新建文件分配空闲盘块时,总是先把超级块中表示栈深的值作为检索超级块中空闲块号栈的索引,得到对应的盘块号,它就是当前分配出去的空闲块。如果需要分配更多个盘块,则重复上述操作即可。

如果当前栈深为1,需要再分配一个空闲盘块。那么,以1作为索引下标,得到盘块号,它是一个组长块;然后,把该组长盘块的内容,即下一组所有空闲盘块的数量和各个盘块的块号分别放进超级块的栈深和空闲块号栈中。最后把该组长块分配出去。如果继续分配,就和上面分配非组长块的操作一样即可。

  • 释放空闲块

若要删除一个文件,循环释放它所占用的空闲块。释放一个空闲块的操作是,先让栈深值加1,接着把块号放在当前栈深所对应的元素中,每次释放修改对应成组链接中的盘块。如果需要释放更多个盘块,则重复上述操作即可。

如果栈深的值是50,表示该栈已满,此时还要释放一个盘块,则进行特殊处理:先将该栈中的内容(包括栈深值和各空闲块块号)写到需要释放的新盘块中 ;将栈深及栈中全部盘块号清除;把栈深值置变为1,将新盘块号写入相应的栈单元中。这样,该盘块就成为新组的组长块。如果继续释放,就和上面普通的释放操作一样即可。

代码

#include <iostream>
#include <random>
#include <ctime>
#include <vector>
#include <algorithm>
using namespace std;

void InitSuperBlock();  // 初始化超级块
void InitUI();  // 初始化用户界面
void AllocateBlock(int size);  // 分配空闲块
void ReleaseBlock(vector<int> file);  // 释放空闲块
void PrintFile();  // 打印文件
void PrintFreeBlock();  // 打印当前所有空闲块
void Refactor();  // 重构成组链接空闲块

struct FreeBlock {
	bool isLeader;  // 是否为组长块
	int p[50];  // 作为组长块时使用,用于存放前一组的块号
	int size;  // 作为组长块时使用,前一组块数
	int seq;  // 空闲块的序号
	bool isFree;  // 是否空闲
	int data[15];  // 数据域,用于存放数据
	FreeBlock() {
		isLeader = false;
		size = 0;
		isFree = true;
	}
};
FreeBlock **block;

int a[51];  // 超级块,a[0]存储栈深
int totalGroups;  // 成组链接总组数
int group;  // 当前所在的组号
int num;  // 空闲块总块数
int remain;  // 空闲块剩余块数
vector<vector<int>> files;  // 文件

int main() {
	srand(unsigned(time(0)));
	num = rand() % 101 + 300;  // 随机300~400个空闲块
	cout << "随机空闲块总块数:" << num << endl;
	int tmp = num + 1;  // 第一组只有49块,加上1块便于计算,实际上没有
	// 申请空闲块二维数组
	totalGroups = (tmp % 50) == 0 ? tmp / 50 : (tmp / 50 + 1);
	block = new FreeBlock *[totalGroups];
	block[0] = new FreeBlock[49];
	for (int i = 1; i < totalGroups; i++) {
		block[i] = new FreeBlock[50];
	}
	tmp--;
	// 建立空闲块成组链接
	for (int i = 0; i < totalGroups; i++) {
		for (int j = 0; j < 50; j++) {
			if (tmp == 0) {
				break;
			}
			if (j == 0 && i != 0) {  // 组长块
				for (int k = 0; k < 50; k++) {
					if (i == 1) {  // 特殊处理第二组
						if (k == 0) {
							block[i][0].p[k] = 0;
						}
						else {
							block[i][0].p[k] = block[i - 1][k - 1].seq;
						}
						continue;
					}
					block[i][0].p[k] = block[i - 1][k].seq;
				}
				block[i][0].isLeader = true;
				block[i][0].size = 50;
				block[i][0].seq = tmp;
				tmp--;
			}
			else {  // 普通空闲块
				if (i == 0 && j == 49) {  // 第一组只有49块
					break;
				}
				block[i][j].seq = tmp;
				tmp--;
			}
		}
	}
	group = totalGroups - 1;  // 当前所在组的组号
	remain = num;

	InitSuperBlock();  // 初始化超级块
	InitUI();  // 初始化用户界面

	return 0;
}

// 初始化超级块
void InitSuperBlock() {
	int n = 0;  // 记录最后一组空闲块的个数(可能不足50)
	for (int i = 0; i < 50; i++) {
		if (block[group][i].seq < 0 || !block[group][i].isFree) {
			break;
		}
		n++;
		a[i + 1] = block[group][i].seq;
	}
	a[0] = n;
}

// 初始化用户界面
void InitUI() {
	while (1) {
		int x;
		int filesSize = files.size();
		cout << "***********************************************************************************" << endl;
		cout << "* 1.空闲块分配   2.空闲块释放   3.查看文件   4.查看空闲块   5.重构空闲块   6.退出 *" << endl;
		cout << "***********************************************************************************" << endl;
		cout << "请输入操作:";
		cin >> x;
		if (x == 1) {  // 空闲块分配
			cout << "当前分配的是第" << filesSize + 1 << "个文件!" << endl;
			while (1) {
				cout << "请输入文件需要的空闲块个数:";
				int n;
				cin >> n;
				if (n <= 0) {
					cout << "错误:输入错误!" << endl;
					continue;
				}
				if (n > remain) {
					cout << "错误:剩余空闲块块数为" << remain << "。无法分配!" << endl << endl;
					break;
				}
				remain -= n;  // 剩余空闲块减少
				AllocateBlock(n);
				break;
			}
		}
		else if (x == 2) {  // 空闲块释放
			if (filesSize == 0) {
				cout << "当前文件为空!" << endl << endl;
			}
			else {
				while (1) {
					cout << "请输入要释放的文件号:";
					int n;
					cin >> n;
					if (n <= 0 || n > filesSize) {
						cout << "错误:输入错误!" << endl;
						continue;
					}
					remain += files[n-1].size();  // 剩余空闲块增加
					ReleaseBlock(files[n - 1]);
					// 释放后删除
					for (vector<vector<int>>::iterator it = files.begin(); it != files.end(); it++) {
						if (*it == files[n - 1]) {
							files.erase(it);
							break;
						}
					}
					break;
				}
			}
		}
		else if (x == 3) {  // 查看文件
			if (filesSize == 0) {
				cout << "当前文件为空!" << endl << endl;
			}
			else {
				PrintFile();
			}
		}
		else if (x == 4) {  // 查看空闲块
			PrintFreeBlock();
		}
		else if (x == 5) {  // 重构空闲块
			Refactor();
		}
		else if (x == 6) {  // 退出
			exit(0);
		}
		else {  // 其它
			cout << "错误:输入无效,请重新输入!" << endl << endl;
		}
	}
}

// 空闲块分配
void AllocateBlock(int size) {
	vector<int> f;
	cout << "分配空闲块:";
	for (int i = 0; i < size; i++) {
		if (a[0] == 1) {  // 组长块
			if (a[a[0]] == 0) {
				cout << "警告!!空闲块不足!";
				break;
			}
			int t = a[1];  // 组长块最后也用来存储
			block[group][0].isLeader = false;  // 不再是组长块
			block[group][0].isFree = false;  // 不再是空闲
			a[0] = block[group][0].size;  // 超级块栈深
			block[group][0].size = 0;
			for (int j = 0; j < 50; j++) {
				a[j + 1] = block[group][0].p[j];
			}
			group--;
			f.push_back(t);
			cout << t << " ";
		}
		else {  // 普通空闲块
			if (a[1] == 0) {  // 最后一组特殊处理
				block[group][a[0] - 2].isFree = false;  // 不再是空闲
			}
			else {
				block[group][a[0] - 1].isFree = false;  // 不再是空闲
			}
			f.push_back(a[a[0]]);
			cout << a[a[0]] << " ";
			a[0]--;
		}
	}
	files.push_back(f);
	cout << endl << endl;
}

// 空闲块释放
void ReleaseBlock(vector<int> file) {
	int fileSize = file.size();
	cout << "释放为空闲块:";
	for (int i = fileSize - 1; i >= 0; i--) {
		if (a[0] == 50) {
			group++;
			block[group][0].isLeader = true;  // 组长块
			block[group][0].isFree = true;
			block[group][0].size = 50;
			block[group][0].seq = file[i];
			for (int j = 0; j < 50; j++) {
				block[group][0].p[j] = a[j + 1];
			}
			a[0] = 1;
			a[a[0]] = file[i];  // 释放
			cout << a[a[0]] << " ";
		}
		else {
			if (a[1] == 0) {  // 特殊处理最后一组
				block[group][a[0] - 1].isFree = true;
				block[group][a[0] - 1].seq = file[i];
			}
			else {
				block[group][a[0]].isFree = true;
				block[group][a[0]].seq = file[i];
			}
			a[0]++;
			a[a[0]] = file[i];
			cout << a[a[0]] << " ";
		}
	}
	cout << endl << endl;
}

// 打印所有已分配有空闲块的文件
void PrintFile() {
	int filesSize = files.size();
	for (int i = 0; i < filesSize; i++) {
		int size = files[i].size();
		cout << "文件" << (i + 1) << "分配的块数量为" << size << ",块号分别为:";
		for (int t : files[i]) {
			cout << t << " ";
		}
		cout << endl;
	}
	cout << endl;
}

// 打印当前所有空闲块
void PrintFreeBlock() {
	if (remain == 0) {
		cout << "当前空闲块块数为0!" << endl << endl;
		return;
	}
	cout << "第1组:" << endl << "普通空闲块:";
	for (int i = 0; i <= group; i++) {
		for (int j = 0; j < 50; j++) {
			if (i == 0 && j == 49) {
				break;
			}
			if (block[i][j].isLeader) {
				cout << endl << "第" << i + 1 << "组:" << endl;
				cout << "组长块:" << block[i][j].seq << "( 成员块:";
				for (int k = 0; k < 50; k++) {
					cout << block[i][j].p[k] << " ";
				}
				cout << ")" << endl << "普通空闲块:";
			}
			else {
				if ((i == group && j >= a[0]) || !block[i][j].isFree) {
					break;
				}
				cout << block[i][j].seq << " ";
			}
		}
		cout << endl;
	}
	cout << endl;
}

// 重构成组链接空闲块
void Refactor() {
	vector<int> ivec;
	vector<int>::iterator it;
	// 收集所有块号
	for (int i = 0; i <= group; i++) {
		for (int j = 0; j < 50; j++) {
			if ((i == group && j >= a[0]) || (i == 0 && j == 49)) {
				break;
			}
			ivec.push_back(block[i][j].seq);
		}
	}
	ivec.push_back(0);
	sort(ivec.begin(), ivec.end());
	it = ivec.end() - 1;
	// 重构
	for (int i = 0; i <= group; i++) {
		for (int j = 0; j < 50; j++) {
			if (j == 0 && i != 0) {  // 组长块
				for (int k = 0; k < 50; k++) {
					if (i == 1) {  // 特殊处理第二组的组长块
						if (k == 0) {
							block[i][0].p[k] = 0;
						}
						else {
							block[i][0].p[k] = block[i - 1][k - 1].seq;
						}
						continue;
					}
					block[i][0].p[k] = block[i - 1][k].seq;
				}
				block[i][0].isLeader = true;
				block[i][0].size = 50;
				block[i][0].seq = *it;
				it--;
			}
			else {  // 普通空闲块
				if (i == 0 && j == 49) {
					break;
				}
				block[i][j].seq = *it;
				it--;
			}
			// 排序时把0也算进去排,刚好用来结束
			if (it == ivec.begin()) {
				break;
			}
		}
	}
	InitSuperBlock();  // 初始化超级块
	cout << "重构完成!!" << endl << endl;
}

  • 13
    点赞
  • 87
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要画出350k磁盘空闲的组链接结构图,需要了解以下几个方面: 1. 磁盘空闲的组织方式:一般来说,磁盘空闲会按照一定的组织方式来存储,比如可以按照某种固定大小的来划分,每个中包含多个磁盘的信息。 2. 组链接结构:组链接是一种常见的磁盘空闲管理方式,它把所有的空闲分成若干组,每组有一个表头,表头中记录了该组中空闲的编号和指向下一组表头的指针。 3. 如何表示组链接结构:一般来说,可以使用链表或者树来表示组链接结构,链表方式比较简单,每个表头中只需要包含指向下一组表头的指针即可,但是查找某个空闲时需要遍历整个链表;树的方式可以更快地查找空闲,但是实现起来比较复杂。 在具备以上知识的基础上,可以按照以下步骤来画出350k磁盘空闲的组链接结构图: 1. 首先确定每个组的大小,假设每组包含100个。 2. 然后确定组的个数,假设有3500个,则需要35个组。 3. 接着画出每个组的表头,每个表头包含两个信息:该组中空闲的编号和指向下一组表头的指针。 4. 将35个表头按照指针关系连接起来,形成一个链表结构,表示整个组链接。 下面是一个简单的示意图: ``` +------------+ +------------+ +------------+ | Group 1 | --> | Group 2 | --> | Group 3 | --> ... +------------+ +------------+ +------------+ | Free block | | Free block | | Free block | | Free block | | Free block | | Free block | | ... | | ... | | ... | +------------+ +------------+ +------------+ ``` 在实际情况下,组链接结构可能更加复杂,比如可能存在多级链接、位图等方式,但是基本原理是相似的。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值