1. 程式人生 > >深度廣度優先遍歷最小生成樹

深度廣度優先遍歷最小生成樹

怎麼用圖的深度和廣度優先遍歷來遍歷樹呢?我是這樣想的,把樹構造成圖就行了。

// 圖的遍歷.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "LinkQueue.h"
#include <stdio.h>
#include <stdlib.h>
#define VRType int//在這裡是權值型別
#define MAX_VERTEX_NUM 10//最大頂點個數
#define VertexType char //頂點型別
#define INFINITY 32767 //無窮大,不連通
//邊的結構
typedef struct ArcCell{
	VRType adj;//權值
}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
//圖的結構
typedef struct {
	VertexType vexs[MAX_VERTEX_NUM];//頂點向量
	AdjMatrix arcs;//鄰接矩陣
	int vexnum,arcnum;//頂點數,邊數
}MGraph;
//輔助陣列,記錄從U到V-U的最小代價的邊
typedef struct {
	VertexType adjvex;
	VRType lowcost;
}Closedge;
//////////
typedef struct edge{
	int begin;//起始頂點位置
	int end;//終點位置
	VRType weight;//權重
}Edge[100];

//函式宣告
void CreateMGraph(MGraph &G);//建立圖
void PrintGraph(MGraph G);//列印圖
void Prim(MGraph G,VertexType v,MGraph &TG);//
void Kruskal(MGraph G,MGraph &TG);
//找到結點v在圖G中的序號,返回,沒找到返回-1
int LocateVex(MGraph G,VertexType v);
void InitGraph(MGraph &G,int arcnum,int vertexnum);//初始化圖
//把G圖中的一條邊新增到TG中去
void AddArc(MGraph &TG,MGraph G,VertexType v1,VertexType v2,VRType weight);
//返回v結點的第一個鄰接頂點的序號,沒找到返回-1
int FirstAdjVex(MGraph G,VertexType v);
//返回v相對於w的下一個鄰接點,若w是v的最後一個鄰接頂點,返回-1
int NextAdjVex(MGraph G,VertexType v,VertexType w);
//遞迴深度優先遍歷圖
int visited[MAX_VERTEX_NUM] = {0};//訪問標記陣列
void DFSG(MGraph G,void (*Visit)(VertexType));
void DFS(MGraph G,int i);
//非遞迴廣度優先遍歷圖
void BFSG(MGraph G,void(*Visit)(VertexType));
//對結點的操作函式
void (*VisitFunc)(VertexType v);//全域性變數,方便訪問VisitNode
void VisitNode(VertexType v);

int main(){
	int i=1;
	MGraph G,TG;
	VertexType v;
	while(i){
		InitGraph(TG,0,1);
		printf("第%d個圖:\n",i++);
		CreateMGraph(G);
		PrintGraph(G);
		//Prim演算法
		printf("========Prim演算法========:\n輸入從哪個頂點開始構造:");
		fflush(stdin);
		scanf("%c",&v);
		Prim(G,v,TG);
		PrintGraph(TG);
		/*---------------
		for(int k=0;k<TG.vexnum;k++){
			printf("%c-%d----",TG.vexs[k],LocateVex(TG,TG.vexs[k]));
		}
		printf("\n");
		/*---------------*/
		printf("========DFS=======\n");
		DFSG(TG,VisitNode);
		printf("\n========BFS=======\n");
		BFSG(TG,VisitNode);
		//Kruskal演算法
		printf("\n========Kruskal演算法========:\n");
		InitGraph(TG,0,1);//重新初始化TG
		Kruskal(G,TG);
		PrintGraph(TG);
		printf("========DFS=======\n");
		DFSG(TG,VisitNode);
		printf("\n========BFS=======\n");
		BFSG(TG,VisitNode);
		system("pause");
	}
	return 0;
}
//函式實現
int minimum(Closedge *closedge,MGraph G){
	int i=0,j,k,min;
	while(!closedge[i].lowcost){//找到第一個權值不為零的
		i++;
	}
	min = closedge[i].lowcost;
	k = i;
	for(j=i+1;j<G.vexnum;j++){
		if(closedge[j].lowcost >0 && min >closedge[j].lowcost){
			min = closedge[j].lowcost;
			k = j;
		}
	}
	return k;
}
/*---------*/
void printCloseE(Closedge*close,int n){
	for(int i=0;i<n;i++){
		printf("closedge[%d].adjvex=%c || closedge[%d].lowcost=%d\n",i,close[i].adjvex,i,close[i].lowcost);
	}
}
/*---------*/
void Prim(MGraph G,VertexType v,MGraph &TG){
	int k = LocateVex(G,v),i=0,j=0;
	Closedge closedge[MAX_VERTEX_NUM];
	//輔助矩陣初始化
	for(i=0;i<G.vexnum;i++){
			closedge[i].adjvex = v;
			closedge[i].lowcost = G.arcs[k][i].adj;
	}
	closedge[k].lowcost = 0;//把結點v加入集合U中
	/*--------
	printCloseE(closedge,G.vexnum);
	/*--------*/
	for(i=1;i<G.vexnum;i++){
		k = minimum(closedge,G) ;//求出最小生成樹的下一個節點,第k頂點
		printf("%c--->%c\n",closedge[k].adjvex,G.vexs[k]);

		AddArc(TG,G,closedge[k].adjvex,G.vexs[k],closedge[k].lowcost);
		closedge[k].lowcost = 0;//第k結點加入U
		//重新選擇最小邊
		for(j=0;j<G.vexnum;j++){
			if( G.arcs[k][j].adj < closedge[j].lowcost){
				closedge[j].adjvex = G.vexs[k];
				closedge[j].lowcost = G.arcs[k][j].adj;
			}
		}
		/*--------
		printf("===============\n");
		printCloseE(closedge,G.vexnum);
		/*--------*/
	}
}
//列印邊陣列
void print(Edge *E,int n,MGraph G){
	for(int i=0;i<n;i++){
		printf("%c---%c---%d\n",G.vexs[E[i]->begin],G.vexs[E[i]->end],G.arcs[E[i]->begin][E[i]->end].adj);
	}
}
//按權值從小到大排序
int cmp(const void *a,const void *b){
	return ((struct edge*)a)->weight - ((struct edge*)b)->weight;
}
void Kruskal(MGraph G,MGraph &TG){
	Edge *E = (Edge*)malloc(sizeof(Edge)*G.arcnum*2) ;
	int i=0,j=0,k=0;
	for(i=0;i<G.vexnum;i++){
		for(j=0;j<G.vexnum;j++){
			if(G.arcs[i][j].adj != INFINITY){
				E[k]->begin = i;
				E[k]->end = j;
				E[k]->weight = G.arcs[i][j].adj;
				k++;
			}
		}
	}
	qsort(E,k,sizeof(E[0]),cmp);
	print(E,k,G);
	int *vset = (int *)malloc(sizeof(int)*G.vexnum);
	for (i=0;i<G.vexnum;i++){                                  //初始化輔助陣列    
        vset[i]=i;  
    }  
    k=1;                                                   //生成的邊數,最後要剛好為總邊數   
    j=0;                                                   //E中的下標   
    while (k<G.vexnum){   
        int set1 = vset[E[j]->begin];  
        int set2 = vset[E[j]->end];                                  //得到兩頂點屬於的集合   
		/*----------
		printf("set1 = %d||set2 = %d\n",set1,set2);
		/*----------*/
        if (set1!=set2){                                    //不在同一集合內的話,把邊加入最小生成樹   
			printf("%c--->%c weight = %d\n",G.vexs[E[j]->begin],G.vexs[E[j]->end],E[j]->weight);

			//加進邊
			AddArc(TG,G,G.vexs[E[j]->begin],G.vexs[E[j]->end],E[j]->weight);
            k++;  
            for (i=0;i<G.vexnum;i++)  
            {  
                if (vset[i]==set2)  
                {  
                    vset[i]=set1; 
                }  
            }
			/*----------
			for(int c=0;c<G.vexnum;c++){
				printf("vset[%d]=%d ",c,vset[c]);
			}
			printf("\n");
			/*----------*/
        }  
        j++;  
    }  
	free(vset);
	free(E);
}
void CreateMGraph(MGraph &G){
	printf("輸入頂點數,邊數:");
	int vexnum=0,arcnum=0;
	scanf("%d %d",&vexnum,&arcnum);
	//初始化矩陣
	InitGraph(G,arcnum,vexnum);

	int i=0,j=0;
	for(i=0;i<G.vexnum;i++){
		printf("輸入第%d個頂點編號:",i+1);
		fflush(stdin);
		scanf("%c",&G.vexs[i]);
	}
	char v1,v2;
	int w;
	for(int k=0;k<G.arcnum;k++){
		printf("輸入頂點1,頂點2及其權值:");
		fflush(stdin);
		scanf("%c %c %d",&v1,&v2,&w);
		i = LocateVex(G,v1);
		j = LocateVex(G,v2);
		G.arcs[i][j].adj = w;
		G.arcs[j][i] = G.arcs[i][j];//對稱邊
	}
}
int LocateVex(MGraph G,VertexType v){
	for(int i=0;i<G.vexnum;i++){
		if(v == G.vexs[i]){
			return i;
		}
	}
	return -1;
}
//初始化一個圖
void InitGraph(MGraph &G,int arcnum,int vertexnum){
	G.arcnum = arcnum;
	G.vexnum = vertexnum;
	for(int i=0;i<MAX_VERTEX_NUM;i++){
		for(int j=0;j<MAX_VERTEX_NUM;j++){
			G.arcs[i][j].adj = INFINITY;
		}
	}
}
//列印一個圖,二維
void PrintGraph(MGraph G){
	printf("\n");
	for(int i=0;i<G.vexnum;i++){
		for(int j=0;j<G.vexnum;j++){
			printf("%10d",G.arcs[i][j].adj);
			/*-----------
			printf("%d",G.arcs[i][j].adj);
			if(G.arcs[i][j].adj!=INFINITY){
				printf("(%c-%d)",G.vexs[i],i);
			}
			printf("\t");
			/*-------------*/
		}
		printf("\n");
	}
}
//向TG圖中加一條邊
void AddArc(MGraph &TG,MGraph G,VertexType v1,VertexType v2,VRType weight){
	int i = LocateVex(G,v1);
	int j = LocateVex(G,v2);
	TG.vexs[i] = v1;
	TG.vexs[j] = v2;
	/*------------
	printf("%c-%d\n%c-%d",G.vexs[i],i,G.vexs[j],j);
	/*------------*/
	if(i>=0 && j>=0){
		TG.arcs[i][j].adj = weight;
		TG.arcs[j][i].adj = weight;
		TG.arcnum++;
		TG.vexnum++;
	}
}
////////////////
int FirstAdjVex(MGraph G,VertexType v){
	int k = LocateVex(G,v);
	for(int i=0;i<G.vexnum;i++){
		if(G.arcs[k][i].adj != INFINITY){//第一個權值不為無窮大的點就是
			return i;
		}
	}
	return -1;
}
///////////////////
int NextAdjVex(MGraph G,VertexType v,VertexType w){
	int a = LocateVex(G,v);
	int b = LocateVex(G,w);
	for(int i=b+1;i<G.vexnum;i++){
		if(G.arcs[a][i].adj != INFINITY){
			return i;
		}
	}
	return -1;
}
/////////////////////
void DFSG(MGraph G,void (*Visit)(VertexType)){
	int i=0;
	VisitFunc = Visit;
	for(i=0;i<G.vexnum;i++){
		visited[i] = 0;//初始化,0代表沒訪問
	}
	for(i=0;i<G.vexnum;i++){
		if(!visited[i]){//第i個結點沒被訪問,就遞迴搜尋
			DFS(G,i);
		}
	}
}
void DFS(MGraph G,int i){
	//從第i個結點出發深度優先遍歷圖
	visited[i] = 1;
	VisitFunc(G.vexs[i]);
	for(int j = FirstAdjVex(G,G.vexs[i]);j>=0;j = NextAdjVex(G,G.vexs[i],G.vexs[j])){
		if(!visited[j]){
			DFS(G,j);
		}
	}
}
/////////////////
void BFSG(MGraph G,void(*Visit)(VertexType)){
	int i=0,k=0;
	for(i=0;i<G.vexnum;i++){
		visited[i] = 0;
	}
	VertexType u;
	LinkQueue Q;
	InitQueue(Q);
	for(i=0;i<G.vexnum;i++){
		if(!visited[i]){
			visited[i] = 1;
			Visit(G.vexs[i]);
			EnQueue(Q,G.vexs[i]);
			while(!QueueEmpty(Q)){
				DeQueue(Q,u);
				for(k=FirstAdjVex(G,u);k>=0;k=NextAdjVex(G,u,G.vexs[k])){
					if(!visited[k]){
						visited[k] = 1;
						Visit(G.vexs[k]);
						EnQueue(Q,G.vexs[k]);
					}
				}
			}
		}
	}
}
//////////////////
void VisitNode(VertexType v){
	printf("結點%c----->",v);
}
廣度優先用到的佇列:
#include <stdio.h>
#include <stdlib.h>
#define QElemType char

typedef struct QNode{
	QElemType data;
	QNode *next;
}*QueuePtr;
struct LinkQueue{
	QueuePtr front,rear;
};

void InitQueue(LinkQueue &Q){
	if(!(Q.front=Q.rear = (QueuePtr)malloc(sizeof(QNode)))){
		exit(-1);//溢位
	}
	Q.front->next = NULL;
}
void EnQueue(LinkQueue &Q,QElemType e){
	QueuePtr p;
	if(!(p = (QueuePtr)malloc(sizeof(QNode)))){
		exit(-1);
	}
	p->data = e;
	p->next = NULL;
	Q.rear->next = p;
	Q.rear = p;
}
int DeQueue(LinkQueue &Q,QElemType &e){
	QueuePtr p;
	if(Q.front==Q.rear){
		return -1;
	}
	p = Q.front->next;
	e = p->data;
	Q.front->next = p->next;
	if(Q.rear==p){
		Q.rear = Q.front;
	}
	free(p);
	return 1;
}
int QueueEmpty(LinkQueue Q){
	if(Q.front==Q.rear){
		return 1;
	}else{
		return 0;
	}
}

執行結果:


輸出的排版變了一下,別忘了。。。