银行家的算法实现—全部安全序列求解dfs以及错误分析

本文深入探讨银行家算法,一种避免死锁的资源分配算法,通过实例代码演示如何确保系统安全状态,避免进程间资源竞争导致的死锁现象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

银行家算法

银行家算法的概述

银行家算法是一种避免死锁,为不同进程分配资源的,保证不同进程都能分配到资源,最终求出实现资源分配后不同进程运行的序列的算法,并将此序列称为安全序列, 具体的原理和解释就看书吧~ 我这里将书中的例子写成代码,时间关系目前先不详解啦,在这里给出的代码实现的过程。

银行家算法代码

#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} A22A33 答案就是 12种

    之后课间我还去问了下老师,我这么想对不对, 她说对,我又问算法实现是不是写出需要全部的安全序列呢? emmmm,搪塞了一下,借马上上课没说清楚~~ 唉! 不得不说差距产生的原因确实也有这一方面吧~

    正确的思路 :刚刚提到的p1, p3p2, p0, p4确实是可以的顺序互换的,但是 当p1, 或者p3执行完成后,会释放资源 在刚刚的例子中,当p1, 或者 p3执行完成后available是 5 2 2 或 5 3 3,再次检测其实p4是可以 p1p3运行的 ,即忽略了当前进程执行完 再次检测后就可能会出现可以分配资源的进程,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种诶 看结果如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值