邻接表及广度优先遍历

邻接表示由多条链表组成的数组。数组决标代表每个结点,每条链表中的数据代表与该节点相连接的结点。

图示:

邻接表及广度优先遍历_第1张图片

邻接表的广度优先遍历和图的广度优先遍历一样,但邻接表对各节点相连接的结点进行了压缩存储,访问相连接的结点时更快捷。 从一个结点顺着链表找到所有相连接的结点并保存,接着从和它相连接的结点中编号从小到大开始跟着链表遍历。同样要借助数组标记是否被访问,重复访问则不在保存。这里要采用循环队列的帮助。为重复访问且被访问的结点存入队中,然后依次出队顺着该结点的链表遍历,和树的广度遍历相似。

直接上代码,若不理解,请跟着代码走:

#include 
#include 

#define QUEUE_SIZE 10

int* visitedPtr;

//图的矩阵结构
typedef struct Graph{
	int** connections;
	int numNodes;
} *GraphPtr;

//队列结构
typedef struct Queue{
	int front;
	int rear;
	int *nodes;
}*QueuePtr,Queue;

//图的链表结点
typedef struct AdjacencyNode{
    struct AdjacencyNode *next;
	int data;
}*AdjacencyNodePtr,AdjacencyNode;

//链表的数组封装
typedef struct  AdjacencyList{
	int numNodes;
	AdjacencyNodePtr headers;
}*AdjacencyListPtr;

//队列初始化
QueuePtr initQueue(){
	QueuePtr resultPtr = (QueuePtr)malloc(sizeof(Queue));
	resultPtr->front = 0;
	resultPtr->rear = 1;
	resultPtr->nodes = (int*)malloc(sizeof(int)*QUEUE_SIZE);
	
	return resultPtr;
}

//入队
void enqueue(QueuePtr paraQueuePtr,int paraNode){
	if((paraQueuePtr->rear+1)%QUEUE_SIZE == paraQueuePtr->front){
		printf("错误,%d尝试入队,队已满\n",paraNode);
		return;
	}
	paraQueuePtr->nodes[paraQueuePtr->rear] = paraNode;
	paraQueuePtr->rear = (paraQueuePtr->rear + 1)%QUEUE_SIZE;
}

//判断队空
bool isQueueEmpty(QueuePtr paraQueuePtr){
	if((paraQueuePtr->front+1)%QUEUE_SIZE == paraQueuePtr->rear){
		return true;
	}
	return false;
}

//出队
int dequeue(QueuePtr paraQueuePtr){
	if(isQueueEmpty(paraQueuePtr)){
		printf("错误,队空无法出队\n");
		return NULL;
	}
	paraQueuePtr->front = (paraQueuePtr->front + 1)%QUEUE_SIZE;
	return paraQueuePtr->nodes[paraQueuePtr->front];
}

//图矩阵初始化
GraphPtr initGraph(int paraSize, int** paraData){
	GraphPtr resultPtr = (GraphPtr)malloc(sizeof(Graph));
    //分配二维数组
	resultPtr->connections = (int**)malloc(sizeof(int*)*paraSize);
	resultPtr->numNodes = paraSize;
	
    //矩阵赋值
	for(int i = 0;i < paraSize;i++){
		resultPtr->connections[i] = (int*)malloc(sizeof(int)*paraSize);
		for(int j = 0;j < paraSize;j++){
			resultPtr->connections[i][j] = paraData[i][j];
		}
	}
	return resultPtr;
}

//打印数组中各链表
void printAdjacentList(AdjacencyListPtr paraPtr){
	printf("This is the graph:\r\n"); 
	int i;
	AdjacencyNodePtr p;
	for(i = 0;i < paraPtr->numNodes;i++){
		p = paraPtr->headers[i].next;
		printf("%d ",i);
		while(p!=NULL){
			printf("%d ",p->data);
			p = p->next;
		}
		printf("\n");
	}
}

//将图矩阵转化为邻接表
AdjacencyListPtr graphToAdjacentList(GraphPtr paraPtr){
	int i,j;
	AdjacencyNodePtr p,q;

	AdjacencyListPtr resultListPtr = (AdjacencyListPtr)malloc(sizeof(struct  AdjacencyList));

    //创建多条链表
	resultListPtr->headers = (AdjacencyNodePtr)malloc(sizeof(AdjacencyNode)*paraPtr->numNodes);
	resultListPtr->numNodes = paraPtr->numNodes;
	
	for(i = 0;i < paraPtr->numNodes;i++){
        //每条链表的初始化
		p = &(resultListPtr->headers[i]);
		p->data = -1;
		p->next = NULL;
		
		for(j = 0;j < paraPtr->numNodes;j++){
			if(paraPtr->connections[i][j] > 0){
                //创建链表结点
				q = (AdjacencyNodePtr)malloc(sizeof(AdjacencyNode));
				q->data = j;
				q->next = NULL;
				
                //连接结点
				p->next = q;
				p = q;
			}
		}
	}
	return resultListPtr;
}

//邻接表的广度优先遍历
void widthFirstTranverse(AdjacencyListPtr paraListPtr,int paraStart){
	printf("width first \r\n");
	
	int i,tempNode;
	AdjacencyNodePtr p;
	
    //标记结点均未被访问
	visitedPtr = (int*)malloc(sizeof(int)*paraListPtr->numNodes);
	for(i = 0;i < paraListPtr->numNodes;i++){
		visitedPtr[i] = 0;
	}
	
	QueuePtr tempQueuePtr = initQueue();
	enqueue(tempQueuePtr,paraStart);
	visitedPtr[paraStart] = 1;
	
    //遍历
	while(!isQueueEmpty(tempQueuePtr)){
		tempNode = dequeue(tempQueuePtr);
		printf("%d ",tempNode);
		
		p = &(paraListPtr->headers[tempNode]);
		p = p->next;
		
		while(p!=NULL){
			if(visitedPtr[p->data]==0){
				enqueue(tempQueuePtr,p->data);
				visitedPtr[p->data] = 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 = initGraph(5, tempPtr);
	AdjacencyListPtr tempListPtr = graphToAdjacentList(tempGraphPtr);

	printAdjacentList(tempListPtr);

	widthFirstTranverse(tempListPtr, 4);
}

int main(){
	testGraphTranverse();
	return 1;
}

你可能感兴趣的:(宽度优先,链表,数据结构)