数据结构:邻接表

摘要:邻接表是图的一种链式存储结构。在邻接表中,对图中每个顶点Vi建立一个单链表,把与Vi相邻接的顶点放在这个链表中。邻接表中每个单链表的第一个节点都存放着有关顶点的信息,把这一节点看成链表的表头,其余节点存放有关边的信息,邻接表包括表头结点表和边表。

一、代码

1)抄代码

我们今天写的邻接表是有二维数组图结构转化而来的。所以可以将之前的代码现抄过来。

#define MAXSIZE 10

int* visited;  

typedef struct graph
{
	int** connections;
	int numNodes;
}*graphPtr;

typedef struct graphQueue
{
	int *node;
	int front;
	int rear;
}*graphQueuePtr;

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;
}

2)邻接表的结构体定义

typedef struct AdjacencyNode
{
	int column;
	struct AdjacencyNode* next;
}*AdjacencyNodePtr;

typedef struct AdjacencyList
{
	int numNodes;
	struct AdjacencyNode* headers;
}*AdjacencyListPtr;

3)将图转化为邻接表

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;
}

4)打印邻接表

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");
	}
}

5)广度遍历

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;
		}
	}
		
}

6)测试函数

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);
}

二、完整代码及运行结果

1)完整代码

#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;
}

2)运行结果

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

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值