图的表示--邻接表

图的表示:

       主要有两种,邻接矩阵和邻接表,前者空间复杂度,O(V2),后者为O(V+E)。因此,除非非常稠密的图(边非常多),一般后者优越于前者。

上篇讨论了邻接矩阵的实现,本篇讨论邻接表的实现

GraphLink.h

#include "Graph.h"
#include <iostream>
#include <queue>
using std::cout;
using std::cin;
using std::endl;
using std::queue;

#define N 5 // 定义图的顶点数

template <typename T> class LList;
template <typename T> class GraphLink;
struct ListUnit//邻接表表目中数据部分的结构定义
{
	int weight; //边的权
	int vertex;//边的终点
};

template <typename T>
class Link //链表元素
{

	friend class GraphLink<T>;
	friend class LList<T>;
	T element;//表目的数据
	Link<T> *next; //表目指针,指向下一个表目

	Link(const T &e,Link<T> *n = nullptr)//构造函数
	{
		element = e;
		next = n;
	}

	Link(Link<T> *n = nullptr)//构造函数
	{
		next = n;
	}

};

template <typename T>
class LList
{
private:
	void removeAll() //释放边表所有表目占据的空间
	{
		Link<T> *p = head->next;
		Link<T> *temp = nullptr;
		while(p != nullptr)
		{
			temp = p;
			p = p->next;
			delete temp;
		}
	}

public:
	Link<T> *head;//head指针并不储存任何实际元素,其存在只是为了操作方便
	LList()//构造函数
	{
		head = new Link<T>();
	}

	~LList()
	{
		removeAll();
	}
};

template <typename T>
class GraphLink : public Graph
{
private:
	LList<ListUnit> *grapList; //graList是保存所有边表的数组	

public:
	GraphLink(int numVert) : Graph(numVert)
	{
		 /*为graList数组申请空间,图有numVertex个顶点,则有numVertex个边表*/
		grapList = new LList<ListUnit>[numVert];

	}

	~GraphLink()
	{
		
		delete []grapList;
	}

	virtual Edge firstEdge(int oneVertex)// 返回与顶点oneVertex相关联的第一条边
	{
		Edge edge;
		edge.from = oneVertex;//将顶点oneVertex作为边edge的始点
		edge.to = -1;

		 /*graList[oneVertex].head保存的是顶点oneVertex的边表,
	      head->next指向顶点oneVertex的第一条边(如果head->next
									  不为null)*/

		Link<ListUnit> *p = grapList[oneVertex].head->next;
		if(p != nullptr)
		{
			edge.to = p->element.vertex;
			edge.weight = p->element.weight;
		}
		return edge;
	}

	virtual Edge nextEdge(Edge preEdge)// 返回与边PreEdge有相同关联顶点的下一条边
	{
		Edge edge;
		edge.from = preEdge.from;
		edge.to = -1;

		Link<ListUnit> *p = grapList[preEdge.from].head->next;
		while(p != nullptr && p->element.vertex <= preEdge.to)// 确定边preEdge的位置
		{
			p = p->next;
		
		}
		
		if(p)// 边preEdge的下一条边存在
		{
			edge.to = p->element.vertex;
			edge.weight = p->element.weight;
		}
		return edge;
	}

	void setEdge(int from, int to, int weight)
	{
		Link<ListUnit> *p = grapList[from].head->next;
		Link<ListUnit> *pre = grapList[from].head;
		/*确定边(from,to)或<from,to>在边表中的位置,如果不存在,
									则边(from,to)或<from,to>为新加的一条边*/
		while(p != nullptr && p->element.vertex < to)
		{
			pre = p;//记录下前一节点
			p = p->next;
		}

		if(p == nullptr)
		{
			Link<ListUnit> *temp = new Link<ListUnit>();
			temp->element.vertex = to;
			temp->element.weight = weight;
			pre->next = temp;
			numEdge++;
			indegree[to]++;
			return;
		}

		 /*边(from,to)或<from,to>在边表中已存在,故只需要改变边的权值*/
		if(p->element.vertex == to)
		{
			p->element.weight = weight;
			return;
		}

		/*边(from,to)或<from,to>在边表中不存在,但在边表中其后存在其它边,则在边表中插入这条边*/
		if(p->element.vertex > to)
		{
			Link<ListUnit> *temp = new Link<ListUnit>();
			temp->element.vertex = to;
			temp->element.weight = weight;
			pre->next = temp;
			temp->next = p;
			numEdge++;
			indegree[to]++;
			return;
		}

	}

	void delEdge(int from, int to)
	{
		Link<ListUnit> *p = grapList[from].head->next;
		Link<ListUnit> *pre = grapList[from].head;
		/*确定边(from,to)或<from,to>在边表中的位置*/
		while(p != nullptr && p->element.vertex < to)
		{
			pre = p;//记录下前一节点
			p = p->next;
		}

		if(p == nullptr)//边(from,to)或<from,to>在边表中不存在,则不需要做任何操作
		{
			return;
		}

		if(p->element.vertex > to)//边(from,to)或<from,to>在边表中不存在,则不需要做任何操作
		{
			return;
		}
		
		if(p->element.vertex == to)
		{
			pre->next = p->next;
			delete p;
			numEdge--;
			indegree[to]--;
			return;
		}

	}

	// 函数功能:初始化图
	void initGraph(GraphLink &graphM,int (*A)[N],int n)
	{
		for (int i = 0; i < n; i ++)  	
		{
			for (int j = 0; j < N; j ++)  
			{
				if (A[i][j] > 0)
					graphM.setEdge(i, j, A[i][j]);
			}
		}

	}

	void DFS( GraphLink &graph,int vertex)
	{
		graph.mark[vertex] = VISITED;
		visit(graph,vertex);
		for(Edge edge = graph.firstEdge(vertex); graph.isEdge(edge); edge = graph.nextEdge(edge))
		{
			if(graph.mark[graph.toVertex(edge)] == UNVISITED)
			{
				DFS(graph,graph.toVertex(edge));
			}
		}
	}

	void BFS( GraphLink &graph,int vertex)
	{
		queue<int> q;                    // 初始化广度优先周游要用到的队列
		q.push(vertex);
		while(!q.empty())
		{
			int v = q.front();
			q.pop();
			if(graph.mark[v] == UNVISITED )
			{
				visit(graph,v);
				graph.mark[v] = VISITED;//标记该顶点已访问

				// 该顶点邻接到的每一个未访问顶点都入队
				for(Edge edge = graph.firstEdge(v); graph.isEdge(edge); edge = graph.nextEdge(edge))
				{
					if(graph.mark[graph.toVertex(edge)] == UNVISITED)
					{
						q.push(graph.toVertex(edge));
					}
				}
			}
		}
	}

	void visit(const GraphLink &graph,int vertex)        
	{
		cout << "V:" << vertex << "\t";
	}
};

测试代码

#include "GraphLink.h"
#include <iostream>



int A[N][N] = {
	//        V0 V1 V2 V3 V4 
	/*V0*/    0, 0, 1, 1, 0,
	/*V1*/    0, 0, 0, 1, 1,
	/*V2*/    1, 0, 0, 1, 1,
	/*V3*/    1, 1, 1, 0, 0,
	/*V4*/    0, 1, 1, 0, 0,};      //图7.2中G1表示的无向图

int main()
{
	GraphLink<ListUnit> graphLink(N);              // 建立图 
	graphLink.initGraph(graphLink, A,N); // 初始化图
	cout << "DFS: ";
	graphLink.DFS(graphLink, 0);
	cout << endl;

	for (int i = 0; i < graphLink.verticesNum(); i++) //把Mark改回UNVISITED
		graphLink.mark[i] = UNVISITED; 

	cout << "BFS: ";
	graphLink.BFS(graphLink, 0);
	cout << endl;

	system("pause");
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值