数据结构与算法分析 收获总结 第11章 图

1.图(Graph)结构是一种非线性的数据结构,可以用G=(V,E)表示,每个图中都包含一个顶点集合V和一个边集合E,其中E中的每条边都是V中的某一对顶点之间的连接,顶点总数记为|V|,边的总数记为|E|,|E|的取值范围是从0到|V|平方-|V|。
关于图的一些概念:
稀疏图(sparse graph):边数较少的图。
密集图(dense graph):边数较多的图。
完全图(complete graph):包括所有可能边的图。
有向图(directed graph):一个图结构中,边是有方向性的,那么这种图就称为有向图。
无向图(undirected graph):如果一个图结构中,所有的边都没有方向性,那么这种图便称为无向图。
子图(subgraph):子图S是指从图G中选出其顶点集的一个子集Vs,以及与Vs中顶点相关联的一些边构成的子集Es所形成的图。
无环图(acyclic):不带回路的图。
有向无环图(directed acyclic graph DAG):一个无回路的有向图。如果有一个非有向无环图,且A点出发向B经C可回到A,形成一个环。将从C到A的边方向改为从A到C,则变成有向无环图。有向无环图的生成树个数等于入度非零的节点的入度积。在图论中,如果一个有向图无法从某个顶点出发经过若干条边回到该点,则这个图是一个有向无环图。
连通图(connected graph):如果图中任意两点都是连通的,那么图被称作连通图。如果 G 是有向图,那么连接i和j的路径中所有的边都必须同向。如果此图是有向图,则称为强连通图(注意:需要双向都有路径)。(在图论中,连通图基于连通的概念。在一个无向图 G 中,若从顶点i到顶点j有路径相连(当然从j到i也一定有路径),则称i和j是连通的。)无向图的最大连通子图称为连通分量(connected component)。
强连通图(Strongly Connected Graph)是指在有向图G中,如果对于每一对vi、vj,vi≠vj,从vi到vj和从vj到vi都存在路径,则称G是强连通图。有向图中的极大强连通子图称做有向图的强连通分量。
弱连通图:将有向图的所有的有向边替换为无向边,所得到的图称为原图的基图。如果一个有向图的基图是连通图,则有向图是弱连通图。
单向连通图:如果有向图中,对于任意节点v1和v2,至少存在从v1到v2和从v2到v1的路径中的一条,则原图为单向连通图。即设G=是有向图,如果u->v意味着图G至多包含一条从u到v的简单路径,则图G为单连通图。
强连通图、连通图、单向连通图三者之间的关系是,强连通图必然是单向连通的,单向连通图必然是弱连通图

无向完全图(undirected complete graph):如果在一个无向图中, 每两个顶点之间都存在条边,那么这种图结构称为无向完全图。
有向完全图(directed complete graph):如果在一个有向图中,每两个顶点之间都存在方向相反的两条边,那么这种图结构称为有向完全图。
自由树(free tree):不带简单回路的连通无向图。(图的顶点序列中,除了第一个顶点和最后一个顶点相同外,其余顶点不重复出现的回路叫简单回路。或者说,若通路或回路不重复地包含相同的边,则它是简单的。)
2.图有两种常见的表示方法:I.相邻矩阵(adjacency matrix)表示法 空间代价:θ(|V|平方) II.邻接表(adjacency list)表示法 空间代价:θ(|V|+|E|)
3.图的实现
4.图的遍历(graph traversal):
I.深度优先搜索(depth-first search,DFS):利用栈
II.广度优先搜索(breadth-first search,BFS):利用队列
5.最短路径问题:
(1)单元最短路径问题:给定一个带权有向图G=(V,E),其中每条边的权是一个实数。另外,还给定V中的一个顶点,称为源。现在要计算从源到其他所有各顶点的最短路径长度。这里的长度就是指路上各边权之和。这个问题通常称为单源最短路径问题。
两种解决算法:I.Dijkstra II.Bellman-Ford
6.最小支撑树问题:设G=(V,E)是一个无向连通网,生成树上各边的权值之和为该生成树的代价,在G的所有生成树中,代价最小的生成树就称为最小支撑树,或称最小生成树。 ||||||另一种定义:MST是一个包括图G中的所有顶点及其一部分边的图,这些边都是图G所有边集合的子集,这些边满足下列条件:I.这个子集中所有边的权之和为所有子集中最小的 II.子集中的边能保证图是连通的
两种解决算法:I.Kruskal II.Prim

从以往考题来讲,图还是以从图构造的存储空间,理解相邻矩阵和邻接表(链表)两种实现图的方式。学会Dijk算法,Prim算法,Kruskal算法
Dijkstra:

class DijkElem{
	friend bool operator<(const DijkElem& r1,const DijkElem& r2) {
		return r1.distance < r2.distance;
	}
	public:   // To convinent the application, make the distance and vertex public
		int vertex, distance;
		DijkElem()  { vertex = -1; distance = -1;  }  // Default constructor
		DijkElem(int v, int d){
			vertex = v;
			distance = d;
		}	
};
		// A operation is lacking : make the precise load 
		// Dijkstra's shortest paths algorithm with priority queue
void Dijkstra(int* D, int s){   // D is used to store the current shortest load
			int i, v, w;  // v is current vertex
			DijkElem temp;
			DijkElem E[e()];   // Heap array with lots of space
			temp.distance = 0;
			temp.vertex = s;
			E[0] = temp;   // Initialize heap array
			heap<DijkElem>  H(E, 1, e());   // Create heap
			for(i = 0; i < n(); i++){   // Now, get distances
				do{
					if(H.size() == 0)  return;   // Nothing to remove
					temp = H.removefirst();
					v = temp.vertex;
				}while (getMark(v) == 1);
				setMark(v,1);
				if (D[v] == 100)   return;       // Unreachable vertices
				for(w = first(v); w <= n(); w = next(v,w)){
					if(D[w] > (D[v] + weight(v,w))){   // Update D
						D[w] = D[v] + weight(v,w);
						pre[w] = v;
						temp.distance = D[w];
						temp.vertex = w;
						H.insert(temp);    // Insert new distance in heap
					}
				}
			}
		}

Prim:

class sortelem{
	friend bool operator < (const sortelem& r1,const sortelem& r2) {
		if(r1.weight != r2.weight) return r1.weight < r2.weight;
		else{
			int temp1,temp2;
			temp1 = r1.v1 < r1.v2 ? r1.v1 : r1.v2;
			temp2 = r2.v1 < r2.v2 ? r2.v1 : r2.v2;
			return temp1 < temp2;
		}
	}
	public:
		int v1,v2,weight;    // weight is the weight between v1 and v2
};

void Prim(sortelem MST[],int* D, int s){   // D is used to store the current shortest load
			int i, v, w;  // v is current vertex
			int V[n() + 1];   // V[I] stores I's closest neighbor
			for(int i = 0;i <= n();i++)  V[i] = i;
			DijkElem temp;
			sortelem temp1;
			DijkElem E[e()];   // Heap array with lots of space
			temp.distance = 0;
			temp.vertex = s;
			E[0] = temp;   // Initialize heap array
			heap<DijkElem>  H(E, 1, e());   // Create heap
			heap<sortelem> H2(MST,0,e());
			for(i = 0; i < n(); i++){   // Now, build MST
				do{
					if(H.size() == 0)  {   // Nothing to remove
						while(H2.size() != 0){
							temp1 = H2.removefirst();
							if(temp1.v1 < temp1.v2) cout<<temp1.v1<<" "<<temp1.v2<<" ";
							else cout<<temp1.v2<<" "<<temp1.v1<<" ";
							cout<<temp1.weight<<endl;
						}	
						return;
					}
					temp = H.removefirst();
					v = temp.vertex;
				}while (getMark(v) == 1);
				setMark(v,1);
				if( v != s)  {     
					temp1.v1 = V[v];
					temp1.v2 = v;
					temp1.weight = weight(V[v],v);
					H2.insert(temp1);
				}
				if (D[v] == 100)   return;       // Unreachable vertices
				for(w = first(v); w <= n(); w = next(v,w)){
					if(D[w] > weight(v,w)){   // Update D
						D[w] =  weight(v,w);
						V[w] = v;   // Update who it came from
						temp.distance = D[w];
						temp.vertex = w;
						H.insert(temp);    // Insert new distance in heap
					}
				}
			}
		}

DFS,BFS:

void DFS(int v,int count){   // Depth first search
	count++;
	if(count != 6)  cout<<v<<" ";
	else cout<<v;
	setMark(v,1);   // Have visted a vertex
	for(int w = first(v); w <= n(); w = next(v,w)){
		if(getMark(w) == 0)  DFS(w,count);
	} 
}

void BFS(int start,AQueue<int> &Q,int count){  // Breadth first search
	int v, w;
	Q.enqueue(start);   // Initialize Q
	setMark(start,1);    // Mark the visted vertex
	while(Q.length() != 0){   // Process all vertices on Q
		v = Q.dequeue();
		count++;
		if(count != 6) cout<<v<<" ";
		else  cout<<v;
		for(w = first(v); w <= n(); w = next(v,w)){
			if(getMark(w) == 0){
				setMark(w,1);
				Q.enqueue(w);
			}
		}
	}
	cout<<endl;
}

以上算法都是在图中实现,有用到图的一些基本操作函数

你可能感兴趣的:(数据结构)