一.邻接表
我们把数组与链表相结合的存储方法称为邻接表(Adjacency List)。
邻接表的处理办法是这样的:
1.图中顶点用一个一维数组存储,当然顶点也可以用单链表来存储,不过数组可以较容易地读取顶点信息,更加方便。另外,对于顶点数组中,每个数据元素还需要存储指向第一个邻接点的指针,以便以查找该顶点的信息。
2.图中每个顶点Vi的所有邻接点构成一个线性表,由于邻接点的个数不定,所以用单链表存储,无向图称为顶点vi的边表,有向图则称为顶点vi作为弧尾的出边表。
二.代码实现
1.定义
typedef struct AdjacencyNode
{
int column;
struct AdjacencyNode* next;
}*AdjacencyNodePtr;
typedef struct AdjacencyList
{
int numNodes;
struct AdjacencyNode* headers;
}*AdjacencyListPtr;
2.图转化为邻接表
AdjacencyListPtr graphToAdjacency(graphPtr paraGraph)
{
int i,j;
int tempNodes = paraGraph->numNodes;
//分配空间
AdjacencyListPtr resultList = (AdjacencyListPtr)malloc(sizeof(struct AdjacencyList));
resultList->numNodes = tempNodes;
resultList->headers = (AdjacencyNodePtr)malloc(tempNodes * sizeof(struct AdjacencyNode));
AdjacencyNodePtr p,q;
for(i = 0;i < tempNodes;i ++)
{
//每一次都指向下一个元素,即下一个链表的头结点
p = &(resultList->headers[i]);
p->column = -1;
p->next = NULL;
for(j = 0;j < tempNodes;j ++)
{
//只有该位置为1,即连通的时候才开辟结点
if(paraGraph->connections[i][j] == 1)
{
q = (AdjacencyNodePtr)malloc(sizeof(struct AdjacencyNode));
q->column = j;
q->next = NULL;
//链接过去,并让p跟踪
p->next = q;
p = q;
}
}
}
return resultList;
}
3.打印
void printAdjacencyList(AdjacencyListPtr paraList)
{
printf("This is the adjacency list\n");
//用p来跟踪,一个一个打印
AdjacencyNodePtr p;
int i;
for(i = 0; i < paraList->numNodes;i ++)
{
//当p跟踪完当前链表后,记得要把p指向下一个链表头结点的next
p = paraList->headers[i].next;
while(p != NULL)
{
printf("%d, ",p->column);
p = p->next;
}
printf("\n");
}
}
4.(广度)遍历
void wideTranverse(AdjacencyListPtr paraList,int paraNum)
{
int temp;
//初始化visited
visitedInit(paraList);
//创建队列
graphQueuePtr tempQueue = queueInit();
enqueue(tempQueue,paraNum);
visited[paraNum] = 1;
printf("%d ",paraNum);
//还是用p跟踪
AdjacencyNodePtr p;
while(tempQueue->front != tempQueue->rear)
{
temp = dequeue(tempQueue);
//出队了就让p指向对应的这个链表的头部的next
p = paraList->headers[temp].next;
//p == NULL就代表这个链表循环完了
while(p != NULL)
{
//如果没被访问过,就直接入队
if(visited[p->column] == 0)
{
enqueue(tempQueue,p->column);
printf("%d ",p->column);
visited[p->column] = 1;
}
//注意这个要写在外面,无论是否被访问了都要往后走
p = p->next;
}
}
}
5.测试代码
void testGraphTranverse()
{
int i, j;
int myGraph[5][5] =
{
{0, 1, 0, 1, 0},
{1, 0, 1, 0, 1},
{0, 1, 0, 1, 1},
{1, 0, 1, 0, 0},
{0, 1, 1, 0, 0}
};
int** tempPtr;
printf("Preparing data\r\n");
tempPtr = (int**)malloc(5 * sizeof(int*));
for (i = 0; i < 5; i ++)
{
tempPtr[i] = (int*)malloc(5 * sizeof(int));
}
for (i = 0; i < 5; i ++)
{
for (j = 0; j < 5; j ++)
{
tempPtr[i][j] = myGraph[i][j];
}
}
printf("Data ready\r\n");
graphPtr tempGraphPtr = graphInit(tempPtr,5);
AdjacencyListPtr tempListPtr = graphToAdjacency(tempGraphPtr);
printAdjacencyList(tempListPtr);
wideTranverse(tempListPtr, 4);
}
6.测试结果
Preparing data
Data ready
This is the adjacency list
1, 3,
0, 2, 4,
1, 3, 4,
0, 2,
1, 2,
4 1 2 0 3
三.完整代码
#include <stdio.h>
#include <malloc.h>
#define MAXSIZE 10
int* visited;
typedef struct graph
{
int** connections;
int numNodes;
}*graphPtr;
typedef struct graphQueue
{
int *node;
int front;
int rear;
}*graphQueuePtr;
typedef struct AdjacencyNode
{
int column;
struct AdjacencyNode* next;
}*AdjacencyNodePtr;
typedef struct AdjacencyList
{
int numNodes;
struct AdjacencyNode* headers;
}*AdjacencyListPtr;
graphQueuePtr queueInit()
{
graphQueuePtr resultQueue = (graphQueuePtr)malloc(sizeof(struct graphQueue));
resultQueue->node = (int*)malloc(MAXSIZE * sizeof(int));
resultQueue->front = 0;
resultQueue->rear = 0;
return resultQueue;
}
void enqueue(graphQueuePtr paraQueue,int paraData)
{
if((paraQueue->rear + 1) % MAXSIZE == (paraQueue->front) % MAXSIZE)
{
printf("队列满了,无法入队!\n");
return ;
}
paraQueue->node[(paraQueue->rear) % MAXSIZE] = paraData;
paraQueue->rear = (paraQueue->rear + 1) % MAXSIZE;
}
int dequeue(graphQueuePtr paraQueue)
{
if(paraQueue->front == paraQueue->rear)
{
printf("队列为空,无法出队!\n");
return ;
}
int temp = paraQueue->node[(paraQueue->front) % MAXSIZE];
paraQueue->front = (paraQueue->front + 1) % MAXSIZE;
return temp;
}
void visitedInit(AdjacencyListPtr paraPtr)
{
int i;
visited = (int*)malloc(paraPtr->numNodes * sizeof(int));
for(i = 0;i < paraPtr->numNodes;i ++)
{
visited[i] = 0;
}
}
graphPtr graphInit(int **paraConnections,int paraNumNodes)
{
int i,j;
graphPtr resultGraph = (graphPtr)malloc(sizeof(struct graph));
resultGraph->numNodes = paraNumNodes;
resultGraph->connections = (int**)malloc(resultGraph->numNodes * sizeof(int*));
for(i = 0;i < resultGraph->numNodes;i ++)
{
resultGraph->connections[i] = (int*)malloc(resultGraph->numNodes * sizeof(int));
}
for(i = 0;i < resultGraph->numNodes;i ++)
for(j = 0;j < resultGraph->numNodes;j ++)
{
resultGraph->connections[i][j] = paraConnections[i][j];
}
return resultGraph;
}
AdjacencyListPtr graphToAdjacency(graphPtr paraGraph)
{
int i,j;
int tempNodes = paraGraph->numNodes;
//分配空间
AdjacencyListPtr resultList = (AdjacencyListPtr)malloc(sizeof(struct AdjacencyList));
resultList->numNodes = tempNodes;
resultList->headers = (AdjacencyNodePtr)malloc(tempNodes * sizeof(struct AdjacencyNode));
AdjacencyNodePtr p,q;
for(i = 0;i < tempNodes;i ++)
{
//每一次都指向下一个元素,即下一个链表的头结点
p = &(resultList->headers[i]);
p->column = -1;
p->next = NULL;
for(j = 0;j < tempNodes;j ++)
{
if(paraGraph->connections[i][j] == 1)
{
q = (AdjacencyNodePtr)malloc(sizeof(struct AdjacencyNode));
q->column = j;
q->next = NULL;
//链接过去,并让p跟踪
p->next = q;
p = q;
}
}
}
return resultList;
}
void printAdjacencyList(AdjacencyListPtr paraList)
{
printf("This is the adjacency list\n");
//用p来跟踪,一个一个打印
AdjacencyNodePtr p;
int i;
for(i = 0; i < paraList->numNodes;i ++)
{
//当p跟踪完当前链表后,记得要把p指向下一个链表头结点的next
p = paraList->headers[i].next;
while(p != NULL)
{
printf("%d, ",p->column);
p = p->next;
}
printf("\n");
}
}
void wideTranverse(AdjacencyListPtr paraList,int paraNum)
{
int temp;
//初始化visited
visitedInit(paraList);
//创建队列
graphQueuePtr tempQueue = queueInit();
enqueue(tempQueue,paraNum);
visited[paraNum] = 1;
printf("%d ",paraNum);
//还是用p跟踪
AdjacencyNodePtr p;
while(tempQueue->front != tempQueue->rear)
{
temp = dequeue(tempQueue);
//出队了就让p指向对应的这个链表的头部的next
p = paraList->headers[temp].next;
//p == NULL就代表这个链表循环完了
while(p != NULL)
{
//如果没被访问过,就直接入队
if(visited[p->column] == 0)
{
enqueue(tempQueue,p->column);
printf("%d ",p->column);
visited[p->column] = 1;
}
//注意这个要写在外面,无论是否被访问了都要往后走
p = p->next;
}
}
}
void testGraphTranverse()
{
int i, j;
int myGraph[5][5] =
{
{0, 1, 0, 1, 0},
{1, 0, 1, 0, 1},
{0, 1, 0, 1, 1},
{1, 0, 1, 0, 0},
{0, 1, 1, 0, 0}
};
int** tempPtr;
printf("Preparing data\r\n");
tempPtr = (int**)malloc(5 * sizeof(int*));
for (i = 0; i < 5; i ++)
{
tempPtr[i] = (int*)malloc(5 * sizeof(int));
}
for (i = 0; i < 5; i ++)
{
for (j = 0; j < 5; j ++)
{
tempPtr[i][j] = myGraph[i][j];
}
}
printf("Data ready\r\n");
graphPtr tempGraphPtr = graphInit(tempPtr,5);
AdjacencyListPtr tempListPtr = graphToAdjacency(tempGraphPtr);
printAdjacencyList(tempListPtr);
wideTranverse(tempListPtr, 4);
}
int main(){
testGraphTranverse();
return 1;
}