V1顶点后面链着的是与他相连的边的序号(第i个单链表后的结点表示依附于顶点Vi的边)
这是一个无向图,所以邻接表一共有12条边
定义结构体
每个单链表的第一个结点存放有关顶点的信息,把这个结点看做链表的表头,其余节点存放有关边的信息
#define Default_Vertex_Size 10
#define T char
typedef struct Edge//其余结点形成的边表
{
int dest;//与当前结点相邻的顶点的序号
struct Edge *link;//指向下一个边结点的指针
}Edge;
typedef struct Vertex//单链表的表头形成的顶点表
{
T data;//顶点信息
Edge *adj;//指向第一个边结点的指针
}Vertex;
typedef struct GraphLnk
{
int MaxVertices;
int NumVertices;
int NumEdges;
Vertex *NodeTable;
}GraphLnk;
初始化
void InitGraph(GraphLnk *g)
{
g->MaxVertices = Default_Vertex_Size;
g->NumEdges = g->NumVertices = 0;
g->NodeTable = (Vertex*)malloc(sizeof(Vertex) * g->MaxVertices);
assert(g->NodeTable != NULL);
for(int i=0; i<g->MaxVertices; ++i)
{
g->NodeTable[i].adj = NULL;
}
}
对于0xcccccccc和0xcdcdcdcd,
在 Debug 模式下,VC 会把未初始化的栈内存上的指针全部填成 0xcccccccc ,当字符串看就是 “烫烫烫烫……”;
会把未初始化的堆内存上的指针全部填成 0xcdcdcdcd,当字符串看就是 “屯屯屯屯……”。
那么调试器为什么要这么做呢?VC的DEBUG版会把未初始化的指针自动初始化为0xcccccccc或0xcdcdcdcd,而不是就让取随机值,那是为了方便我们调试程序,如果野指针的初值不确定,那么每次调试同一个程序就可能出现不一样的结果,比如这次程序崩掉,下次却能正常运行,这样显然对我们解bug是非常不利的,所以自动初始化的目的是为了让我们一眼就能确定我们使用了未初始化的野指针了。
插入顶点
void InsertVertex(GraphLnk *g, T v)
{
if(g->NumVertices >= g->MaxVertices)
return;
g->NodeTable[g->NumVertices++].data = v;
}
插入边
//获取顶点的位置
int GetVertexPos(GraphLnk *g, T v)
{
for(int i=0; i<g->NumVertices; ++i)
{
if(g->NodeTable[i].data == v)
return i;
}
return -1;
}
void InsertEdge(GraphLnk *g, T vertex1, T vertex2)
{
int v1 = GetVertexPos(g,vertex1)