1. 程式人生 > >建立一個圖,並且遍歷---MOOC浙大資料結構

建立一個圖,並且遍歷---MOOC浙大資料結構

建圖

以鄰接表方式儲存的圖型別

typedef struct GNode *PtrToGNode;
struct GNode{//整個圖
	int Nv;//頂點數
	int Ne;//邊數、
	AdjList G;//鄰接表
};
typedef PtrToGNode LGraph;

typedef struct AdjVNode *PtrToAdjVNode;
typedef struct Vnode{//頂點
	PtrToAdjuVNode FirstEdge;
	DataType Data;/*存頂點的資料*/
}AdjList[MaxVertexNum];//鄰接表型別

typedef struct AdjVNode *PtrToAdjVNode;
struct AdjVNode{//鄰接點
	Vertex AdjV;//鄰接點下標
	WeightType Weight;//邊權重
	PtrToAdjVNode Next;
};
typedef struct ENode *PtrToENode;
struct ENode{
	Vertex V1, V2;		//有向邊《V1,V2》
	WeightType Weight;	//權重(如果需要)
};
typedef PtrToENode Edge;
Vertex V1, V2; //有向邊《V1,V2》 WeightType Weight; //權重(如果需要) }; typedef PtrToENode Edge;

LGraph初始化

typedef int Vertex;//用頂點下標表示頂點,為整型int
LGraph CreateGraph(int VertexNum)
{
	Vertex V, W;
	LGraph Graph;

	Graph = (LGraph)malloc(sizeof(struct GNode));
	Graph->Nv = VertexNum;
	Graph->Ne = 0;
	/*預設頂點編號從0開始,到Graph->Nv-1 */
	for (V = 0; V < Graph->Nv; V++)
		Graph->G[V].FirstEdge = NULL;
	return Graph;
}

向LGraph中插入邊

void InsertEdge(LGraph Graph, Edge E)
{
	PtrToAdjVNode NewNode;
	/*插入邊《V1,V2》*/
	NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));//V2建立鄰接點
	NewNode->AdjV = E->V2;
	NewNode->Weight = E->Weight;
	/*將V2插入V1的表頭*/
	NewNode->Next = Graph->G[E->V1].FirstEdge;
	Graph->G[E->V1].FirstEdge = NewNode;

	/*如果是無向圖,還要插入邊《V2,V1》*/
	/*插入邊《V2,V1》*/
	NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));//V1建立鄰接點
	NewNode->AdjV = E->V1;
	NewNode->Weight = E->Weight;
	/*將V1插入V2的表頭*/
	NewNode->Next = Graph->G[E->V2].FirstEdge;
	Graph->G[E->V2].FirstEdge = NewNode;
}

完整地建立一個圖

LGraph BuildGraph()
{
	LGraph Graph;
        Edge  E;
	Vertex V;
	int Nv, i;

	scanf("%d",&Nv);
	Graph = CreateGraph(Nv);
	scanf("%d",&(Graph->Ne));
	if (Graph->Ne != 0){
		E = (Edge)malloc(sizeof(struct ENode));
		for (i = 0; i < Graph->Ne; i++){
			scanf("%d %d %d",&E->V1, &E->V2, &E->Weight);
			InsertEdge(Graph, E);
		}
	}
	/*如果頂點有資料,甚至是結構體,那麼還要讀入資料*/
	for (V = 0; V < Graph->Nv; V++)
		scanf("%c", &(Graph->Data[V]));
	return Graph;
}

考試寫法:

struct graph{
  int     node;
  graph*  p_next;
  graph(int x):node(x),p_next(NULL){}
};
  graph* p=new graph(0);//圖的頭,連結串列頭
  graph* tmp=p;
While()//迴圈條件
{
     tmp->node=a;//節點的值
     tmp->p_next=new graph(b);//邊的值
     tmp=tmp->p_next;
}
#include <iostream>
#include <vector>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
struct graph{
	int     node;
	graph*  p_next;
	graph(int x) :node(x), p_next(NULL){}
};
int N;

void DFS(int vertex,vector<int>& vec,int value,graph** head,int * visit)
{
	value++;
	visit[vertex] = 1;
	int flag = false;
	graph* tmp = head[vertex];
	while (tmp->p_next != NULL)
	{
		tmp = tmp->p_next;
		if (!visit[tmp->node])
		{
			flag = true;
			DFS(tmp->node,vec,value,head,visit);
		}
	}
	if (!flag)
	{
		vec.push_back(value-1);
	}
}

int main()
{
	cin >> N;
	int *visit = new int[N + 1];
	for (int i = 0; i < N + 1; i++)
	{
		visit[i] = 0;
	}

	graph** head = new graph*[N];
	for (int i = 1; i <= N;i++)
	{
		head[i] = new graph(i);
	}
	int saveN = N - 1;
	while (saveN--)
	{
		int tmp1, tmp2;
		cin >> tmp1>>tmp2;
		graph* tmp = head[tmp1];
		while (tmp->p_next != NULL)
		{
			tmp = tmp->p_next;
		}
		tmp->p_next = new graph(tmp2);
	}
	vector<int> vec;
	DFS(1, vec, 0, head, visit);
	sort(vec.begin(),vec.end());
	int res = 0;
	for (int i = 0; i < vec.size()-1;i++)
	{
		res += 2 * vec[i];
	}
	res += vec[vec.size() - 1];
	cout << res<<endl;

	return 0;
}

矩陣方式:

定義圖:

typedef struct GNode *PtrToGNode;

struct GNode{
	int Nv;//頂點數
	int Ne;//邊數、
        /*有可能有權值int value*/
	WeightType G[MaxVertexNum][MaxVertexNum];
        DataType   Data[MaxVertexNum];//存頂點的資料型別
};
typedef PtrToGNode MGraph;//以鄰接矩陣儲存的圖型別

建立圖:

typedef int Vertex;//用頂點下標表示頂點,為整型int
MGraph CreateGraph(int VertexNum)
{
	Vertex V, W;
	MGraph Graph;

	Graph = (MGraph)malloc(sizeof(struct GNode));
	Graph->Nv = VertexNum;
	Graph->Ne = 0;

	for (V = 0; V < Graph->Nv; V++)
		for (W = 0; W < Graph->NV; W++)
			Graph->G[V][W] = 0;//有權圖用INFINITY無窮大表示沒有邊
	return Graph;
}

插入邊:

typedef struct ENode *PtrToENode;
struct ENode{
	Vertex V1, V2;		//有向邊《V1,V2》
	WeightType Weight;	//權重(如果需要)
};
typedef PtrToENode Edge;

void InsertEdge(MGraph Graph, Edge E)
{
	Graph->G[E->V1][E->V2] = E->Weight;//V1,V2邊
	Graph->G[E->V2][E->V1] = E->Weight;//無向圖V2,V1
}

完整建立一個MGraph

MGraph BuildGraph()
{
	MGraph Graph;
	Edge E;
	Vertex V;
	int Nv, i;

	scanf("%d",&Nv);
	Graph = CreateGraph(Nv);
	scanf("%d",&(Graph->Ne));
	if (Graph->Ne != 0){
		E = (Edge)malloc(sizeof(struct ENode));
		for (i = 0; i < Graph->Ne; i++){
			scanf("%d %d %d",&E->V1, &E->V2, &E->Weight);
			InsertEdge(Graph, E);
		}
	}
	/*如果頂點有資料,甚至是結構體,那麼還要讀入資料*/
	for (V = 0; V < Graph->Nv; V++)
		scanf("%c", % (Graph->Data[V]));
	return Graph;
}

考試寫法:

上述兩種標準寫法,封裝好了底層的介面,讓呼叫者無須關注底層的實現,到底是用矩陣?還是用連結串列?

遍歷

深度優先

void DFS ( Vertex V )
{ visited[ V ] = true;
	for ( V 的每個鄰接點W )
		if ( !visited[ W ] )
			DFS( W );
}

廣度優先

void BFS ( Vertex V )
{ 
	visited[V] = true;
	Enqueue(V, Q);
	while(!IsEmpty(Q)){
		V = Dequeue(Q);
		for ( V 的每個鄰接點W )
		if ( !visited[W] ) {
			visited[W] = true;
			Enqueue(W, Q);
			}
	}
}

DFS的例子:

BFS的例子: