【算法与数据结构】图 -- 十字链表

图的【十字链表】表示法是一种链式存储结构,可以看成是【邻接表】和【逆邻接表】的组合

本文中用到的有向图


/************************************************************************
有向图的存储:十字链表

有向图的十字链表存储结构,是有一种链式存储结构,可以看成是【邻接表】和【逆邻接表】
的结合。
图中每条弧对应一个【弧结点】,每个顶点对应一个【顶点结点】

弧结点
--------------------------------------------
| tailvex | headvex | hlink | tlink | info |
--------------------------------------------
talivex:以该弧为【弧尾】的结点在图中的位置
headvex:以该弧为【弧头】的结点在图中的位置
hlink: 下一条与该弧有【相同弧头的弧】
tlink: 下一条与该弧有【相同弧尾的弧】
info: 弧的相关信息,权值等

顶点结点
-----------------------------
| data | firstin | firstout |
-----------------------------
data: 该结点的数据
firstin: 第一条以该弧为弧头的【弧结点】
firstout:第一条以该弧为弧尾的【弧结点】

************************************************************************/

相关数据结构


//顶点结点最大数量
int const MAX_VERTEXNUM = 100;

//数据结构

typedef int InfoType;
typedef int Data;

//弧结点
typedef struct _tagArcBox
{
int tailvex; //该弧的弧尾结点在图中的位置
int headvex; //该弧的弧头结点在图中的位置
struct _tagArcBox* hlink; //下一条与该弧有相同弧头结点的弧
struct _tagArcBox* tlink; //下一条与该弧有相同弧尾结点的弧
InfoType info; //弧的相关信息
}ArcBox;

//顶点结点
typedef struct _tagArcNode
{
Data data; //数据
ArcBox* firstin; //第一条以该节点为弧尾的弧
ArcBox* firstout; //第一条以该结点为弧头的弧
}ArcNode;

//十字链表存储结构的有向图
typedef struct _tagOLGraph
{
ArcNode vertex[MAX_VERTEXNUM]; //顶点向量

int vexnum; //顶点数
int arcnum; //弧树

}OLGraph, *POLGraph;

从顶点向量中查找该顶点在图中的位置(下标)


//输入图的【顶点向量】和某个顶点的数据
//获取此顶点在顶点向量中的位置(下标)
int LocateNode(ArcNode* pNodesArr, Data data, int length)
{
if( NULL == pNodesArr ) return NULL;

for (int i = 0; i < length; ++ i)
{
if (pNodesArr[i].data == data) return i;
}

return -1;
}

//输入【图】和某顶点的数据
//获取该顶点在顶点向量中的位置(下标)
int LocateNode(POLGraph& pOLGraph, Data data)
{
return (NULL == pOLGraph ?
NULL : LocateNode(pOLGraph->vertex, data, pOLGraph->vexnum) );
}

有向图的创建


/************************************************************************
当使用这种函数原型时:
void CreateOLGraph(POLGPraph& pOLGraph)
{
pOLGraph = new OLGraph();
//codes
pOLGraph->vexnum = num; //这里报运行时错误! why?
}
************************************************************************/
//创建十字链表有向图
POLGraph CreateOLGraph()
{
POLGraph pOlGraph = NULL;

__try
{
pOlGraph = new OLGraph();

if(NULL == pOlGraph) {cerr << "申请图结点失败!\n"; return NULL;}

int num = 0;
cout << "请输入图的顶点数量:";
cin >> num;
pOlGraph->vexnum = num;

cout << endl;

cout << "请输入图的弧的数量:";
cin >> num;
pOlGraph->arcnum = num;

cout << endl;

Data data = 0;

cout << endl << "--------开始 初始化顶点向量-----------"<<endl;
for (int i = 0; i < pOlGraph->vexnum; ++i)
{
cout << "请输入结点的值:";
cin >> data;

pOlGraph->vertex[i].data = data;
pOlGraph->vertex[i].firstin = NULL;
pOlGraph->vertex[i].firstout = NULL;
cout<<endl;

} //for
cout <<endl<<"------------结束 初始化顶点向量------------"<<endl;

cout<<endl<<endl;

cout << "************开始 初始化弧结点 **************"<<endl;
for(int i = 0; i < pOlGraph->arcnum; ++ i)
{
cout << "请输入弧的弧尾结点:";
cin >> data;
int begin = LocateNode(pOlGraph->vertex, data, pOlGraph->arcnum);
if(-1 == begin) {cerr << "您输入的弧尾结点不在图中,请重新输入"<<endl; --i; continue;}

cout << "请输入弧的弧头结点:";
cin >> data;
int end = LocateNode(pOlGraph->vertex, data, pOlGraph->arcnum);
if(-1 == end) {cerr << "您输入的弧头结点不在图中,请重新输入"<<endl; -- i; continue;}

cout << "请输入弧的权值:";
cin >> data;

cout<<endl<<endl;

ArcBox* pArcBox = new ArcBox();
if(NULL == pArcBox) {cerr << "申请弧结点失败!"<<endl; -- i; continue;}

pArcBox->tailvex = begin; //该弧的弧尾在图中的位置
pArcBox->headvex = end; //该弧的弧头在图中的位置
pArcBox->hlink = pOlGraph->vertex[end].firstin; //下一条与该弧有相同弧尾的弧结点
pArcBox->tlink = pOlGraph->vertex[begin].firstout; //下一条与该弧有相同弧头的弧结点
pArcBox->info = data; //权值

pOlGraph->vertex[begin].firstout = pOlGraph->vertex[end].firstin = pArcBox;

} //for

} //__try

__except(1)
{
cerr << endl<<"有异常发生"<<endl;
}

return pOlGraph;
}

运行情况:

出度和入度


//求图的出度
//先根据输入的顶点的值,求得该点所在的顶点向量的分量
//然后得到该点的firstout,然后再得到所有与该弧有相同弧尾
//结点的弧(的条数)
int OutDegree(POLGraph& pOLGraph, Data data)
{
int nCount = 0;

//根据结点的值定位该点在图的顶点向量中的位置(下标)
int nIndex = LocateNode(pOLGraph, data);
if(-1 == nIndex) {cerr << "该点不在图中,所以没有出度!\n"<<endl; return -1;}

//得到该结点指针
ArcNode* pArcNode = &(pOLGraph->vertex[nIndex]);
if(NULL == pArcNode) {cerr << "在图中查找该顶点出错!\n"<<endl; return -1;}

//第一条该顶点为弧尾的弧(该顶点结点的第一条出边)
ArcBox* pArcBox = pArcNode->firstout;

//查找所有以该【顶点结点】为【弧尾】的【弧结点】
while(NULL != pArcBox)
{
++ nCount;
pArcBox = pArcBox->tlink;
}

return nCount;
}

//定点的入度
int InDegree(POLGraph& pOLGraph, Data data)
{
int nCount = 0;

//定位该顶点结点在顶点向量中的位置(下标)
int nIndex = LocateNode(pOLGraph, data);
if(-1 == nIndex){cerr << "该点不在图中,所以没有入度!\n"<<endl; return -1;}

//得到该顶点结点的指针
ArcNode* pArcNode = &(pOLGraph->vertex[nIndex]);
if(NULL == pArcNode) {cerr << "在图中查找该点出错!"<<endl; return -1;}

//第一条以该顶点结点为弧头的弧(该顶点结点的第一条入边)
ArcBox* pArcBox = pArcNode->firstin;

//查找所有以该【顶点结点】为【弧头】的【弧结点】
while(NULL != pArcBox)
{
++nCount;
pArcBox = pArcBox->hlink;
}

return nCount;
}

 查找出度 / 入度


    POLGraph pGraph = CreateOLGraph();

int num = 0;
for(int i = 0; i < pGraph->vexnum + 3; ++ i)
{
cout << "请输入带查的顶点的值:";
cin >> num;

cout<<"结点 "<< num << " 的出度OutDegree为:"<<OutDegree(pGraph, num);
cout<<endl;
cout<<"结点 "<< num << " 的入度InDegree为:"<<InDegree(pGraph, num);

cout<<endl<<endl;
}

 深度优先遍历(DFS)


/************************************************************************
深度优先遍历
从某顶点出发,访问之,然后获得该顶点的第一条出边(firstout),如果该出边
不为空,则获得该条出边的【弧头】结点在图中的位置(下标),查看此下标的结点
是否被访问过,如果没有则根据此下标获取该结点,然后递归访问之;如果此结点
被访问过了,则说明出现回路,及此条弧指向了之前访问过的结点,需要跳出循环,
否则出现死循环。

************************************************************************/

//顶点结点是否遍历过标志数组
bool* pVisited = NULL;

void DFS(POLGraph& pOLGraph, ArcNode* pArcNode)
{
int nIndex = LocateNode(pOLGraph, pArcNode->data);
pVisited[nIndex] = true;
cout << "the node is "<<pArcNode->data<<endl;

ArcBox* pArcBox = pArcNode->firstout;

while(NULL != pArcBox)
{
//该弧的弧头在图中的位置
int nHeadVex = pArcBox->headvex;

if (pVisited[nHeadVex] == false)
{
ArcNode* pHeadNode = &(pOLGraph->vertex[nHeadVex]);
DFS(pOLGraph, pHeadNode);
}

//如果某条弧的弧头结点已经被访问过时,则说明已经有了回路,此时要跳出循环
//否则会在while中死循环
else
{
break;
}
}
}

//有向图的深度优先遍历
void DFSTraverse(POLGraph& pOLGraph)
{
if(NULL == pOLGraph) {cerr << "该图为空!"; return;}

pVisited = new bool[pOLGraph->vexnum]();
for (int i = 0; i < pOLGraph->vexnum; ++ i) pVisited[i] = false;

for (int i = 0; i < pOLGraph->vexnum; ++ i)
{
if (! pVisited[i])
{
DFS(pOLGraph, &pOLGraph->vertex[i]);
}
}
}

 

深度优先遍历结果

广度优先遍历(BFS)

【算法与数据结构】图 -- 十字链表

时间: 2024-10-12 15:53:28

【算法与数据结构】图 -- 十字链表的相关文章

算法与数据结构(二):链表

上一篇简单的开了一个头,简单介绍了一下所谓的时间复杂度与空间复杂度,从这篇开始将陆陆续续写一下常用的数据结构:链表.队列.栈.树等等. 链表当初是我在学校时唯一死磕过的数据结构,那个时候自己还算是一个好学生,虽然上课没怎么听懂,但是课后还是根据仔细调试过老师给的代码,硬是自己给弄懂了,它是我离校时唯一能够写出实现的数据结构,现在回想起来应该是它比较简单,算法也比较直来直去吧.虽然它比较简单,很多朋友也都会链表.但是作为一个系列,如果仅仅因为它比较简单而不去理会,总觉得少了点什么,所以再这仍然将其

数据结构——图的链表实现

图的链表实现 之前实现了图的数组实现 http://blog.csdn.net/cinmyheart/article/details/41370465 下图仅作示意性说明,和测试数据有点区别,测试数据还是用的原来数组实现时的测试数据,这并不影响图的数据结构的表示(其实我就是懒得再做一遍原始数据了...哈哈) 现对图进行抽象,对于整个图,我用了结构体struct graph,图中有节点,那么节点我用struct vertex 进行抽象,至于struct vertex adjacent[0]这个技巧

算法与数据结构--图的实现、基本操作及应用

#include<iostream> #include<queue> #include<stack> using namespace std; #define INFINITY DBL_MAX //无穷大 #define MAX_VERTEX_NUM 20 //最大顶点个数 enum GraphKind //图的类型 { DG,DN,UDG,UDN//有向图.有向网.无向图.无向网 }; //弧结构 typedef struct ArcCell { double adj

数据结构之十字链表

#define MAXSIZE 100 #define ERROR 1 #define OK 0 typedef struct{ int a; char s; }ElemType; typedef struct{ ElemType e; int i,j; Node *rigth; Node *down; }Node,*PointNode; typedef struct{ PointNode *C; PointNode *R; int mu,nu,tu; }Ta; int init_table(T

[数据结构]图,邻接多重表,十字链表

十字链表 你会发现,要表示一个有向图,因为有 出度 和 入度 ,需要两个邻接表:邻接表和逆邻接表. 其实我们可以把这两个表整合在一起,也就是十字链表(Orthogonal List). 我们依然需要构造一种结构体A,用结构体A的数组来存放所有顶点-我们其实可以把它叫做 顶点表. 我们构造的结构体A如下: data firstin firstout 构造结构体B,用结构体B来记录与这个顶点 用边邻接的 顶点的相关信息,我们把它叫做 边表. tailvex headvex headlink tail

7-3-有向图的十字链表存储结构-图-第7章-《数据结构》课本源码-严蔚敏吴伟民版

课本源码部分 第7章  图 - 有向图的十字链表存储结构 ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑        本源码引入的文件  链接? Status.h.Scanf.c.LinkQueue.c        

数据结构之---C++语言实现图的十字链表存储表示

最近一直忙着考研复习,很久都没有更新博客了,今天写一篇数据结构的存储. //有向图的十字链表存储表示 //杨鑫 #include <iostream> #include <cstdio> #include <stdlib.h> #include <cstring> using namespace std; #define MAX_VERTEX_NUM 20 #define OVERFLOW -2 #define OK 1 typedef int Status

看数据结构写代码(37) 图的十字链表的表示与实现

图的邻接表在 查找 有向图的 出度 很 方便,但是 在 查找 入度 时,需要遍历整个图.如果想要 方便的 查找 入度,需要 建立 逆邻接表.十字链表 正好 就是 邻接表 和 逆邻接表的集合.具体结构图如下: 感觉 十字链表 在 查找 入度时 方便 一些,其他 跟 邻接表没什么区别. 源代码 网盘地址:点击打开链接 代码如下: // CrossLinkGraph.cpp : 定义控制台应用程序的入口点. //有向图的十字链表表示法 #include "stdafx.h" #include

java 数据结构 图中使用的一些常用算法 图的存储结构 邻接矩阵:图的邻接矩阵存储方式是用两个数组来标示图。一个一位数组存储图顶点的信息,一个二维数组(称为邻接矩阵)存储图中边或者弧的信息。 设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为: 实例如下,左图是一个无向图。右图是邻接矩阵表示:

以下内容主要来自大话数据结构之中,部分内容参考互联网中其他前辈的博客. 图的定义 图是由顶点的有穷非空集合和顶点之间边的集合组成,通过表示为G(V,E),其中,G标示一个图,V是图G中顶点的集合,E是图G中边的集合. 无边图:若顶点Vi到Vj之间的边没有方向,则称这条边为无项边(Edge),用序偶对(Vi,Vj)标示. 对于下图无向图G1来说,G1=(V1, {E1}),其中顶点集合V1={A,B,C,D}:边集合E1={(A,B),(B,C),(C,D),(D,A),(A,C)}: 有向图:若