[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
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
C++ 中,我们可以使用邻接表来存储有向图邻接表是一种基于链表数据结构,它可以有效地存储图中的节点和边,并提供快速的遍历和搜索。 邻接表由一个数组和一个链表组成。数组的每个元素对应一个图中的节点,而链表则包含从该节点出发的所有边。具体实现过程如下: 1. 定义一个结构体来表示图中的边: ``` struct Edge { int to; // 边的终点 int weight; // 边的权重(如果有) Edge* next; // 指向下一条边的指针 }; ``` 2. 定义一个数组来存储节点和指向其邻接表的指针: ``` const int MAXN = 100; // 最大节点数 Edge* head[MAXN]; // 每个节点指向其邻接表的头指针 ``` 3. 对于每个节点,初始化其邻接表为空: ``` for (int i = 0; i < MAXN; i++) { head[i] = nullptr; } ``` 4. 对于每条边,创建一个新的 `Edge` 结构体,并将其添加到起点节点的邻接表中: ``` void addEdge(int from, int to, int weight) { Edge* e = new Edge; e->to = to; e->weight = weight; e->next = head[from]; head[from] = e; } ``` 完整代码如下: ``` #include <iostream> using namespace std; const int MAXN = 100; // 最大节点数 struct Edge { int to; // 边的终点 int weight; // 边的权重(如果有) Edge* next; // 指向下一条边的指针 }; Edge* head[MAXN]; // 每个节点指向其邻接表的头指针 void addEdge(int from, int to, int weight) { Edge* e = new Edge; e->to = to; e->weight = weight; e->next = head[from]; head[from] = e; } int main() { // 添加边 addEdge(0, 1, 1); addEdge(0, 2, 2); addEdge(1, 2, 3); addEdge(2, 3, 4); // 输出邻接表 for (int i = 0; i < MAXN; i++) { if (head[i] != nullptr) { cout << i << ": "; for (Edge* e = head[i]; e != nullptr; e = e->next) { cout << "(" << e->to << ", " << e->weight << ") "; } cout << endl; } } return 0; } ``` 这个程序将会输出以下内容: ``` 0: (2, 2) (1, 1) 1: (2, 3) 2: (3, 4) ``` 其中,每行表示一个节点的邻接表,格式为 `节点编号: (邻居节点编号, 边权重) ...`。例如,第一行表示节点 0 与节点 2 之间有一条边权重为 2 的边,与节点 1 之间有一条边权重为 1 的边。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值