有向图的十字链表存储以及相关操作

以十字链表作为有向图的存储结构,将邻接表和逆邻接表结合起来,对统计结点的出入度很方便,

这是之前的一篇日志,也是说图的存储的,有兴趣的也可以看看 图的几种存储结构

下面是代码:

//graph.h

#include <iostream>
#include <string>
#include <queue>
#include <stack>
using namespace std;

bool visited[100]; //顶点是否已被访问的标志数组

//十字链表存储图
//弧结点
struct ArcBox
{
	//弧结点头尾结点位置
	int tailvex;
	int headvex;
	//弧头和弧尾相同的弧的链域
	ArcBox *hlink;
	ArcBox *tlink;
};

//顶点节点
struct VexNode
{
	string data; //顶点名称
	ArcBox *firstin; //指向第一条入弧
	ArcBox *firstout; //指向第一条出弧
};

class OLGraph
{
private:
	VexNode *xlist; //指向顶点数组的指针
	int vexnum;  //顶点数
	int arcnum;  //弧数
	int maxnum; //顶点数的最大值
public:
	OLGraph(int num=20)
	{
		xlist=new VexNode[num];
		maxnum=num;
	}
	
	int Locate_Vex(string v)
	{
		for(int i=0;i<vexnum;i++)
		{
			if(xlist[i].data==v)
				return i;
		}
		return -1;
	}

	void CreateDG_OLG()
	{
		//构造有向图
		string v1,v2;
		int i,j,k;
		cout<<"输入顶点数和边的数目:";
		cin>>vexnum>>arcnum;
		
		while(vexnum>maxnum)		
		{
			cout<<"顶点数目大于最大限制,请重新输入:";
			cin>>vexnum;
		}

		cout<<"输入各个顶点的名称:";
		for(i=0;i<vexnum;i++)
		{
			cin>>xlist[i].data;
			xlist[i].firstin=NULL;
			xlist[i].firstout=NULL;
		}
		
		for(k=0;k<arcnum;k++)
		{
			cout<<"输入第"<<k+1<<"条边的两个顶点(尾—>头的顺序):";
			cin>>v1>>v2;
			i=Locate_Vex(v1);
			j=Locate_Vex(v2);
			
			while(i == -1 || j == -1)
			{
				cout<<"结点位置输入错误,重新输入: ";
				cin>>v1>>v2;
				i=Locate_Vex(v1);
				j=Locate_Vex(v2);	
			}		
			
			ArcBox *p=new ArcBox;
			p->tailvex=i;
			p->headvex=j;
			p->hlink=xlist[j].firstin;
			p->tlink=xlist[i].firstout;
			xlist[i].firstout=xlist[j].firstin=p;
		}

		cout<<"有向图构造完成"<<endl;
	}

	//统计顶点入度
	int In_degree(string v)
	{
		int pos=Locate_Vex(v);
		if(pos == -1)
		{
			cout<<"结点不在图中"<<endl;
			return -1;
		}
		ArcBox *p=xlist[pos].firstin;
		int ins=0;
		while(p)
		{
			ins++;
			p=p->hlink;
		}
		return ins;
	}

	//统计顶点出度
	int Out_degree(string v)
	{
		int pos=Locate_Vex(v);
		if(pos == -1)
		{
			cout<<"结点不在图中"<<endl;
			return -1;
		}
		ArcBox *p=xlist[pos].firstout;
		int out=0;
		while(p)
		{
			out++;
			p=p->tlink;
		}
		return out;
	}

	//深度优先遍历
	void DFS(int v)
	{
		visited[v]=true;
		cout<<xlist[v].data<<"  ";
		ArcBox *p=xlist[v].firstout;
		while(p)
		{
			if(!visited[p->headvex])
				DFS(p->headvex);
			p=p->tlink;
		}
	}

	void DFS_Traverse()
	{
		for(int i=0;i<vexnum;i++)
			visited[i]=false;
		for(i=0;i<vexnum;i++)
			if(!visited[i])
				DFS(i);
	}

	//广度优先遍历
	void BFS(int v)
	{
		visited[v]=true;
		cout<<xlist[v].data<<"  ";
		queue<int> qu;
		int vex;
		ArcBox *p;
		qu.push(v);
		while(!qu.empty())
		{
			vex=qu.front();
			qu.pop();
			p=xlist[vex].firstout;
			while(p)
			{
				if(!visited[p->headvex])
				{
					visited[p->headvex]=true;
					cout<<xlist[p->headvex].data<<"  ";
					qu.push(p->headvex);
				}
				p=p->tlink;
			}
		}
	}

	void BFS_Traverse()
	{
		for(int i=0;i<vexnum;i++)
			visited[i]=false;
		for(i=0;i<vexnum;i++)
			if(!visited[i])
				BFS(i);
	}

	void DFS_2(int v)
	{
		visited[v]=true;
		cout<<xlist[v].data<<"  ";
		stack<int> s;
		ArcBox *p;
		int pos;
		s.push(v);
		while(!s.empty())
		{
			pos=s.top();
			p=xlist[pos].firstout;
			while(p && visited[p->headvex])
				p=p->tlink;
			if(!p)
				s.pop();
			else
			{
				visited[p->headvex]=true;
				cout<<xlist[p->headvex].data<<"  ";
				s.push(p->headvex);
			}
		}
	}

	void DFS_Traverse_2()
	{
		for(int i=0;i<vexnum;i++)
			visited[i]=false;
		for(i=0;i<vexnum;i++)
			if(!visited[i])
				DFS_2(i);
	}
	//求连通分支数
	int Connect_Cpnt()
	{
		for(int i=0;i<vexnum;i++)
			visited[i]=false;
		cout<<"下面的每一行显示一个连通分支:"<<endl;
		int num=1;
		DFS(0);
		cout<<endl;
		for(i=0;i<vexnum;i++)
		{
			if(!visited[i])
			{
				num++;
				DFS(i);
				cout<<endl;
			}
		}
		return num;
	}
};

#include "graph.h"
#include <iostream>
#include <string>
using namespace std;

int main()
{
	OLGraph G;
	string v;
	int ins,out,a;
	G.CreateDG_OLG();
	
	cout<<"输入要统计哪个结点的入度:";
	cin>>v;
	ins=G.In_degree(v);
	if(ins != -1)
		cout<<"顶点"<<v<<"的入度为:"<<ins<<endl;

	cout<<"输入要统计哪个结点的出度:";
	cin>>v;
	out=G.Out_degree(v);
	if(out != -1)
		cout<<"顶点"<<v<<"的出度为:"<<out<<endl;

	cout<<"深度优先遍历:";
	G.DFS_Traverse();
	cout<<endl;

	cout<<"广度优先遍历:";
	G.BFS_Traverse();
	cout<<endl;

	cout<<"计算图的连通分支"<<endl;
	int num=G.Connect_Cpnt();
	cout<<"图的连通分支数目为:"<<num<<endl;

	cout<<"深度优先遍历非递归:";
	G.DFS_Traverse_2();
	cout<<endl;

	return 0;
}

测试结果:

输入顶点数和边的数目:12 12
输入各个顶点的名称:v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11 v12
输入第1条边的两个顶点(尾—>头的顺序):v1 v3
输入第2条边的两个顶点(尾—>头的顺序):v1 v5
输入第3条边的两个顶点(尾—>头的顺序):v2 v1
输入第4条边的两个顶点(尾—>头的顺序):v2 v5
输入第5条边的两个顶点(尾—>头的顺序):v5 v4
输入第6条边的两个顶点(尾—>头的顺序):v4 v2
输入第7条边的两个顶点(尾—>头的顺序):v3 v6
输入第8条边的两个顶点(尾—>头的顺序):v3 v4
输入第9条边的两个顶点(尾—>头的顺序):v7 v8
输入第10条边的两个顶点(尾—>头的顺序):v7 v9
输入第11条边的两个顶点(尾—>头的顺序):v8 v10
输入第12条边的两个顶点(尾—>头的顺序):v11 v12
有向图构造完成
输入要统计哪个结点的入度:v4
顶点v4的入度为:2
输入要统计哪个结点的出度:v12
顶点v12的出度为:0
深度优先遍历:v1  v5  v4  v2  v3  v6  v7  v9  v8  v10  v11  v12
广度优先遍历:v1  v5  v3  v4  v6  v2  v7  v9  v8  v10  v11  v12
计算图的连通分支
下面的每一行显示一个连通分支:
v1  v5  v4  v2  v3  v6
v7  v9  v8  v10
v11  v12
图的连通分支数目为:3
深度优先遍历非递归:v1  v5  v4  v2  v3  v6  v7  v9  v8  v10  v11  v12
Press any key to continue

所生成的有向图的示意图,晚点再放 今晚得上实验课了,差点忘了。。。闪

下面是图的示意图:


  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
稀疏矩阵是其中大多数元素为0的矩阵,我们可以使用十字链表来表示稀疏矩阵,从而节省存储空间。下面是基于十字链表存储的稀疏矩阵创建和输出操作的实现。 首先,我们定义一个节点类,用于表示稀疏矩阵的非零元素节点。该节点类包含四个成员变量:row、col、value和right。其中row和col分别表示该节点所在的行和列的索引值,value表示该节点的数值,right是指向下一个非零元素的指针。 然后,我们创建一个稀疏矩阵类,该类包含一个头节点head、一个保存行头节点的一维数组rows、一个保存列头节点的一维数组cols以及两个整型变量row_num和col_num。头节点head用于表示稀疏矩阵的整体信息,rows和cols数组分别用于保存每一行和每一列的头节点,row_num和col_num分别保存稀疏矩阵的行数和列数。 在创建操作中,我们首先通过读取输入,获取稀疏矩阵的行数row_num和列数col_num。然后,根据row_num和col_num创建rows和cols数组并初始化头节点head。接下来,我们通过遍历输入,获取每个非零元素的行列索引和数值,并创建相应的节点,将其插入到十字链表中。最后,我们根据稀疏矩阵的规模和十字链表的结构,输出稀疏矩阵的元素。 具体的实现过程可以参考以下伪代码: class Node: def __init__(self, row, col, value): self.row = row self.col = col self.value = value self.right = None class SparseMatrix: def __init__(self): self.head = Node(-1, -1, -1) self.rows = [] self.cols = [] self.row_num = 0 self.col_num = 0 def create_sparse_matrix(self): self.row_num, self.col_num = input().split() self.row_num = int(self.row_num) self.col_num = int(self.col_num) self.rows = [Node(-1, -1, -1) for _ in range(self.row_num)] self.cols = [Node(-1, -1, -1) for _ in range(self.col_num)] self.head.row = self.row_num self.head.col = self.col_num for _ in range(self.row_num): row_data = input().split() row = int(row_data[0]) col = int(row_data[1]) value = int(row_data[2]) node = Node(row, col, value) # 插入链表中 self.insert_node(node) def insert_node(self, node): # 插入到对应行的链表中 if self.rows[node.row].right is None: self.rows[node.row].right = node else: cur = self.rows[node.row].right while cur.right is not None and cur.right.col < node.col: cur = cur.right node.right = cur.right cur.right = node # 插入到对应列的链表中 if self.cols[node.col].right is None: self.cols[node.col].right = node else: cur = self.cols[node.col].right while cur.right is not None and cur.right.row < node.row: cur = cur.right node.right = cur.right cur.right = node def output_sparse_matrix(self): print(self.row_num, self.col_num) for i in range(self.row_num): cur = self.rows[i].right while cur is not None: print(cur.row, cur.col, cur.value) cur = cur.right 通过以上代码,我们实现了基于十字链表存储的稀疏矩阵的创建和输出操作

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值