数据结构 C++实现 图的操作

一、图的邻接矩阵存储 AMGraph 

/*有向图的邻接矩阵存储*/

#define maxValue 999                 //表示正无穷
#define MVNum 100                    //矩阵的最大空间为100*100
typedef char verTextType;            //顶点数据类型
typedef int ArcType;                //边的权值
typedef struct{
    verTextType vexs[MVNum];         //顶点集用一个数组表示
    ArcType arcs[MVNum][MVNum];      //边集用一个二维矩阵表示
    int vexnum, arcnum;              //图的顶点数,边数
}AMGraph;

int Location(AMGraph G, verTextType v) //顶点v在顶点集数组中的索引
{
    for(int i = 0; i < G.vexnum; i++)
        if(G.vexs[i] == v)
            return i;
    return -1;                        //顶点集中没有顶点v
}

void Create(AMGraph &G)
{
    cout << "输入顶点数: ";
    cin >> G.vexnum;
    cout << "输入边数: ";
    cin >> G.arcnum;

    cout << "输入全部的顶点: ";
    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] = maxValue;
    }

    verTextType Start, End;           //接收边的起点,接收边的终点

    for(int i = 0; i < G.arcnum; i++)
    {
        cout << "输入第" << i+1 << "条边的起点:";
        cin >> Start;

        cout << "输入第" << i+1 << "条边的终点:";
        cin >> End;

        int index1 = Location(G,Start);
        int index2 = Location(G,End); //利用location函数得到起点和终点在顶点数组中的位置

        cout << "输入第" << i+1 << "条边的权值:";
        cin >> G.arcs[index1][index2];   //利用上一步的的两个索引值确定边的位置
    }
}

void TestFun(AMGraph G)                 //测试create函数
{
    cout<<"邻接矩阵如下:" << endl;

    for(int i = 0; i < G.vexnum; i++)
    {
        for(int j = 0; j < G.vexnum; j++)
            cout << G.arcs[i][j] << " ";
        cout << endl;
    }
}

int main()
{
    AMGraph* P1 = new AMGraph;
    Create(*P1);
    TestFun(*P1);

    return 0;
}

二、图的邻接表存储 ALGraph 

/*图有向图的邻接表存储*/

#define MVnum 100               //最大顶点数
typedef char 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;

int Location(ALGraph G, VerTexType v)  //确定顶点v在顶点集数组中的索引
{
    for(int i = 0; i < G.vexnum; i++)
        if( G.vertices[i].data == v )
            return i;
    return -1;
}

void Create(ALGraph &G)
{
    cout << "输入顶点个数: ";
    cin >> G.vexnum;

    cout << "输入边的条数: ";
    cin >> G.arcnum;

    cout << "输入全部顶点: ";
    for(int i = 0; i < G.vexnum; i++)
    {
        cin >> G.vertices[i].data;
        G.vertices[i].firstarc = NULL; //初始化顶点指向的第一条边
    }

    for(int j = 0; j < G.arcnum; j++)
    {
        VerTexType Start, End;

        cout << "输入第" << j+1 << "条边的起点:";
        cin >> Start;

        cout << "输入第" << j+1 << "条边的终点:";
        cin >> End;

        int index1 = Location(G, Start);  //得到起点的位置
        int index2 = Location(G, End);    //得到终点的位置


        ArcNode* new_arc = new ArcNode; //为这条边申请一个节点空间

        cout << "输入第" << j+1 << "条边的权值:";
        cin >> new_arc->info;

        new_arc->adjvex = index2;       //存储终点的位置(索引)

        new_arc->nextarc = G.vertices[index1].firstarc; //利用尾插法,将该结点插入起点后面
        G.vertices[index1].firstarc = new_arc;
    }
}

void TestFun(ALGraph G)
{
    cout << "邻接矩阵如下:" << endl;
    for(int i = 0; i < G.vexnum; i++)
        {
            cout << i << " " << G.vertices[i].data << "->";
            ArcNode * p = G.vertices[i].firstarc;

            while(p)
            {
                cout << p->adjvex << "(终点)" << p->info << "(权值)" << "->";
                p = p->nextarc;
            }
            cout << endl;
        }
}

int main()
{
    ALGraph* P2 = new ALGraph;
    Create(*P2);
    TestFun(*P2);

    return 0;
}

三、图的深度优先遍历(AMGraph) 


/*图的深度优先遍历*/

bool visited[MVNum];                         //用来记录顶点是否已被访问

void DFS_connected(AMGraph G, int v)        //深度优先遍历邻接矩阵存储的连通图,v为遍历的起点的位置
{
    cout << G.vexs[v] << " ";                // 起点最先被访问,输出起点
    visited[v] = true;

    for(int w = 0; w < G.vexnum; w++)       //设计递归算法:找到未被访问的以V为起点,w为终点的边,并将w作为下一次操作的起点
        if((G.arcs[v][w] != maxValue) && (!visited[w]))
            DFS_connected(G,w);
}

void DFS(AMGraph G)      //深度优先遍历邻接矩阵存储的非连通图
{
    for(int m = 0; m < G.vexnum; m++)       //初始化数组
        visited[m] = false;
    for(int m = 0; m < G.vexnum; m++)
        if(!visited[m])
            DFS_connected(G,m);     //在每个"划分"里调用DFS_connected函数,默认从第一个顶点开始遍历
}

int main()
{
    AMGraph* P1 = new AMGraph;
    Create(*P1);
    cout << "深度优先遍历顺序:";
    DFS(*P1);

    return 0;
}

 三、图的深度优先遍历(ALGraph)


#define MVnum 100
bool visited[MVnum];
void DFS_connected(ALGraph G, int v)             //邻接表存储的连通图
{
    cout << G.vertices[v].data << " "; //输出顶点
    visited[v] = true;
    ArcNode *p = G.vertices[v].firstarc;
    while(p != NULL)
    {
        int w = p->adjvex;
        if(!visited[w])
            DFS_connected(G,w);
        p = p->nextarc;
    }
}


void DFS(ALGraph G)
{
    for(int v = 0; v < G.vexnum; ++v)
        visited[v] = false;
    for(int v = 0; v < G.vexnum; ++v)   //遍历的起点为输入的第一个顶点
        if(!visited[v])
            DFS_connected(G, v);
}

int main()
{
    ALGraph* P2 = new ALGraph;
    Create(*P2);
    TestFun(*P2);
    DFS(*P2);

    return 0;
}

 四、图的广度优先遍历(AMGraph)

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


#define maxValue 999                 //表示正无穷
#define MVNum 100                    //矩阵的最大空间为100*100
typedef char verTextType;            //顶点数据类型
typedef int ArcType;                //边的权值
typedef struct{
    verTextType vexs[MVNum];         //顶点集用一个数组表示
    ArcType arcs[MVNum][MVNum];      //边集用一个二维矩阵表示
    int vexnum, arcnum;              //图的顶点数,边数
}AMGraph;

int Location(AMGraph G, verTextType v) //顶点v在顶点集数组中的索引
{
    for(int i = 0; i < G.vexnum; i++)
        if(G.vexs[i] == v)
            return i;
    return -1;                        //顶点集中没有顶点v
}

void Create(AMGraph &G)
{
    cout << "输入顶点数: ";
    cin >> G.vexnum;
    cout << "输入边数: ";
    cin >> G.arcnum;

    cout << "输入全部的顶点: ";
    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] = maxValue;
    }

    verTextType Start, End;           //接收边的起点,接收边的终点

    for(int i = 0; i < G.arcnum; i++)
    {
        cout << "输入第" << i+1 << "条边的起点:";
        cin >> Start;

        cout << "输入第" << i+1 << "条边的终点:";
        cin >> End;

        int index1 = Location(G,Start);
        int index2 = Location(G,End); //利用location函数得到起点和终点在顶点数组中的位置

        cout << "输入第" << i+1 << "条边的权值:";
        cin >> G.arcs[index1][index2];   //利用上一步的的两个索引值确定边的位置
    }
}


bool visited[MVNum];                          //该数组的大小为MVNum,用于AMGraph
int FirstAdjVex(AMGraph G,int u)
{
    for(int i = 0; i < G.vexnum; ++i)
        if(G.arcs[u][i] != maxValue)          //得到以u为起点的第一个未被访问的终点的位置
            return i;                        //返回u作为起点的边的第一个终点的位置,如果没有则返回-1
    return -1;
}

int NextAdjVex(AMGraph G,int u,int w)       //得到以u作为起点,w作为相邻的上一个终点的终点的位置
{
    for(int i = w+1 ; i < G.vexnum; ++i)
        if(G.arcs[u][i] != maxValue)        //得到w的下一个终点的位置,如果没有则返回-1
            return i;
    return -1;
}

void BFS_connected(AMGraph G,int v)        //广度优先遍历【邻接矩阵存储】的连通图,v表示遍历的起点的位置
{

    cout << "->" << G.vexs[v];             //输出起点
    visited[v] = true;
    queue<verTextType> Q;                  //利用队列按顺序存储访问点,类似于层序遍历; 使用该数据类型需要 #include <queue>
    Q.push(G.vexs[v]);                      //让起点入队
    while(!Q.empty())
    {
        int u = Location(G, Q.front());    //获取队头顶点的位置作为下一层遍历的起点,并让队头顶点出队
        Q.pop();

        for(int w = FirstAdjVex(G,u); w >= 0; w = NextAdjVex(G,u,w)) //依次输出以u(刚刚出队的原队头顶点)为起点的终点并让他们入队
        {
            if(!visited[w])
            {
                cout << "->" << G.vexs[w];
                visited[w] = true;
                Q.push(G.vexs[w]);
            }
        }
    }
}

void BFS(AMGraph G)                 //广度优先遍历【邻接矩阵存储】的【非连通图】
{
    for(int v = 0; v < G.vexnum; ++v)
        visited[v] = false;
    for(int v = 0; v < G.vexnum; ++v)
        if(!visited[v])
            BFS_connected(G, v);
}

int main()
{
    AMGraph* P1 = new AMGraph;
    Create(*P1);
    cout << "广度优先遍历:" << endl;
    BFS(*P1);

    return 0;
}

五、Dijkstra算法求图的最短路径(AMGraph)

/*对于邻接矩阵存储的图,使用Dijkstra算法求最短路径*/

void ShortestPath_DIJ(AMGraph G,int v0)
{
    int n = G.vexnum;
    bool S[n];                      //记录顶点是否访问
    int D[G.arcnum];                //记录权值
    int Path[G.vexnum];             //记录最短路径到该点的上一个顶点

    int ShowPath[G.vexnum];

    for(int v = 0; v < n; ++v)     //找到所有与v0连接的顶点
    {
        S[v] = false;
        D[v] = G.arcs[v0][v];

        if(D[v] < maxValue)
            Path[v] = v0;
        else
            Path[v] = -1;
    }

    S[v0] =  true;                 
    D[v0] = 0;                      

    for(int i = 1; i < n; ++i)     
    {
        int min = maxValue;         
        int v;

        for(int w = 0; w < n; ++w)
        {
            if(!S[w] && D[w] < min)
            {
                v = w;
                min = D[w];
            }
        }

        S[v] = true;               

        for(int w = 0; w < n; ++w)
            {
                if(!S[w] && (D[v] + G.arcs[v][w] < D[w])) 
                {
                    D[w] = D[v] + G.arcs[v][w];
                    Path[w] = v;
                }
            }
    }

    cout << "得到的最短路径表:" << endl;
    for(int i = 0; i < G.vexnum; i++)
    {
        if(Path[i] != -1)
            cout <<  G.vexs[i] << "的前一个点是"<< G.vexs[Path[i]] << endl;
        else
            cout << "起点和" << G.vexs[i] << "之间不存在最短路径" << endl;
    }
}

int main()
{
    AMGraph* P1 = new AMGraph;
    Create(*P1);
    TestFun(*P1);
    cout << "输入最短路径的起点:";
    verTextType v0;
    cin >> v0;
    ShortestPath_DIJ(*P1,Location(*P1, v0));

    return 0;
}

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
王道数据结构C是一种基于C语言数据结构实现的教材或参考书籍。该教材根据数据结构的原理与应用,详细介绍了常见的数据结构算法,并给出了它们的C语言实现。 在实现王道数据结构C时,我们可以通过以下几个步骤来进行: 1. 理解数据结构的原理和特性:首先,我们需要深入理解所学习的数据结构的基本原理和特性,包括线性表、链表、栈、队列、树、等。熟悉它们的操作规则以及适用的场景。 2. 设计算法数据结构:其次,针对每个数据结构,我们需要设计相应的算法数据结构,以满足各种操作和需求。对于线性表,我们可以选择使用顺序表或链表来实现,对于树结构,可以选择二叉树或多叉树等等。 3. 编写C语言代码实现:一旦我们设计好了算法数据结构,我们可以使用C语言实现它们。根据数据结构的不同,可能会使用到C语言的指针、结构体、递归等特性来完成实现。 4. 测试和验证:完成代码实现后,我们需要编写一些测试用例来验证代码的正确性和性能。通过不同的测试用例,我们可以检查代码是否满足预期的需求,并且确认代码的运行效率。 5. 优化和修改:在测试过程中,我们可能会发现一些代码的问题或者可以进一步优化的地方。在保证代码正确性的前提下,我们可以对代码进行优化,提高其运行效率和性能。 通过上述步骤,我们可以实现王道数据结构C。通过编写和理解代码,我们可以更深入地学习和理解数据结构的原理和应用,提高自己的编程能力和解决问题的能力。同时,也可以帮助我们更好地理解和掌握C语言的使用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值