银行家算法c++模拟
非注释版:
#include <bits/stdc++.h>
using namespace std;
int avallable[100],sum[100],cha[100],need[100][100],allocation[100][100],maxn[100][100],n,m,que[100];
bool book[100];
bool check()
{
memset(book,true,sizeof(book));
int i,j,l,k=0,ans;
i=0;
ans=i;
while(k<n)
{
for(j=0; j<m; j++)
if(cha[j]<need[i][j]||book[i]==false)
break;
if(j==m)
{
que[k++]=i;
ans=i;
book[i]=false;
for(l=0; l<m; l++)
cha[l]+=allocation[i][l];
}
i++;
i%=n;
if(i==ans)
return false;
}
return true;
}
int main()
{
int i,j;
char process[100][5];
printf("请输入进程个数n,以及资源类数m(资源默认为A,B,C,D……)\n");
printf("n=");
scanf("%d",&n);
printf("m=");
scanf("%d",&m);
printf("请输入全部资源总量:");
for(i=0; i<m; i++)
scanf("%d",&avallable[i]);
printf("请输入在某时刻的资源分配情况表:\n");
printf("格式例如:P0 2 17 10 6-1 9 3 2(其中数字个数取决于输入的资源类数m)\n");
for(i=0; i<n; i++)
{
scanf("%s",process[i]);
for(j=0; j<m; j++)
scanf("%d",&maxn[i][j]);
scanf("-");
for(j=0; j<m; j++)
scanf("%d",&allocation[i][j]);
}
printf("1.此时系统中可利用的资源向量");
for(i=0; i<m; i++)
printf("%c",65+i);
printf("为:\n");
for(j=0; j<m; j++)
for(i=0; i<n; i++)
sum[j]+=allocation[i][j];
for(i=0; i<m; i++)
cha[i]=avallable[i]-sum[i];
for(i=0; i<n; i++)
for(j=0; j<m; j++)
need[i][j]=maxn[i][j]-allocation[i][j];
for(i=0; i<m; i++)
printf("%c:%d\n",i+65,cha[i]);
printf("\n\n");
printf("2.利用银行家算法判断此时刻系统状态是否安全:\n");
if(check())
{
printf("安全\n\n\n");
printf("3.安全序列为:\n");
for(i=0; i<n; i++)
printf("%s ",process[que[i]]);
}
else
{
printf("不安全\n\n\n");
printf("3.因为系统状态不安全,所以无法给出安全序列。\n");
}
printf("\n");
return 0;
}
这里给出一些样例用以验证:
样例1
5 4
24 28 25 31
P0 2 17 10 6-1 9 3 2
P1 11 6 12 13-9 1 6 5
P2 0 0 13 11-0 0 7 4
P3 4 15 8 8-1 6 1 2
P4 9 11 9 9-5 8 2 9
样例2
5 3
17 5 20
P1 5 5 9-2 1 2
P2 5 3 6-4 0 2
P3 4 0 11-4 0 5
P4 4 2 5-2 0 4
P5 4 2 4-3 1 4
以上两组样例都可以完美运行,暂时来看代码没有什么缺陷,如果找到bug再来修复。
注释版:
#include <bits/stdc++.h>
using namespace std;
int avallable[100];//avallable[a]=b 代表系统中全部资源a总量为b
int sum[100];//sum[a]=b 代表编号为a的资源总量为b(已经给进程分配的)
int cha[100];//cha[a]=b 代表编号为a的资源还剩b(即资源总量-已经给进程分配的)
int need[100][100];//need[a][b]=c 代表编号为a的进程的b类资源还需要c
int allocation[100][100];//allocati[a][b]=c 代表已经分配给进程编号为a的b类资源c
int maxn[100][100];//maxn[a][b]=c 代表进程编号为a的进程总共需要b类资源c
int n,m;//n代表进程个数 m代表资源类数
int que[100];//模拟队列 用来保存安全序列
bool book[100];//标记数组 查找安全序列的时候需要对已经在队列中的进程标记,防止多次执行同一个进程
bool check()//检查函数 用来判断进程序列是否安全 如果安全同时计算出安全序列并把它保存到que数组中
{
memset(book,true,sizeof(book));//初始值为true,即所有进程暂时都没有进入安全序列
int i,j,l,k=0,ans;//k用来记录当前安全序列中进程的个数。ans用来记录上一次进入安全序列的进程编号,该变量可以判断进程是否安全
i=0;//对i进行初始化 即首先对编号为0的进程开始检测
ans=i;//让ans等于i
while(k<n)//while循环 当安全序列中进程的个数小于总进程数,即安全序列没有找全
{
for(j=0; j<m; j++)//遍历每一个资源类数
if(cha[j]<need[i][j]||book[i]==false)//如果当前进程所需的资源大于系统中剩余的资源或者该进程已经出现在安全序列中的话就break 跳出循环
break;
if(j==m)//如果j等于m的话 就说明上面的break没有被执行到,也就代表着当前进程的m类资源都小于系统中剩余的资源(即系统可以对其分配资源)同时,当前进程没有出现在安全序列中(如果出现在安全序列中我们就不需要再对其判断)
{
que[k++]=i;//把该进程放入安全队列中
ans=i;//更改ans的值
book[i]=false;//更改标记数组的值,代表该进程已经进入安全序列了,在以后的判断中不需要再对该进程进行判断
for(l=0; l<m; l++)//遍历m个资源,释放该进程所占有的资源
cha[l]+=allocation[i][l];
}
i++;//i++,遍历下一个进程
i%=n;//对n取模,因为while循环不确定循环多少次,所以要对n取模,确保i在[0,n)之间
if(i==ans)//如果i==ans的话就说明 经过一轮循环 遍历过所有进程,但是在这轮循环中没有进程进去安全序序列(如果进入安全序列的话ans就会更新),即说明剩下的进程请求不会被系统接纳
return false;//返回 false 说明该进程序列不安全
}
return true;//反之 如果前面没有返回ralse 同时k==n了 即说明所有进程都已进入安全序列,则说明该进程序列时安全的 同时返回true
}
int main()
{
int i,j;
char process[100][5];//记录进程名字 例如P0,P1,P2
printf("请输入进程个数n,以及资源类数m(资源默认为A,B,C,D……)\n");
printf("n=");
scanf("%d",&n);//读入进程个数n
printf("m=");
scanf("%d",&m);//如果资源类数m
printf("请输入全部资源总量:");
for(i=0; i<m; i++)
scanf("%d",&avallable[i]);//分别读入系统中全部的资源总量
printf("请输入在某时刻的资源分配情况表:\n");
printf("格式例如:P0 2 17 10 6-1 9 3 2(其中数字个数取决于输入的资源类数m)\n");
for(i=0; i<n; i++)//读入进程
{
scanf("%s",process[i]);//进程的名字
for(j=0; j<m; j++)//遍历m类资源
scanf("%d",&maxn[i][j]);//进程需要的总资源
scanf("-");
for(j=0; j<m; j++)//遍历m类资源
scanf("%d",&allocation[i][j]);//系统已经分配给进程的资源
}
printf("1.此时系统中可利用的资源向量");
for(i=0; i<m; i++)
printf("%c",65+i);//用来输出A,B,C…… 代表资源A 资源B 资源C ……
printf("为:\n");
for(j=0; j<m; j++)
for(i=0; i<n; i++)
sum[j]+=allocation[i][j];//计算系统一共分配的编号为j的资源数目(遍历每一个进程)
for(i=0; i<m; i++)
cha[i]=avallable[i]-sum[i];//计算当前系统中还剩编号为i的资源的数目
for(i=0; i<n; i++)
for(j=0; j<m; j++)
need[i][j]=maxn[i][j]-allocation[i][j];//计算编号为i的进程还需要编号为j的资源数目
for(i=0; i<m; i++)
printf("%c:%d\n",i+65,cha[i]);//输出当前系统中还剩编号为i的资源的数目
printf("\n\n");
printf("2.利用银行家算法判断此时刻系统状态是否安全:\n");
if(check())//如果检查函数返回值是true,即代表该进程序列是安全的
{
printf("安全\n\n\n");
printf("3.安全序列为:\n");
for(i=0; i<n; i++)
printf("%s ",process[que[i]]);//按顺序输出进程的名字
}
else//如果此时系统状态不安全
{
printf("不安全\n\n\n");
printf("3.因为系统状态不安全,所以无法给出安全序列。\n");
}
printf("\n");
return 0;
}
最终版:
//编译语言 c++
#include <bits/stdc++.h>
#define Coding author 计科1905孙黎明
using namespace std;
int avallable[100];//avallable[a]=b 代表系统中全部资源a总量为b
int sum[100];//sum[a]=b 代表编号为a的资源总量为b(已经给进程分配的)
int cha[100];//cha[a]=b 代表编号为a的资源还剩b(即资源总量-已经给进程分配的)
int need[100][100];//need[a][b]=c 代表编号为a的进程的b类资源还需要c
int allocation[100][100];//allocati[a][b]=c 代表已经分配给进程编号为a的b类资源c
int maxn[100][100];//maxn[a][b]=c 代表进程编号为a的进程总共需要b类资源c
int n,m;//n代表进程个数 m代表资源类数
int que[100];//模拟队列 用来保存安全序列
bool book[100];//标记数组 查找安全序列的时候需要对已经在队列中的进程标记,防止多次执行同一个进程
void initialization()//清空函数,把所有变量清空,为下一次计算安全序列做准备
{
memset(sum,0,sizeof(sum));
memset(cha,0,sizeof(cha));
memset(need,0,sizeof(need));
memset(que,0,sizeof(que));
}
bool check()//检查函数 用来判断进程序列是否安全 如果安全同时计算出安全序列并把它保存到que数组中
{
memset(book,true,sizeof(book));//初始值为true,即所有进程暂时都没有进入安全序列
int i,j,l,k=0,ans;//k用来记录当前安全序列中进程的个数。ans用来记录上一次进入安全序列的进程编号,该变量可以判断进程是否安全
i=0;//对i进行初始化 即首先对编号为0的进程开始检测
ans=i;//让ans等于i
while(k<n)//while循环 当安全序列中进程的个数小于总进程数,即安全序列没有找全
{
for(j=0; j<m; j++)//遍历每一个资源类数
if(cha[j]<need[i][j]||book[i]==false)//如果当前进程所需的资源大于系统中剩余的资源或者该进程已经出现在安全序列中的话就break 跳出循环
break;
if(j==m)//如果j等于m的话 就说明上面的break没有被执行到,也就代表着当前进程的m类资源都小于系统中剩余的资源(即系统可以对其分配资源)同时,当前进程没有出现在安全序列中(如果出现在安全序列中我们就不需要再对其判断)
{
que[k++]=i;//把该进程放入安全队列中
ans=i;//更改ans的值
book[i]=false;//更改标记数组的值,代表该进程已经进入安全序列了,在以后的判断中不需要再对该进程进行判断
for(l=0; l<m; l++)//遍历m个资源,释放该进程所占有的资源
cha[l]+=allocation[i][l];
}
i++;//i++,遍历下一个进程
i%=n;//对n取模,因为while循环不确定循环多少次,所以要对n取模,确保i在[0,n)之间
if(i==ans)//如果i==ans的话就说明 经过一轮循环 遍历过所有进程,但是在这轮循环中没有进程进去安全序序列(如果进入安全序列的话ans就会更新),即说明剩下的进程请求不会被系统接纳
return false;//返回 false 说明该进程序列不安全
}
return true;//反之 如果前面没有返回ralse 同时k==n了 即说明所有进程都已进入安全序列,则说明该进程序列时安全的 同时返回true
}
int main()
{
int i,j;
int flag;//记录预分配进程编号
char process[100][5];//记录进程名字 例如P0,P1,P2
char str[10];//保存预分配进程名称
int before[100];//before[a]=b 代表预分配进程需要a类资源的数量为b
printf("请输入进程个数n,以及资源类数m(资源默认为A,B,C,D……)\n");
printf("n=");
scanf("%d",&n);//读入进程个数n
printf("m=");
scanf("%d",&m);//如果资源类数m
printf("请输入全部资源总量:");
for(i=0; i<m; i++)
scanf("%d",&avallable[i]);//分别读入系统中全部的资源总量
printf("\n");
printf("请输入在某时刻的资源分配情况表:\n");
printf("进程名称\t进程所需最大资源数量\t系统已经分配给进程的资源数\n");
printf("格式例如:\nP0\t\t2 17 10 6\t\t1 9 3 2 (数字个数取决于资源类数)\n");
for(i=0; i<n; i++)//读入进程
{
scanf("%s",process[i]);//进程的名字
for(j=0; j<m; j++)//遍历m类资源
scanf("%d",&maxn[i][j]);//进程需要的总资源
for(j=0; j<m; j++)//遍历m类资源
scanf("%d",&allocation[i][j]);//系统已经分配给进程的资源
}
printf("\n\n1.此时系统中可利用的资源向量");
for(i=0; i<m; i++)
printf("%c",65+i);//用来输出A,B,C…… 代表资源A 资源B 资源C ……
printf("为:\n");
for(j=0; j<m; j++)
for(i=0; i<n; i++)
sum[j]+=allocation[i][j];//计算系统一共分配的编号为j的资源数目(遍历每一个进程)
for(i=0; i<m; i++)
cha[i]=avallable[i]-sum[i];//计算当前系统中还剩编号为i的资源的数目
for(i=0; i<n; i++)
for(j=0; j<m; j++)
need[i][j]=maxn[i][j]-allocation[i][j];//计算编号为i的进程还需要编号为j的资源数目
for(i=0; i<m; i++)
printf("%c:%d\n",i+65,cha[i]);//输出当前系统中还剩编号为i的资源的数目
printf("\n\n");
printf("2.利用银行家算法判断此时刻系统状态是否安全:\n");
if(check())//如果检查函数返回值是true,即代表该进程序列是安全的
{
printf("安全\n\n\n");
printf("3.安全序列为:\n");
for(i=0; i<n; i++)
printf("%s ",process[que[i]]);//按顺序输出进程的名字
}
else//如果此时系统状态不安全
{
printf("不安全\n\n\n");
printf("3.因为系统状态不安全,所以无法给出安全序列。\n");
}
printf("\n\n\n");
initialization();//清空函数 清空变量的值
printf("4.若进程x提出请求y,系统能否将资源分配给它?\n");
printf("例如:\nx:P0\ny:0 1 1 0\nps:其中数字个数取决于资源类数\n\n");
printf("x:");
scanf("%s",str);//读入预分配进程的名称
printf("y:");
for(i=0; i<m; i++)
scanf("%d",&before[i]);//分别读入预分配进程所需的各类资源数量
printf("\n\n");
for(i=0; i<n; i++)//遍历所有进程
if(strcmp(process[i],str)==0)//如果发现进程名称等于预分配进程名称,即找到对应的进程
{
flag=i;//用变量flag标记进程编号
break;
}
for(i=0; i<m; i++)
allocation[flag][i]+=before[i];//由于预分配,所以改变原本系统分配给该进程的资源数量
/******************************/ //该部分与上面相同,作用是用来处理数据 计算所需要数据的值
for(j=0; j<m; j++)
for(i=0; i<n; i++)
sum[j]+=allocation[i][j];//计算系统一共分配的编号为j的资源数目(遍历每一个进程)
for(i=0; i<m; i++)
cha[i]=avallable[i]-sum[i];//计算当前系统中还剩编号为i的资源的数目
for(i=0; i<n; i++)
for(j=0; j<m; j++)
need[i][j]=maxn[i][j]-allocation[i][j];//计算编号为i的进程还需要编号为j的资源数目
/******************************/
if(check())//如果系统状态安全,且存在安全序列
{
printf("系统能否把资源预分配给它?能\n\n\n");
printf("预分配后安全序列为:\n");
for(i=0; i<n; i++)
printf("%s ",process[que[i]]);//按顺序输出进程的名字
}
else//如果系统不安全,也不存在安全序列
{
printf("系统能否把资源预分配给它?不能\n\n\n");
printf("因为预分配后系统状态不安全,所以无法给出安全序列。\n");
}
printf("\n");
return 0;
}
输入样例1:
5 4
24 28 25 31
P0 2 17 10 6 1 9 3 2
P1 11 6 12 13 9 1 6 5
P2 0 0 13 11 0 0 7 4
P3 4 15 8 8 1 6 1 2
P4 9 11 9 9 5 8 2 9
P1
0 1 0 1
输出样例1:
1.此时系统中可利用的资源向量ABCD为:
A:8
B:4
C:6
D:9
2.利用银行家算法判断此时刻系统状态是否安全:
安全
3.安全序列为:
P2 P4 P0 P1 P3
4.若进程x提出请求y,系统能否将资源分配给它?
系统能否把资源预分配给它?能
预分配后安全序列为:
P2 P4 P0 P1 P3
输入样例2:
5 3
17 5 20
P1 5 5 9 2 1 2
P2 5 3 6 4 0 2
P3 4 0 11 4 0 5
P4 4 2 5 2 0 4
P5 4 2 4 3 1 4
P2
0 3 4
输出样例2:
1.此时系统中可利用的资源向量ABC为:
A:2
B:3
C:3
2.利用银行家算法判断此时刻系统状态是否安全:
安全
3.安全序列为:
P4 P5 P1 P2 P3
4.若进程x提出请求y,系统能否将资源分配给它?
系统能否把资源预分配给它?不能
因为预分配后系统状态不安全,所以无法给出安全序列。
输入样例3:
5 3
17 5 20
P1 5 5 9 2 1 2
P2 5 3 6 4 0 2
P3 4 0 11 4 0 5
P4 4 2 5 2 0 4
P5 4 2 4 3 1 4
P4
2 0 1
输出样例3:
1.此时系统中可利用的资源向量ABC为:
A:2
B:3
C:3
2.利用银行家算法判断此时刻系统状态是否安全:
安全
3.安全序列为:
P4 P5 P1 P2 P3
4.若进程x提出请求y,系统能否将资源分配给它?
系统能否把资源预分配给它?能
预分配后安全序列为:
P4 P5 P1 P2 P3
一、算法或原理的实现思想:
算法:算法的话是银行家算法,用于判断给定的序列是否安全,系统能否给他们分配相应的资源。
实现思想:我个人的实现思想就是模拟,银行家算法总的来说并不难,但是可能比较麻烦,需要一步步模拟,计算出每个进程所需要的资源,系统中每个资源所剩的数目等等。
遇到的困难:总体来说还可以,只要理解银行家算法整个过程,写起来就很好写了,要说难点的话,我代码的难点主要在check函数(检查函数)中,也是我整个代码最核心的部分,用来判断序列是否安全,以及求出相应的安全序列。我用了while循环,由于不确定循环次数,其中i%n也是很重要的,因为要保证编号位于[0,1)之前,同时用que数组模拟队列,用来保存安全序列,其中在进行预分配前需要把之前计算的一些数据清零(因为那是前一次处理的参与数据,不清零的话会影响后续数据的计算),在敲的时候我没有意识到这一点,然后测数据的时候出现了错误,我才意识到需要清零。
可以改进的地方:我的代码中有一部分用了两次,就是/***/框中的那部分,其实可以把它单独写成一个处理函数,这样在对它进行二次调用的时候就可以直接调用函数了,思路上并没有什么改变,但是可以使代码看起来更整洁。
ps:我所测得数据均是网络信息综合教育平台上《操作系统》的在线测试题,即银行家算法随堂测试1和银行家算法随堂测试2
四、参考文献:
参考网址:http://etcnew.sdut.edu.cn/meol/jpk/course/layout/newpage1/index.jsp?courseId=45133(山东理工大学网络信息综合教育平台《操作系统》在线测试)参考输入样例和答案。
没有参考其它书籍和同学交流。
五、感想体会或收获:
更加熟悉银行家算法了,因为在敲代码之前我又复习了一下银行家算法,把网络教学平台上的两个在线测试又做了一遍,复习了一下,然后就开始敲代码,在理解了算法之后敲代码就比较简单了,就是按照做题思路来敲,锻炼了动手能力,也对银行家算法了解更深了。
注:另外还有一些完整的解题思路以及我改代码的整个过程都放到了博客:https://blog.csdn.net/qq_34035720/article/details/109998841上。