银行家算法
银行家算法的概述
银行家算法是一种避免死锁,为不同进程分配资源的,保证不同进程都能分配到资源,最终求出实现资源分配后不同进程运行的序列的算法,并将此序列称为安全序列, 具体的原理和解释就看书吧~ 我这里将书中的例子写成代码,时间关系目前先不详解啦,在这里给出的代码实现的过程。
银行家算法代码
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e3 + 10;
int m , n;
int Max[N][N], Allocation[N][N], Need[N][N], Available[N], temp[N];
bool finish[N], notExistSeq = true;
string ans;
/**
* 银行家算法 :
* 声明几个对应的数组含义
* max表示不同进程 对不同的资源 需要的最大的资源的个数
* Allocation 表示已经分配的资源
* need 表示 还需要分配的资源的个数
* available 表示当前 可用的资源个数
* m 表示列的个数 列代表对应的资源的种类的数量 资源 A B C .....
* n 表示 行的个数, 对应代表了进程种类的数量 p0 p1 p2 p3 p4 .....
* ans 表示安全序列中一个答案
*/
void init() {
cout << "依次 输入进程数量 和资源的数量 " << endl;
cin >> n >> m;
cout << "输入当前的可用资源" << endl;
for (int i = 0; i < m; ++i)
cin >> Available[i];
cout << "依次输入最大的分配" << endl;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
cin >> Max[i][j];
cout << "依次输入当前已经分配的资源" << endl;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++ )
cin >> Allocation[i][j];
for (int i = 0; i < n; i ++)
for (int j = 0; j < m; j ++ )
Need[i][j] = Max[i][j] - Allocation[i][j];
// 矩阵转置
for (int i = 0; i < m; i++){
for (int j = 0; j < n; j++){
// printf("%d ", Allocation [j][i]);
Available[i] -= Allocation [j][i];
}
temp[i] = Available[i];
}
}
void showbaseinfo(){
printf("\n Max Allocation Need\n");
for (int i = 0; i < n; i++ ){
for (int j = 0; j < m; j++)
printf("%3d", Max[i][j]);
printf("%*s", 6, "");
for (int j = 0; j < m; j++)
printf("%3d", Allocation[i][j]);
printf("%*s", 6, "");
for (int j = 0; j < m; j++)
printf("%3d", Need[i][j]);
printf("\n");
}
printf("\n初始的当前资源可用值为: \n");
for (int i = 0; i < m; i++)
printf("%d ", Available[i]);
puts("");
}
void release(int row){
for(int i = 0; i < m; i++)
Available[i] += Allocation[row][i];
finish[row] = true;
ans += row + '0';
}
void rollBack(int row){
for(int i = 0; i < m; i++)
Available[i] -= Allocation[row][i];
finish[row] = false;
ans = string(ans, 0, ans.size() - 1);
}
bool couldRecheak(){
for (int i = 0; i < n; i++)
if (finish[i] == false) return true;
return false;
}
bool getSafeSequence(){
notExistSeq = true;
for (int i = 0; i < n ; i++){
if (finish[i] == false){
bool flag = true;
for (int j = 0; j < m; j++)
if (Need[i][j] > Available[j]) flag = false;
if (flag) release(i), notExistSeq = false;
}
}
return !notExistSeq;
}
void recheak(){
while (couldRecheak() && getSafeSequence());
}
void setdefault(){
for (int i = 0; i < m; i ++) Available[i] = temp[i];
for (int i = 0; i < n; i ++) finish[i] = false;
ans = "";
}
void dfs(int cur){
//递归的出口
if (cur == n){
printf("安全序列为%s\n", ans.c_str());
return;
}
for (int i = 0 ; i < n; i ++){
if (!finish[i]){
bool flag = true;
for (int j = 0; j < m; j++)
if (Need[i][j] > Available[j]) flag = false;
if (flag){
release(i);
dfs(cur + 1);
rollBack(i);
}
}
}
}
int main() {
init();
showbaseinfo();
getSafeSequence();
recheak();
if (!notExistSeq){
printf("当前资源分配的安全序列之一为%s", ans.c_str());
printf("是否要出输全部的安全序列呢 ?yes(1) or (0)\n");
int a;
scanf("%d", &a);
if (a) setdefault(), dfs(0);
else printf("欢迎下次使用\n");
}
else printf("不存在安全的序列\n");
return 0;
}
测试样例
给出书中的样例 直接复制输入即可:
/*
书中的案例:
5 3
10 5 7
7 5 3
3 2 2
9 0 2
2 2 2
4 3 3
0 1 0
2 0 0
3 0 2
2 1 1
0 0 2
如果分配为 不存在安全序列的值
5 3
0 1 0
7 5 3
3 2 2
9 0 2
2 2 2
4 3 3
0 1 0
2 0 0
3 0 2
2 1 1
0 0 2
*/
代码思路 错误分析
说一下思考过程 写代码的时候注意一下几点
-
求安全序列的是每次都应当检查当前的
available
是否满足当前的need
,如果都不满足的话, 那么就没有安全序列, 即检查是否满足条件,第一次写的时候很容易忘的 -
安全序列的求解问题
我们可以直到安全序列并不是唯一的,我记得这一点上课的时候老师也讲了,但是并没有说具体由多少种安全序列,我自己思考了一下,应该是 12种
12种的由来: 不难算出起始的
available
对应每种资源 是 3 3 2 根据need
的值 满足条件available[i]
>=need[i]
由两个 分别是p1
,p3
所以说p1
,p3
,两个顺序是可以互换的,当执行完p1
,p3
的时候释放资源此时available
的中资源的可用的数量就是 7 3 3 此时是满足其他三个进程的条件的所以剩余的三个进程p2
,p0
,p4
执行的顺序是可以任意互换的,由此我以为是两次的全排列相乘即 A 2 2 ∗ A 3 3 {A_2^2 * A_3^3} A22∗A33 答案就是 12种之后课间我还去问了下老师,我这么想对不对, 她说对,我又问算法实现是不是写出需要全部的安全序列呢? emmmm,搪塞了一下,借马上上课没说清楚~~ 唉! 不得不说差距产生的原因确实也有这一方面吧~
正确的思路 :刚刚提到的
p1
,p3
和p2
,p0
,p4
确实是可以的顺序互换的,但是 当p1
, 或者p3
执行完成后,会释放资源 在刚刚的例子中,当p1
, 或者p3
执行完成后available
是 5 2 2 或 5 3 3,再次检测其实p4
是可以p1
或p3
运行的 ,即忽略了当前进程执行完 再次检测后就可能会出现可以分配资源的进程,available[i]
>=need[i]
不仅仅是看当前第一次条件有p1
p3
,其实是每次释放后的都要检测,类似理解与并发 的过程,并不是同时进行的,虽然cpu处理速度快宏观上看起来是同时的。一个细节理解偏差出大错了! -
求全部的安全序列
刚刚也说道到了求全部的安全顺序问题,是根据全排列的过程计算的 全排列是可以用dfs求解的,就是基于字符串的全排列问题,看一个简单的例子123 全排列代码实现:
#include <iostream> using namespace std; const int N = 10; int a[N], n; bool visit[N]; void dfs(int cur){ if (cur == n){ for (int i = 0; i < n; i++) printf("%d ", a[i]); cout << endl; return; } for (int i = 1; i <= n; i++){ if (!visit[i]){ a[cur] = i; visit[i] = true; dfs(cur + 1); visit[i] = false; } } } int main(){ scanf("%d", &n); dfs(0); return 0; }
有了刚刚那个题的思路,全安全序列只不过就是在其中添加条件而已了,类似理解为剪枝吧(一开始 以为 12中看结果 以为我递归写错了hh)
void dfs(int cur){ //递归的出口 if (cur == n){ printf("安全序列为%s\n", ans.c_str()); return; } for (int i = 0 ; i < n; i ++){ if (!finish[i]){ bool flag = true; for (int j = 0; j < m; j++) if (Need[i][j] > Available[j]) flag = false; if (flag){ release(i); dfs(cur + 1); rollBack(i); } } } }
运行结果
实现结果说明我刚刚分析确实不是 12种诶 看结果如下: