Реализация неориентированного графа с матрицей смежности - PullRequest
0 голосов
/ 24 апреля 2019

Я пытался реализовать ненаправленный граф с матрицей смежности.
Тип значения вершины - целое число. И я использую двойной указатель для представления матрицы смежности.

Вопрос возникает сразу после того, как я ввел все значения вершин, поскольку, как я
запрограммировал из кода, который я разместил ниже, произошла ошибка времени выполнения
. Затем я добавил комментарий в строку с содержанием ошибки
, из которой происходит ошибка. Я знаю, что причиной должен быть двойной указатель
. Но я действительно понятия не имею, как его отладить.
Может ли кто-нибудь мне помочь? Спасибо!

#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
    int adj;
}verNode;
typedef struct graph
{
    verNode **matrix;
    int* verList;
    int verNum;
    int edgeNum;
}graph;
graph* createGraph(int v)
{
    graph *g=malloc(sizeof(graph));
    if(!g) exit(-1);
    g->matrix=NULL;
    g->verList=malloc(sizeof(verNode)*v);
    if(!g->verList) exit(-1);
    g->verNum=v;
    printf("Enter the value of vertices:\n");
    for(int i=0;i<g->verNum;i++)
    {
        printf("Enter the value of vertex %d:\n",i);
        scanf("%d",g->verList);
    }
    return g;
}
verNode** createMatrix(graph *g)
{
    if(!g) exit(-1);
    g->matrix=malloc(sizeof(int*)*g->verNum*g->verNum);
    if(!g->matrix) exit(-1);
    for(int i=0;i<g->verNum;i++)
    {
        for(int j=0;j<g->verNum;j++)
        {
            (*g->matrix)->adj=0; //error:EXC_BAD_ACCESS (code=1,           //address=0x0)
        }
    }
    return g->matrix;
}
void addEdge(graph *g,int v)
{
    if(!g||!g->matrix||!g->verList) exit(-1);
    int ver1,ver2;
    g->edgeNum=v;
    printf("Enter the indexes of the vertices:\n");
    for(int i=0;i<g->edgeNum;i++)
    {
        printf("Enter the index of vertex 1:\n");
        scanf("%d",&ver1);
        printf("Enter the index of vertex 2:\n");
        scanf("%d",&ver2);
        if(ver1>g->verNum-1||ver2>g->verNum-1) exit(-1);
        g->matrix[ver1][ver2].adj=1;
        g->matrix[ver2][ver1].adj=1;
    }
}
void printMatrix(graph *g)
{
    if(!g||!g->matrix||!g->verList) exit(-1);
    printf("Print the adjacency matrix:");
    for(int i=0;i<g->verNum;i++)
    {
        for(int j=0;j<g->verNum;j++)
        {
            printf("%d ",g->matrix[i][j].adj);
        }
        printf("\n");
    }
}
int main() {
    graph *g=createGraph(5);
    verNode **matrix =createMatrix(g);
    g->matrix=matrix;
    addEdge(g,7);

    return 0;
}

Ответы [ 2 ]

0 голосов
/ 24 апреля 2019

Вы объявили graph.matrix как vernode **.Вы выделили память для конкретного экземпляра g->matrix, по-видимому, успешно.*g->matrix обозначает vernode *, появляющийся в начале этого пространства (и учитывая, что вы намереваетесь использовать пространство в качестве массива, было бы более обычным обозначать этот элемент как g->matrix[0], что эквивалентно). Но вы никогда не присваивали значение этому объекту .Его значение не определено, и вы вызываете неопределенное поведение, пытаясь получить к нему доступ.

В целом, похоже, что вы объединили аспекты нескольких различных подходов.Это распределение ...

g->matrix=malloc(sizeof(int*)*g->verNum*g->verNum);

... во-первых, неправильно, потому что небезопасно предполагать, что sizeof(int *) совпадает с sizeof(vernode *), а последнее - то, что вам действительно нужноучитывая заявленный тип g->matrix.Кажется, что это неправильно и потому, что вы выделяете гораздо больше места, чем я ожидал бы для подхода, основанного на двойном указателе.Обычно выделяется один указатель для каждой строки, а не один на элемент, а затем отдельно выделяется память для элементов каждой строки.После этого будет поддерживаться двойное индексирование, как если бы у вас был истинный 2D массив: g->matrix[i][j].adj = 0;.

. Вы можете использовать только одно выделение для всех вершин,но тогда вам понадобится одиночный указатель (vernode *matrix;), и вам нужно будет использовать различные вычисления индекса: g->matrix[i * g->verNum + j].adj = 0;.

0 голосов
/ 24 апреля 2019

Здесь:

g->matrix = malloc(sizeof(int*) * g->verNum * g->verNum);

Вы выделяете плоский одномерный массив размером V × V .Вы получаете доступ к этому массиву, как если бы это был двухмерный массив: g->matrix[i][j].adj.

Представление матрицы смежности в виде двумерного массива является хорошей идеей, но тогда ваше распределение должно быть также двумерным: Allocateмассив V указателей на int, затем сделайте каждый из этих указателей дескриптором массива V int:

g->matrix = malloc(g->verNum * sizeof(*g->matrix));

for (int i = 0; i < g->verNum; i++) {
    g->matrix[i] = calloc(g->verNum, sizeof(*g->matrix[i]));    
}

Что следует отметить:

  • calloc(n, size) похож на malloc(n*size), но сначала обнуляет память, так что вы начинаете с несвязанного графа.
  • p = malloc(n * sizeof(*p)) - полезная идиома, которая выводиттип из p вместо того, чтобы указывать тип явно.
  • Существуют и другие способы получения двумерного массива.Например, вы можете выделить плоский массив измерения V × V , как вы это сделали, а затем сделать matrix массивом указателей на этот массив, так что matrix[i] представляетстрока в плоском массиве.Я думаю, что в целях обучения, вышеприведенный подход лучше, потому что он более прост.
  • Конечно, вы должны free выделенной памяти позже.Сделайте это в обратном порядке: сначала освободите matrix[i], а затем matrix.
...