[C++]有向图(邻接链表描述)

本文介绍了一种使用邻接链表实现有向图的方法,并提供了判断边是否存在、插入边、删除边等基本操作的代码实现。此外,还介绍了如何进行广度优先搜索和深度优先搜索。

有向图的所有顶点使用整数1~n表示,对于每一个顶点,都有若干条有向边从该顶点出发,到达其他顶点,这些有向边的终点称为该顶点的邻接顶点。对于每一个顶点,都可以使用一条链表来记录它的所有邻接顶点,这条链表称为邻接链表。而有向图的所有顶点构成一个数组,所以所有顶点对应的邻接链表也构成了一个链表类型的数组。
邻接链表描述的有向图和邻接矩阵描述的有向图大多数函数都大同小异,本文对函数逻辑不做详细描述。以下代码主要为邻接链表描述下的有向图判断边是否存在、插入边、删除边、广度优先搜索、深度优先搜索。
关于有向图的更多阐述,详见[C++]有向图(邻接数组描述)

代码

先构建一个简单的链表类以满足邻接链表的需求

template<class T>
struct chainNode//定义链表节点
{
	T element;
	chainNode<T>* next;
	chainNode() {}
	chainNode(const T& element)
	{
		this->element = element;
	}
	chainNode(const T& element, chainNode<T>* next)
	{
		this->element = element;
		this->next = next;
	}
};
template<class T>
class graphChain//定义适合有向图的链表
{	
public:
	chainNode<T>* firstNode;
	int listSize;
	graphChain()
	{
		firstNode = NULL;
		listSize = 0;
	}
	int indexOf(const T& theElement)const//获取指定节点在链表中的坐标,若该节点不存在则返回-1
	{
		chainNode<T>* currentNode = firstNode;
		int index = 0;
		while (currentNode != NULL && currentNode->element != theElement)
		{
			currentNode = currentNode->next;
			index++;
		}
		if (currentNode == NULL)
			return -1;
		else
			return index;
	}
	void insert(const T& theElement)//为提高效率,所有插入都采用头插法
	{
		firstNode = new chainNode<T>(theElement, firstNode);
		listSize++;
	}
	bool erase(const T& theElement)//删除某节点,返回值表示删除是否成功(删除节点是否存在)
	{
		chainNode<T>* deleteNode;
		if (theElement == firstNode->element)//删除首项
		{
			deleteNode = firstNode;
			firstNode = firstNode->next;
		}
		else
		{
			chainNode<T>* currentNode = firstNode;
			while (currentNode->next != NULL && currentNode->next->element != theElement)
				currentNode = currentNode->next;
			if (currentNode->next == NULL)//没找到该节点则返回false
				return false;
			deleteNode = currentNode->next;
			currentNode->next = currentNode->next->next;
		}
		listSize--;
		delete deleteNode;
		return true;//删除成功返回true
	}
};

邻接链表描述的有向图类

template<class T>
struct edge//定义有向边
{
	int vertex1;//起点
	int vertex2;//终点
	T weight;//权值,对于无权图可以令T=bool,则weight可以表示该有向边是否存在
	edge(const int& v1, const int& v2, const T& w)
	{
		vertex1 = v1;
		vertex2 = v2;
		weight = w;
	}
};
class linkedDigraph//邻接链表描述的有向图
{
protected:
	int n;//顶点个数
	int e;//边个数
	graphChain<int>* aList;//邻接链表组
public:
	linkedDigraph(int theNumber)
	{
		n = theNumber;
		e = 0;
		aList = new graphChain<int>[n + 1];
	}
	~linkedDigraph() { delete[] aList; }
	bool existsEdge(const int& v1, const int& v2) const//判断两点之间的有向边是否存在
	{
		if (v1<1 || v2<1 || v1>n || v2>n || aList[v1].indexOf(v2)==-1)
			return false;
		else
			return true;
	}
	void insertEdge(edge<bool>* theEdge)//插入有向边
	{
		int v1 = theEdge->vertex1;
		int v2 = theEdge->vertex2;
		if (v1<1 || v2<1 || v1>n || v2>n || v1 == v2)
		{
			cout << "该有向边无效" << endl;
			return;
		}
		if (aList[v1].indexOf(v2) == -1)
		{
			aList[v1].insert(v2);
			e++;
		}
		else
			cout << "该有向边已存在" << endl;
	}
	void eraseEdge(const int& v1, const int& v2)//删除有向边
	{
		if (v1 >= 1 && v2 >= 1 && v1 <= n && v2 <= n)
		{
			bool flag = aList[v1].erase(v2);//删除有向边,并返回删除是否成功
			if (flag)
				e--;
			else
				cout << "该有向边不存在" << endl;
		}
	}
	void bfs(int v, int reach[], int label)//广度优先搜索(队列)
	{
		queue<int> q;
		reach[v] = label;
		q.push(v);
		while (!q.empty())
		{
			int w = q.front();
			cout << w << " ";//输出搜索到的顶点
			q.pop();
			for (chainNode<int>* u = aList[w].firstNode; u != NULL; u = u->next)
			{
				int temp = u->element;
				if (reach[temp] == 0)
				{
					q.push(temp);
					reach[temp] = label;
				}
			}
		}
	}
	void dfs(int v, int reach[], int label)//深度优先搜索(递归)
	{
		reach[v] = label;
		cout << v << " ";//输出搜索到的顶点
		for (chainNode<int>* u = aList[v].firstNode; u != NULL; u = u->next)
		{
			int temp = u->element;
			if (reach[temp] == 0)
				dfs(temp, reach, label);
		}
	}
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值