数据结构 图

 1、数组(邻接矩阵)

无向图的邻接矩阵是对称的
顶点i的度=第i行(列)中1的个数

特别:完全图的邻接矩阵中,对角元素为0,其余1。

#define MVNum 100     //最大顶点数
typedef string VerTexType; //假设顶点的数据类型为字符串
typedef int ArcType;             //假设边的权值类型为整型

//------------图的邻接矩阵------------------
typedef struct {
    VerTexType vexs[MVNum];            //顶点表
    ArcType arcs[MVNum][MVNum];      //邻接矩阵
    int vexnum, arcnum;                //图的当前点数和边数
} Graph;

//得到顶点i的数据
VerTexType Vertexdata(const Graph& g, int i)
{
    return g.vexs[i];
}

int LocateVex(const Graph& g, VerTexType v)
{
    //确定点v在G中的位置
    for (int i = 0; i < g.vexnum; ++i)
        if (g.vexs[i] == v)
            return i;
    return -1;
}//LocateVex

int FirstAdjVex(const Graph& g, int v)
{
    //返回v的第一个邻接点编号,没有返回-1
    for (int i = 0; i < g.vexnum; i++)if (g.arcs[v][i])return i;
    return -1;
}//FirstAdjVex

int NextAdjVex(const Graph& g, int v, int w)
{
    //返回v相对于w的下一个邻接点,没有返回-1
    for (int i = w + 1; i < g.vexnum; i++)  if (g.arcs[v][i])return i;
    return -1;

}//NextAdjVex

void CreateUDG(Graph& g)
{
    //采用邻接矩阵表示法,创建无向图G
    cin >> g.vexnum >> g.arcnum;
    for (int i = 0; i < g.vexnum; i++)cin >> g.vexs[i];
    for (int i = 0; i < g.vexnum; i++)
        for (int j = 0; j < g.vexnum; j++) {
            g.arcs[i][j] = 0;
        }
    for (int k = 0; k < g.arcnum; k++)
    {
        string s1, s2;
        cin >> s1 >> s2;
        int m = LocateVex(g, s1);
        int n = LocateVex(g, s2);
        if (m != -1 && n != -1)g.arcs[m][n] = g.arcs[n][m] = 1;
    }

}//CreateUDN

void DestroyUDG(Graph& g)
{
    //you should do this
    memset(g.arcs, 0, sizeof( g.arcs ));
}


//输出邻接矩阵
void PrintUDG(const Graph& g)
{
    int i, j;
    cout << "    ";
    for (i = 0; i < g.vexnum; i++) {
        cout << setw(4) << g.vexs[i];
    }
    cout << endl;
    for (i = 0; i < g.vexnum; i++) {
        cout << setw(4) << g.vexs[i];
        for (j = 0; j < g.vexnum; j++) {
            cout << setw(4) << g.arcs[i][j];
        }
        cout << endl;
    }
}

 

 有向图的邻接矩阵可能是不对称的。

行为出度,列为入度

顶点的出度=第i行元素之和顶点的入度=第i列元素之和
顶点的度=第i行元素之和+第i列元素之和
 

 

#define MAXlnt 32999  // 极大值,无穷
#define MVNum 100     //最大顶点数
typedef string VerTexType; //假设顶点的数据类型为字符串
typedef int ArcType;             //假设边的权值类型为整型


//------------图的邻接矩阵------------------
typedef struct {
    VerTexType vexs[MVNum];            //顶点表
    ArcType arcs[MVNum][MVNum];      //邻接矩阵
    int vexnum, arcnum;                //图的当前点数和边数
} AMGraph;

int LocateVex(AMGraph G, VerTexType u)
{
    // 图G中查找顶点u,存在则返回顶点表中的下标;否则返回-1
    int i;
    for (i = 0; i < G.vexnum; ++i)
        if (u == G.vexs[i])
            return i;
    return -1;
}


Status CreateUDN(AMGraph &G)
{
    // 采用邻接矩阵表示法,创建无向网G
    int i,k,j,w;
    VerTexType v1,v2;
        G.vexnum >> G.arcnum; // 输入总顶点数,总边数
    for(i = 0; i<G.vexnum; ++i)
    cin >> G.vexs[i];
    // 依次输入点的信息
    for (i = 0; i < G.vexnum; ++i) // 初始化邻接矩阵
    for(j = 0; j<G.vexnum; ++j)
        G.arcs[i][j] = MAXlnt; // 边的权值均置为极大值
    for (k = 0; k < G.arcnum; ++k)
    {                     // 构造邻接矩阵
    cin >> v1 >> v2 >> w; // 输入—条边所依附的顶点及边的权值
    i = LocateVex(G, v1);
    j = LocateVex(G, v2); // 确定v1和v2在G中的位置
    G.arcs[i][j] = w; // 边<v1,v2>的权值置为w
    G.arcs[j][i] = G.arcs[i][j]; // 置<v1, v2>的对称边<v2, v1>的权值为w
    }//for
    return 1;
    } // CreateUDN

2、邻接表

 

#define MVNum 100         //最大顶点数
#define OK 1

typedef string VerTexType; //顶点信息
typedef int OtherInfo;    //和边相关的信息

//- - - - -图的邻接表存储表示- - - - -
typedef struct ArcNode {                //边结点
    int adjvex;                          //该边所指向的顶点的位置
    struct ArcNode* nextarc;          //指向下一条边的指针
    OtherInfo info;                      //和边相关的信息
} ArcNode;

typedef struct VNode {
    VerTexType data;                    //顶点信息
    ArcNode* firstarc;                //指向第一条依附该顶点的边的指针
} VNode, AdjList[MVNum];                //AdjList表示邻接表类型

typedef struct {
    AdjList vertices;                  //邻接表
    int vexnum, arcnum;              //图的当前顶点数和边数
} ALGraph;

 采用邻接表表示法创建无向网

【算法思想】
(1)输入总顶点数和总边数。

(2)建立顶点表
依次输入点的信息存入顶点表中
使每个表头结点的指针域初始化为NULL

(3)创建邻接表
依次输入每条边依附的两个顶点确定两个顶点的序号i和j,建立边结点
将此边结点分别插入到v,和v;对应的两个边链表的头部

int CreateUDG(Graph& g)
{
    //采用邻接表表示法,创建无向图G
    int i, j, k;
    ArcNode* p1, * p2;
    cin >> g.vexnum >> g.arcnum;
    k = g.vexnum;
    for (i = 0; i < k; ++i)
    {
        cin >> g.vertices[i].data;
        g.vertices[i].firstarc = NULL;
    }
    k = g.arcnum;
    while (k--)
    {
        VerTexType v1, v2;
        cin >> v1;
        cin >> v2;
        i = LocateVex(g, v1);
        j = LocateVex(g, v2);
        p1 = new ArcNode;
        p2 = new ArcNode;
        p1->adjvex = j;
        p1->nextarc = g.vertices[i].firstarc;
        g.vertices[i].firstarc = p1;
        p2->adjvex = i;
        p2->nextarc = g.vertices[j].firstarc;
        g.vertices[j].firstarc = p2;
    }
   
    for (int i = 0; i < g.vexnum; ++i) {
        sort(g.vertices[i].firstarc); 保证有序,不依赖输入次序
    }//for
    return OK;
}//CreateUDG

 1.联系:邻接表中每个链表对应于邻接矩阵中的一行,链表中结点个数等于一行中非零元素的个数。


3、图的遍历

1)深度优先搜索(DFS)

连通图的深度优先遍历类似手树的先根遍历
 

void DFS(AMGraph G, int v){
//图G为邻接矩阵类型
cout<<v; visited[v] = true;//访问第v个顶点
for(w = 0; w< G.vexnum; w++)//依次检查邻接矩阵v所在的行
if((G.arcs[v][w]!=0)&& (!visited[w]))
DFS(G,w);
//w是v的邻接点,如果w未访问,则递归调用DFS
}
void DFS_AL(AMGraph G, int v){
//图G为邻接表类型
cout<<v; visited[v] = true;//访问第v个顶点
p=G.vertices[v].firstarc //p指向v边链表的第一个边结点
while(!p)
{
    w=p->adjvex; //w是v的邻接点
if(!visited[w])
DFS(G,w);
p=p->nextarc; //指向下一边结点
//w是v的邻接点,如果w未访问,则递归调用DFS
}
}

 2)广度优先搜索(BFS)

类似于树的按层次遍历

void BFS(Graph G, int v){
    //按广度优先非递归遍历连通图G
    cout<<v; visited[v] = true;//访问第v个顶点
lnitQueue(Q);
//辅助队列Q初始化,置空
EnQueue(Q, v);
//v进队
while(!QueueEmpty(Q)){
//队列非空
DeQueue(Q, u);
//队头元素出队并置为u
for(w = FirstAdjVex(G, u); w> =0; w = NextAdjVex(G, u, w))
if(!visited[w]){
//w为u的尚未访问的邻接顶点
cout<<w; visited[w] = true; EnQueue(Q, w);//w进队
}//if
}//while
}//BFS

DFS和BFS比较 

·空间复杂度相同,都是O(n)(借用了堆栈或队列) ;
·时间复杂度只与存储结构,邻接矩阵O(n^2)或邻接表O(e+n)有关,而与搜索路径无关。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值