一些定义:
一个图(Gragh)G = (V,E)由定点(Vertex)集V和边(Edge)集E组成。
图的每一条边都是由一个对点(v,w)组成的。如果点是有序的,那么图就叫做有向图。
反之则图为无向图。
如果在一个无向图种从每一个顶点到每个其他顶点都存在一条路径,则称该无向图是连通的。具有这样的性质的有向图是强连通的。如果一个有向图不是强连通,但是他的基础图(其弧上去掉方向所形成的图)是连通的,那么该有向图称为弱连通的。
完全图是其每一个顶点间都存在一条边的图。
一条弧两端的两个顶点存在邻接关系
我们可以根据点的邻接关系画出邻接矩阵
那么表示图的第一种方法就是用邻接矩阵来实现。
如图
我们用1来表示两点之前存在关系,用0表示没有关系。
但是如果是带权图,我们可以置他们之间的关系值为权值,而没有邻接关系的两点之间的初始化需要根据实际情况来定。
例如:图代表了飞机的航线,寻找两个城市之间的最短航线。既然是寻找最短,那么我们就应该将没有邻接关系的权设置为∞。那假设是寻找最长的那条航线,我们就应该将其设置为-∞。
这种算法最容易实现方式当然是用二维数组存储。但是假设是一个顶点很多,而边数很少的图,我们需要建立一个v*v大小的图,而大部分的空间都被浪费掉了,如果要进行查找等操作也是及其的不方便,这种图我们称其是稀疏的,显然要存储稀疏图还需要其他的算法。
但是如果是稠密图(边数很多),用这种方式是很方便的。
还是用点的邻接关系来表示图,想到了数组,那很容易就可以想到表了。
直接用链表来动态申请内存不就行了?
用链表来存储不仅可以存储边的权值,还可以方便的找出与其邻接的下一个点,如果用单向链表来表示的话,可想起内存的使用量基本上是双倍的,因为一个结点只能指向下一个结点而不能后退。虽然说指针是一个比较难掌握的东西,但是他确是一个很方便的东西,如果我们在这里使用双向链表或者甚至是循环链表,就可以让空间节省很多,但是这对于指针的掌控要求很高。
所以还需要继续努力啊。
创建一个固定的图的邻接表表示
代码
#include<stdio.h>
#include<stdlib.h>
typedef struct GraghNode
{
int Element;
struct GraghNode *next;
}Node;
typedef struct Gragh
{
int EdgeNum = 8;
Node *TheCells;
}Gragh;
Gragh CreatedGragh();
void FreeGragh(Gragh G);
void PrintfGragh(Gragh G);
int main()
{
Gragh G;
G = CreatedGragh();
PrintfGragh(G);
FreeGragh(G);
}
Gragh CreatedGragh()
{
Gragh G;
Node *Temp;
G.TheCells = (Node*)malloc(sizeof(Node)*G.EdgeNum);
if(G.TheCells == NULL)
{
printf("Out of space!!");
exit(1);
}
//不用第一个Node,将其置为NULL
for(int i = 0; i < G.EdgeNum; i++)
{
G.TheCells[i].Element = i;
G.TheCells[i].next = NULL;
}
//定义一个固定的图
G.TheCells[1].next = (Node*)malloc(sizeof(Node));
if(Temp == NULL)
{
printf("Error!");
exit(1);
}
Temp = G.TheCells[1].next;
Temp->Element = 2;
Temp->next = (Node*)malloc(sizeof(Node));
if(Temp == NULL)
{
printf("Error!");
exit(1);
}
Temp = Temp->next;
Temp->Element = 4;
Temp->next = (Node*)malloc(sizeof(Node));
if(Temp == NULL)
{
printf("Error!");
exit(1);
}
Temp = Temp->next;
Temp->Element = 3;
Temp->next = NULL;
G.TheCells[2].next = (Node*)malloc(sizeof(Node));
if(Temp == NULL)
{
printf("Error!");
exit(1);
}
Temp = G.TheCells[2].next;
Temp->Element = 4;
Temp->next = (Node*)malloc(sizeof(Node));
if(Temp == NULL)
{
printf("Error!");
exit(1);
}
Temp = Temp->next;
Temp->Element = 5;
Temp->next = NULL;
G.TheCells[3].next = (Node*)malloc(sizeof(Node));
if(Temp == NULL)
{
printf("Error!");
exit(1);
}
Temp = G.TheCells[3].next;
Temp->Element = 6;
Temp->next = NULL;
G.TheCells[4].next = (Node*)malloc(sizeof(Node));
if(Temp == NULL)
{
printf("Error!");
exit(1);
}
Temp = G.TheCells[4].next;
Temp->Element = 6;
Temp->next = (Node*)malloc(sizeof(Node));
if(Temp == NULL)
{
printf("Error!");
exit(1);
}
Temp = Temp->next;
Temp->Element = 7;
Temp->next = (Node*)malloc(sizeof(Node));
if(Temp == NULL)
{
printf("Error!");
exit(1);
}
Temp = Temp->next;
Temp->Element = 3;
Temp->next = NULL;
G.TheCells[5].next = (Node*)malloc(sizeof(Node));
if(Temp == NULL)
{
printf("Error!");
exit(1);
}
Temp = G.TheCells[5].next;
Temp->Element = 4;
Temp->next = (Node*)malloc(sizeof(Node));
if(Temp == NULL)
{
printf("Error!");
exit(1);
}
Temp = Temp->next;
Temp->Element = 7;
Temp->next = NULL;
G.TheCells[7].next = (Node*)malloc(sizeof(Node));
if(Temp == NULL)
{
printf("Error!");
exit(1);
}
Temp = G.TheCells[7].next;
Temp->Element = 6;
Temp->next = NULL;
return G;
}
void PrintfGragh(Gragh G)
{
int i;
Node *Temp = NULL;
for(i = 1; i < G.EdgeNum; i++)
{
printf("%-2d| ", G.TheCells[i].Element); //输出头单元
if(G.TheCells[i].next != NULL)
{
Temp = G.TheCells[i].next;
do
{
printf("%2d", Temp->Element);
Temp = Temp->next;
}while(Temp!=NULL);
}
printf("\n-----------------------------\n");
}
}
void FreeGragh(Gragh G)
{
int i;
Node *Temp = NULL, *Temp1 = NULL;
for(i = 0; i < G.EdgeNum; i++)
{
if(G.TheCells[i].next != NULL)
{
Temp = G.TheCells[i].next;
do
{ Temp1 = Temp;
Temp = Temp->next;
free(Temp1);
}while(Temp!=NULL);
}
}
free(G.TheCells);
}
结果