算法导论-第22章-基本的图算法-22.1 图的表示

一、综述

图的表示方法通常有两种,即邻接表表示法和邻接矩阵表示法。这两种方法都可以表示有向图和无向图

1.邻接表表示法

(1)用邻接表表示无向图

(2)用邻接表表示有向图

(3)邻接表的优点及适用场合

使用邻接表表示稀疏图比较紧凑

2.邻接矩阵表示法

(1)用邻接矩阵表示无向图

(2)用邻接矩阵表示有向图

(3)邻接矩阵的优点与适用场合

用邻接矩阵表示稠密图可以很快地判别两个给定顶点是否存在邻接边

 

二、代码


1.邻接表表示法 "Link_Graph.h"


#include 
using namespace std;

#define N 100

struct Vertex;
struct Edge
{
	int start;//一条边的第一个编号,例如(1,2)的1
	int end;//一条边的第二个编号,(1,2)中的2
	int value;//边的权重,本程序默认为1
	Edge *next;//第start起点的链表的下一条边
	Edge(int s, int e, int v):start(s),end(e),value(v),next(NULL){}
};
struct Vertex
{
	Edge *head;
	Vertex():head(NULL){};
};
class Link_Graph
{
public:
	int n;
	Vertex *V;//邻接链表,相当于动态数组 Vertex V[n+1];V[1].head代表编号为1的点的链表,head为链表的第一个结点,每个结点代表一条边,有start和end
	Link_Graph(int num):n(num)
	{
		V = new Vertex[n+1];
	}
	~Link_Graph(){delete []V;}
	//把当前边(start,end)插入到编号为start的点的链表中,插入一条边意味着是有向图,单相插入
	void AddSingleEdge(int start, int end, int value = 1)
	{
		Edge *NewEdge = new Edge(start, end, value);
		//如果编号为start的点的链表为空或者他的第一个结点的end大于要插入的边的end,则把要插入的边放到第一个(保证每个点的链表的边的end按从小到大的顺序排列)
		if(V[start].head == NULL || V[start].head->end > end)
		{
			NewEdge->next = V[start].head;
			V[start].head = NewEdge;
		}
		else
		{
			Edge *e = V[start].head, *pre = e;
			//找到要插入的位置,pre的end小于要插入的边的end,e的end大于等于要插入的边的end
			while(e != NULL && e->end < end)
			{
				pre = e;
				e = e->next;
			}
			//遇到重复的边,则不插入
			if(e && e->end == end)
			{
				delete NewEdge;
				return;
			}
			//否则,插入到pre和e之间
			NewEdge->next = e;
			pre->next = NewEdge;
		}
	}
	//无向图的边的插入
	void AddDoubleEdge(int a, int b, int value = 1)
	{
		AddSingleEdge(a, b, value);
		AddSingleEdge(b, a, value);
	}
	//有向图的边删除
	void DeleteSingleEdge(int start, int end)
	{
		Edge *e = V[start].head, *pre = e;
		while(e && e->end < end)
		{
			pre = e;
			e = e->next;
		}
		//如果e为空,或者当前的e的end>end,则说明要删除的边不存在,直接返回
		if(e == NULL || e->end > end) return;
		//删除的是头结点时,需要先把后一个结点置为头结点
		if(e == V[start].head)
			V[start].head = e->next;
		else
			pre->next = e->next;//直接把前一个指向e的后一个结点
		delete e;
	}
	//无向图的边删除
	void DeleteDoubleEdge(int a, int b)
	{
		DeleteSingleEdge(a, b);
		DeleteSingleEdge(b, a);
	}
	//22.1-1,计算有向图的出度和入度
	void OutDegree();
	void InDegree();
	//22.1-2
	void Print();
	//22.1-3
	Link_Graph* Reverse();
	//22.1-5
	Link_Graph* Square();
};

void Link_Graph::OutDegree()
{
	int i, cnt = 0;
	Edge *e;
	for(i = 1; i <= n; i++)
	{
		cnt = 0;//保存编号为i的结点的链表中结点的个数,即出度
		e = V[i].head;
		while(e)
		{
			cnt++;
			e = e->next;
		}
		cout<<"顶点"<end]++;
			e = e->next;
		}
	}
	for(i = 1; i <= n; i++)
		cout<<"顶点"<"<end;
			e = e->next;
		}
		cout<AddSingleEdge(e->end, e->start);  
			e = e->next;  
		}  
	}  
	return ret; 
}

Link_Graph* Link_Graph::Square()
{
	int i;
	Link_Graph *ret = new Link_Graph(n);  
	//遍历图中每个顶点  
	for(i = 1; i <= n; i++)  
	{  
		//遍历以该顶点为起点的边  
		Edge *e = V[i].head, *e2;  
		while(e)  
		{  
			//把原来有的边加入到新图中  
			ret->AddSingleEdge(e->start, e->end);  
			//把以e的终点为起点的边加入当前点的链表中  
			e2 = V[e->end].head;  
			while(e2)  
			{  
				ret->AddSingleEdge(e->start, e2->end);  
				e2 = e2->next;  
			}  
			e = e->next;  
		}     
	}  
	return ret;
}



2.邻接矩阵表示法


#include 
using namespace std;

#define N 100

class Mat_Graph
{
public:
	int n;
	int Map[N+1][N+1];

	Mat_Graph(int num):n(num)
	{
		memset(Map, 0, sizeof(Map));
	}
	void AddDoubleEdge(int a, int b, int value = 1)
	{
		AddSingleEdge(a, b, value);
		AddSingleEdge(b, a, value);
	}
	void AddSingleEdge(int start, int end, int value = 1)
	{
		Map[start][end] = value;
	}
	void DeleteDoubleEdge(int a, int b)
	{
		DeleteSingleEdge(a, b);
		DeleteSingleEdge(b, a);
	}
	void DeleteSingleEdge(int start, int end)
	{
		Map[start][end] = 0;
	}
	//22.1-2
	void Print();
	//22.1-3
	Mat_Graph* Reverse();
	//22.1-5
	Mat_Graph* Square();
	//22.1-6
	bool Universal_Sink();
};

void Mat_Graph::Print()
{
	int i, j;
	for(i = 1; i <= n; i++)
	{
		for(j = 1; j <= n; j++)
			cout<AddSingleEdge(j, i);
	}
	return ret;
}

Mat_Graph* Mat_Graph::Square()
{
	int i, j, k;
	Mat_Graph *ret = new Mat_Graph(n);  
	//遍历图中每个顶点  
	for(i = 1; i <= n; i++)  
	{  
		for(j = 1; j <= n; j++)  
		{  
			if(Map[i][j])  
			{  
				//把原来有的边加入到新图中  
				ret->AddSingleEdge(i, j);
				//把以E的终点为起点的边加入新图中  
				for(k = 1; k <= n; k++)  
					if(Map[j][k])  
						ret->AddSingleEdge(i, k);  
			}  
		}  
	}  
	return ret;
}

bool Mat_Graph::Universal_Sink()
{
	//i指向有可能是汇的编号最小的点  
	int i = 1, j = 1;  
	while(j <= n)  
	{  
		//map[i][j] = 0,那么j没有i的入,一定不是汇,i可能是汇  
		if(Map[i][j] == 0)  
			j++;  
		//若map[i][j] = 1,则(1)i有出,i不是汇(2)map[i][i+1..j-1]=0,i+1..j-1都不是汇(3)j及j以后的点可能是汇  
		//若i=j,j也不是汇,j+1可能是汇      
		else if(i == j)  
		{  
			i++;  
			j++;  
		}  
		//若i!=j,j以前的点都不是汇,j可能是汇  
		else i = j;  
	}  
	//没有汇  
	if(i > n)  
		return false;  
	//找到有可能是汇的点,但是还是需要验证一下  
	else  
	{  
		//汇的纵向都是1,除了map[i][i]  
		for(j = 1; j <= i-1; j++)  
		{  
			if(Map[i][j] == 1)  
				return false;  
		}  
		//汇的横向都是0  
		for(j = 1; j <= n; j++)  
			if( i != j && Map[j][i] == 0)  
				return false;  
		return true;  
	}  
}

3.main.cpp 


#include 
using namespace std;

#include "Link_Graph.h"
#include "Mat_Graph.h"

void Test1()
{
	cout<<"Test1"<>n;
	Link_Graph *LG = new Link_Graph(n);
	while(cin>>a>>b && a && b)//输入00时结束
		LG->AddSingleEdge(a, b);//增加一条边
	LG->OutDegree();//计算出度(有向图)
	LG->InDegree();//计算入度
	delete LG;
}
void Test2()
{
	cout<<"Test2"<AddSingleEdge(edge[i][0], edge[i][1]);
		MG->AddSingleEdge(edge[i][0], edge[i][1]);
	}
	LG->Print();
	MG->Print();
	delete LG;
	delete MG;
}
void Test3()
{
	cout<<"Test3"<>n;
	Link_Graph *LG = new Link_Graph(n);
	Mat_Graph *MG = new Mat_Graph(n);
	while(cin>>a>>b && a && b)//输入00时结束
	{
		LG->AddSingleEdge(a, b);
		MG->AddSingleEdge(a, b);
	}
	Link_Graph *NewLG = LG->Reverse();
	NewLG->Print();
	Mat_Graph *NewMG = MG->Reverse();
	NewMG->Print();
	delete LG;
	delete MG;
	delete NewLG;
	delete NewMG;
}
void Test5()
{
	cout<<"Test5"<>n;
	Link_Graph *LG = new Link_Graph(n);
	Mat_Graph *MG = new Mat_Graph(n);
	while(cin>>a>>b && a && b)//输入00时结束
	{
		LG->AddSingleEdge(a, b);
		MG->AddSingleEdge(a, b);
	}
	Link_Graph *NewLG = LG->Square();
	NewLG->Print();
	Mat_Graph *NewMG = MG->Square();
	NewMG->Print();
	delete LG;
	delete MG;
	delete NewLG;
	delete NewMG;
}

void Test6()
{
	cout<<"Test6"<>n;
	Mat_Graph *MG = new Mat_Graph(n);
	while(cin>>a>>b && a && b)//输入00时结束
		MG->AddSingleEdge(a, b);
	if(MG->Universal_Sink())
		cout<<"包含通用的汇"<

转自: http://blog.csdn.net/mishifangxiangdefeng/article/details/7837650

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