You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

稳定婚姻问题Rotation查找算法实现故障排查求助

稳定婚姻问题旋转查找算法实现异常排查

我们正在实现Dan Gusfield 1987年论文《Three Fast Algorithms for Four Problems in Stable Marriage》第6-7页描述的稳定婚姻问题旋转查找算法,但代码出现以下问题:

  • breakmarriage函数本不应失败退出,实际却触发失败分支,导致内存随机访问引发程序崩溃;
  • 部分测试用例中,旋转总数正确,但无前驱的Rotation数量超出预期。

数据结构定义

#include <stdlib.h>

struct ResultsList {
    struct ResultsListElement* first;
    struct ResultsListElement* last;
};

struct ResultsListElement {
    char* value;    // 匹配结果
    struct ResultsListElement* next;
};

struct RotationList { // list_el
    char man;
    char woman;
    struct RotationList* next;
};

struct RotationNode {
    struct RotationList* rotation;
    int index;
    int missing_predecessors;
    struct SuccessorsList* successors;
};

struct SuccessorsList {
    struct RotationNode* value;
    struct SuccessorsList* next;
};

struct RotationsList { // free_rotations_list
    struct RotationsListElement* first;
    struct RotationsListElement* last;
};

struct RotationsListElement { // free_rotations_list
    struct RotationNode* value;
    struct RotationsListElement* next;
};

void appendResultsList(struct ResultsList* list, char* result){
    struct ResultsListElement *new = malloc(sizeof (struct ResultsListElement));
    new->value = result;
    new->next = NULL;
    if (list->first==NULL){
        list->first = new;
        list->last=new;
    }else{
        list->last->next = new;
        list->last = new;
    }
}

void appendRotationsList(struct RotationsList* list, struct RotationNode* rotation_node){
    struct RotationsListElement *new = malloc(sizeof (struct RotationsListElement));
    new->value = rotation_node;
    new->next = NULL;
    if (list->first==NULL){
        list->first = new;
        list->last=new;
    }else{
        list->last->next = new;
        list->last = new;
    }
}

算法实现代码

#include <stdlib.h>
#include "..\data_structures\data_structures.h"

#define false 0
#define true 1

char* gale_shapley(int, int*, int*);
int accept_proposal(int*, int, int, int, int);
struct RotationsList* find_all_rotations(int*, int*, int, char*);
void breakmarriage(char*, int, int, int*, int*, int*, int*, struct RotationsList*, struct RotationNode**, int*, int*, int);
void pause_breakmarriage(int*, char*, char*, char*, struct RotationsList*, int, int, struct RotationNode**, int*, int*);
void recursive_search(char*, int, struct RotationsListElement*, struct ResultsList*);


char* gale_shapley(int n, int* men_preferences, int* women_preferences) {
    int women_partners[n], men_free[n];
    for (int i = 0; i < n; i++) {
        women_partners[i] = -1;
        men_free[i] = true;
    }

    while (true) {
        int m = -1;
        for (int i = 0; i < n; i++) {
            if (men_free[i]){
                m = i;
                break;
            }
        }
        if (m == -1) {
            break;
        }

        for (int i = 0; i < n && men_free[m]; i++) {
            int w = men_preferences[m * n + i];
            if (women_partners[w] == -1) {
                women_partners[w] = m;
                men_free[m] = false;
            } else {
                int m1 = women_partners[w];
                if (accept_proposal(women_preferences, n, w, m, m1)) {
                    women_partners[w] = m;
                    men_free[m] = false;
                    men_free[m1] = true;
                }
            }
        }
    }
    char* matching = (char*)malloc(n * sizeof(char));
    for (char i = 0; i < n; i++) {
        matching[women_partners[i]] = i;
    }
    return matching;
}


int accept_proposal(int* women_preferences, int n, int w, int m, int m1) {
    for (int i = 0; i < n; i++) {
        if (women_preferences[w * n + i] == m) {
            return true;
        }
        if (women_preferences[w * n + i] == m1) {
            return false;
        }
    }
    return 0;
}


struct RotationsList* find_all_rotations(int* men_preferences, int* women_preferences, int n, char* top_matching) {
    struct RotationsList* free_rotations_list = (struct RotationsList*) malloc(sizeof (struct RotationsList));
    free_rotations_list->first=NULL;
    free_rotations_list->last=NULL;
    struct RotationNode** last_to_have_modified = (struct RotationNode**)malloc(sizeof (struct RotationNode) * n); // 记录每个男人最后被哪个旋转节点修改的指针数组
    char* m_i = (char*) malloc(sizeof (char) * n);
    char* inverted_bottom_matching = gale_shapley(n, women_preferences, men_preferences);
    char* bottom_matching = (char*)malloc(sizeof (char) * n);
    for(int i=0;i<n;i++){
        bottom_matching[inverted_bottom_matching[i]]=i;
    }
    
    int* marking = (int*) malloc(sizeof (int) * n); // -1=未标记,n=标记但未配对,其他值为前一个女人
    int rotation_index = 0; // 用于给旋转节点编号,对应already_added_predecessors的索引
    int* already_added_predecessors = (int*) malloc(sizeof (int) * (n*n)); // 用于减少旋转图中的重复边

    for (int j = 0; j < n; j++) {
        m_i[j] = top_matching[j];
        marking[j] = -1;
        last_to_have_modified[j] = NULL;
    }
    int* men_preferences_indexes = (int*) malloc(sizeof (int) * n);
    for (int j = 0; j < n*n; j++) {
        already_added_predecessors[j] = false;
    }
    // 排除不可能出现在稳定匹配中的偏好
    for (int j = 0; j < n; j++) {
        int k = 0; 
        while (men_preferences[j * n + k] != m_i[j]) {
            k++;
        }
        men_preferences_indexes[j] = k+1; // 跳过当前匹配的偏好,只保留后续的
    }

    int old_m = 0;
    while (true) {
        // STEP 1
        int m = -1;
        // 找到第一个在m_i和bottom_matching中匹配不同的男人
        for (int j = old_m; j < n; j++) {
            if (m_i[j] != bottom_matching[j]) {
                m = j; 
                old_m = j;
                break;
            }
        }

        if (m < 0) { // m_i等于bottom_matching,结束循环
            break;
        }
        
        // STEP 2
        char w = m_i[m];
        marking[w] = n;
        breakmarriage(m_i, m, n, men_preferences, men_preferences_indexes, women_preferences, marking, free_rotations_list, 
                      last_to_have_modified, &rotation_index, already_added_predecessors, w);
    }
    free(last_to_have_modified);
    free(m_i);
    free(marking);
    free(already_added_predecessors);
    free(men_preferences_indexes);
    free(inverted_bottom_matching);
    free(bottom_matching);
    return free_rotations_list;
}


void breakmarriage(char* M, int m, int n, int* men_preferences, int* men_preferences_indexes, int* women_preferences, int* marking,
                   struct RotationsList* free_rotations_list, struct RotationNode** last_to_have_modified, int* rotation_index, 
                   int* already_added_predecessors, int first_woman) {
    int i = 0;
    while (men_preferences[m * n + i] != M[m]) { // 是否需要?
        i++;
    }
    men_preferences_indexes[m] = i + 1;
    int former_wife = M[m]; // 论文中的w,即当前男人的配偶,需要解除婚姻
    char* reversed_M = (char*)malloc(sizeof (char) * n);
    char* old_reversed_M = (char*)malloc(sizeof (char) * n);
    for (i = 0; i < n; i++) {
        reversed_M[M[i]] = i;
        old_reversed_M[M[i]] = i;
    }
    int w, m1, breakmarriage_fail, k, old_marking;
    int previous_woman = first_woman;

    while(true) {
        breakmarriage_fail = true;
        // 遍历m的偏好列表
        // 循环内m会变成论文中的m'
        for (i = men_preferences_indexes[m]; i < n; i++) {
            w = men_preferences[m * n + i]; // 论文中的w
            // 获取w当前的配偶m1,并和m比较
            m1 = reversed_M[w];
            // 如果w更偏好m而非m1,解除(w,m1)并配对(w,m)
            if (marking[w] < 0 && accept_proposal(women_preferences, n, w, m, m1)) { // step 2a
                k = men_preferences_indexes[m]; // 更新索引
                while (men_preferences[k] != w) {
                    k++;
                }
                men_preferences_indexes[m] = k+1;
                reversed_M[w] = m;
                marking[w] = previous_woman;
                previous_woman = w;
                m = m1; // 新的未配对男人
                breakmarriage_fail = false;
                break;
            } else if (accept_proposal(women_preferences, n, w, m, old_reversed_M[w])) { // step 2b
                breakmarriage_fail = false;
                old_marking = marking[w];
                reversed_M[w] = m;
                pause_breakmarriage(marking, M, reversed_M, old_reversed_M, free_rotations_list, w, previous_woman, 
                                    last_to_have_modified, rotation_index, already_added_predecessors);
                reversed_M[w] = m1;
                if (former_wife == w) { // 3c: w = w'
                    reversed_M[w] = m;
                    free(reversed_M);
                    free(old_reversed_M);
                    return; // 返回step 1
                } else {
                    if (!accept_proposal(women_preferences, n, w, m, m1)) {
                        marking[w] = old_marking;
                        previous_woman = w;
                        continue; // 返回step 2
                    } else {
                        reversed_M[w] = m;
                        m = m1; // m1是否正确?还是应该是其他值?
                        break;
                    }
                }
            }
        }
        if (breakmarriage_fail) { // 无法为m找到稳定配对
            free(reversed_M);
            free(old_reversed_M);
            return;
        }
    }
}


void pause_breakmarriage(int* marking, char* M, char* reversed_M, char* old_reversed_M, struct RotationsList* free_rotations_list, int w, 
                         int previous_woman, struct RotationNode** last_to_have_modified, int* rotation_index, int* already_added_predecessors) {
    int no_predecessors = true;
    struct RotationList* prev_list_el = NULL;
    int w2 = w;
    int go_on = true;
    struct RotationNode* rotation_node = (struct RotationNode*)malloc(sizeof (struct RotationNode));
    rotation_node->missing_predecessors = 0;
    rotation_node->index = *rotation_index;
    rotation_node->successors=NULL;
    *rotation_index += 1;
    struct RotationsList* predecessors_list = (struct RotationsList*)malloc(sizeof (struct RotationsList)); // 记录当前旋转节点的前驱,用于重置already_added_predecessors
    predecessors_list->first = NULL;
    predecessors_list->last=NULL;
    struct RotationList* list_el = NULL;
    struct SuccessorsList* new_successor;
    while(w2 != w || go_on) {
        go_on = false;
        // 从尾到头构建旋转列表
        list_el = (struct RotationList*)malloc(sizeof (struct RotationList));
        list_el->man = old_reversed_M[w2];
        list_el->woman = w2;
        list_el->next = prev_list_el;
        prev_list_el = list_el;
        // 更新前驱和last_to_have_modified
        if (last_to_have_modified[old_reversed_M[w2]] != NULL && !already_added_predecessors[last_to_have_modified[old_reversed_M[w2]]->index]) {
            new_successor = (struct SuccessorsList*)malloc(sizeof (struct SuccessorsList));
            new_successor->value = rotation_node;
            // 每个前驱只添加一次当前旋转节点
            new_successor->next = last_to_have_modified[old_reversed_M[w2]]->successors;
            last_to_have_modified[old_reversed_M[w2]]->successors = new_successor;
            no_predecessors = false;
            rotation_node->missing_predecessors += 1;
            already_added_predecessors[last_to_have_modified[old_reversed_M[w2]]->index] = true;
            appendRotationsList(predecessors_list, last_to_have_modified[old_reversed_M[w2]]);
        }
        last_to_have_modified[old_reversed_M[w2]] = rotation_node;
        // 更新old_reversed_M (i = i+1)
        old_reversed_M[w2] = reversed_M[w2];
        // 更新M
        M[old_reversed_M[w2]] = w2;
        // 重置marking
        marking[w2] = -1;
        // 更新previous_woman
        w2 = previous_woman;
        previous_woman = marking[w2];
    }

    rotation_node->rotation = prev_list_el;

    if (no_predecessors) {
        appendRotationsList(free_rotations_list, rotation_node);
    }

    // 重置already_added_predecessors并释放空间
    struct RotationsListElement* rot_list_el = predecessors_list->first;
    struct RotationsListElement * temp;
    
    while (rot_list_el != NULL) {
        already_added_predecessors[rot_list_el->value->index] = false;
        temp = rot_list_el;
        rot_list_el = rot_list_el->next;
        free(temp);
    }

    free(predecessors_list);
    return;
}

触发问题的测试输入示例

2 0 1
0 1 2
1 0 2

2 0 1
0 1 2
1 2 0

内容的提问来源于stack exchange,提问作者StefanoTrv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 15:57:01