数据结构实验三

图遍历生成树演示

程序的功能

通过对连通图和非连通图的遍历,可以访问图中全部结点。可以输出该图的邻接矩阵以及该图的邻接表,可以进行广度优先遍历或深度优先遍历生成树。可以实现删除一个结点的操作。

输入的形式和输入值的范围:输入顶点个数以及边的个数,每条边的权值默认为1,每个都是整型变量,即int型变量。

输出的形式:

1.如果输出邻接矩阵,是等于顶点个数的行数与列数,如果权值不存在即输出0
2.如果输出的是邻接表,即用箭头指向,边表指向与顶点存在边的顶点
3.广度与深度优先输出的是一行整型数字,并且该整型数字为遍历生成树的先序遍历序列

测试数据:依照要求输入符合输入形式的顶点与边的个数,权值默认为1,对连通图和非连通图进行测试,分别进行深度优先和广度优先遍历和插入删除操作。

#include <stdio.h>
#include <stdlib.h>
#define MAX_VERtEX_NUM 20              //顶点的最大个数
#define VRType int                        //表示顶点之间的关系的变量类型
#define VertexType int                     //图中顶点的数据类型
#define InfoType char                     //存储弧或者边额外信息的指针变量类型
#define int_max  10000
#define max  20
typedef enum { false, true }bool;            //定义bool型常量
bool visited[MAX_VERtEX_NUM];        //设置全局数组,记录标记顶点是否被访问过
typedef struct {
    VRType adj;  //对于无权图,用 1 或 0 表示是否相邻;对于带权图,直接为权值。
    InfoType* info;                        //弧或边额外含有的信息指针
}ArcCell, AdjMatrix[MAX_VERtEX_NUM][MAX_VERtEX_NUM];
typedef struct {
    VertexType vexs[MAX_VERtEX_NUM];        //存储图中顶点数据
    AdjMatrix arcs;                         //二维数组,记录顶点之间的关系
    int vexnum, arcnum;                      //记录图的顶点数和弧(边)数
}MGraph;
typedef struct CSNode {//孩子兄弟表示法的链表结点结构
    VertexType data;
    struct CSNode* lchild;//孩子结点
    struct CSNode* nextsibling;//兄弟结点
}*CSTree, CSNode;//根据顶点本身数据,判断出顶点在二维数组中的位置
typedef struct Queue {
    CSTree data;//队列中存放的为树结点
    struct Queue* next;
}Queue;
int LocateVex(MGraph G, VertexType v) {//遍历一维数组,找到变量v,返回位置i
    int i = 0;
    for (; i < G.vexnum; i++) {
        if (G.vexs[i] == v) {
            break;
        }
    }//如果找不到,输出提示语句,返回-1
    if (i > G.vexnum) {
        printf("no such vertex.\n");
        return -1;
    }
    return i;
}//构造无向图
void CreateDN(MGraph* G) {
    int i = 0;
    printf(" ***********************************************\n");
    printf(" ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^ ^_^\n");
    printf(" ***********************************************\n");
    printf("  _____________________________________________ \n");
    printf("┃                                            ┃\n");
    printf("┃               创建无向图                   ┃\n");
    printf("┃____________________________________________┃\n");
    printf("************************************************\n");
    printf("请输入图G的顶点和弧的个数如:(4 4),但不包括()\n");
    scanf("%d %d", &(G->vexnum), &(G->arcnum));
    system("cls");
    printf(" ***********************************************\n");
    printf(" ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^ ^_^\n");
    printf(" ***********************************************\n");
    printf("  _____________________________________________ \n");
    printf("┃                                            ┃\n");
    printf("┃               正在创建无向图               ┃\n");
    printf("┃____________________________________________┃\n");
    printf("************************************************\n");
    for (i = 0;i < 20;i++)//初始化
    {
        if (i < G->vexnum)
            G->vexs[i] = i + 1;
        else
            G->vexs[i] = 0;
    }
    for (i = 0;i < G->vexnum;++i)
    {
        printf("按照您输入的顶点个数,已为您创建第%d顶点为 %d \n", i + 1, i + 1);
    }
    printf("按任意键继续");
    system("pause");
    system("cls");
    printf(" ***********************************************\n");
    printf(" ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^ ^_^\n");
    printf(" ***********************************************\n");
    printf("  _____________________________________________ \n");
    printf("┃                                            ┃\n");
    printf("┃               正在创建无向图               ┃\n");
    printf("┃____________________________________________┃\n");
    printf("************************************************\n");
    for (i = 0; i < G->vexnum; i++) {
        for (int j = 0; j < G->vexnum; j++) {
            G->arcs[i][j].adj = 0;
            G->arcs[i][j].info = NULL;
        }
    }
    for (i = 0; i < G->arcnum; i++) {//创建邻接矩阵
        int v1, v2;
       printf("输入第%d条边所依附的顶点如:(1 5),但不包括(),默认权值为1\n", i + 1);
        scanf("%d %d", &v1, &v2);
        int n = LocateVex(*G, v1);
        int m = LocateVex(*G, v2);
        if (m == -1 || n == -1) {
            printf("无此顶点\n");
            return;
        }
        G->arcs[n][m].adj = 1;
        G->arcs[m][n].adj = 1;//无向图的二阶矩阵沿主对角线对称
    }
    printf("创建邻接矩阵成功,按任意键继续");
    system("pause");
    system("cls");
}
int FirstAdjVex(MGraph G, int v)
{
    //查找与数组下标为v的顶点之间有边的顶点,返回它在数组中的下标
    for (int i = 0; i < G.vexnum; i++) {
        if (G.arcs[v][i].adj) {
            return i;
        }
    }
    return -1;
}
int NextAdjVex(MGraph G, int v, int w)
{
    //从前一个访问位置w的下一个位置开始,查找之间有边的顶点
    for (int i = w + 1; i < G.vexnum; i++) {
        if (G.arcs[v][i].adj) {
            return i;
        }
    }
    return -1;
}
//初始化队列
typedef struct arcnode//图的邻接表存储   弧结点
{
    int adjvex;//该弧指向的顶点的位置
    struct arcnode* nextarc;//弧尾相同的下一条弧
    char* info;//该弧信息
}arcnode;
typedef struct vnode//邻接链表顶点----头接点
{
    int data;//顶点信息
    arcnode* firstarc;//指向第一条依附该结点的弧的指针
}vnode, adjlist;
typedef struct algraph//邻接表的图的定义
{
    adjlist vertices[max];//邻接表
    int vexnum, arcnum;//图的顶点,弧数
    int kind;
}algraph;
void InitQueue(Queue** Q) {
    (*Q) = (Queue*)malloc(sizeof(Queue));
    (*Q)->next = NULL;
}
//结点v进队列
void EnQueue(Queue** Q, CSTree T) {
    Queue* element = (Queue*)malloc(sizeof(Queue));
    element->data = T;
    element->next = NULL;

    Queue* temp = (*Q);
    while (temp->next != NULL) {
        temp = temp->next;
    }
    temp->next = element;
}
//队头元素出队列
void DeQueue(Queue** Q, CSTree* u) {
    (*u) = (*Q)->next->data;
    (*Q)->next = (*Q)->next->next;
}
//判断队列是否为空
bool QueueEmpty(Queue* Q) {
    if (Q->next == NULL) {
        return true;
    }
    return false;
}
void ljjzprint(MGraph G)//输出邻接矩阵
{
    int i, j;
    for (i = 0;i < G.vexnum;i++)
    {
        for (j = 0;j < G.vexnum;j++)
        printf("%d   ", G.arcs[i][j].adj);
        printf("\n");
    }
}
//*************邻接表表示图*********************************
int creatadj(algraph* gra, MGraph G)//用邻接表存储图
{
    int i = 0, j = 0;
    arcnode* arc, * tem, * p;
    for (j = 0, i = 0;i < 20;i++)
    {
        if (G.vexs[i] != 0)
        {
            gra->vertices[j].data = G.vexs[i];
            gra->vertices[j].firstarc = NULL;//初始化邻接链表的表头指针   
            j++;
        }
    }
    for (i = 0;i < G.vexnum;i++)
    {
        for (j = 0;j < G.vexnum;j++)
        {
            if (gra->vertices[i].firstarc == NULL)
            {
                if (G.arcs[i][j].adj != 0 && j != G.vexnum)
                {
                    arc = (arcnode*)malloc(sizeof(arcnode));
                    arc->adjvex = j;
                    gra->vertices[i].firstarc = arc;
                    arc->nextarc = NULL;
                    p = arc;
                    ++j;
                    while (G.arcs[i][j].adj != 0 && j != G.vexnum)
                    {
                        tem = (arcnode*)malloc(sizeof(arcnode));
                        tem->adjvex = j;
                        gra->vertices[i].firstarc = tem;
                        tem->nextarc = arc;
                        arc = tem;
                        j++;
                    }
                    --j;
                }
            }
            else
            {
                if (G.arcs[i][j].adj != 0 && j != G.vexnum)
                {
                    arc = (arcnode*)malloc(sizeof(arcnode));
                    arc->adjvex = j;
                    p->nextarc = arc;
                    arc->nextarc = NULL;
                    p = arc;
                }
            }
        }
    }
    gra->vexnum = G.vexnum;
    gra->arcnum = G.arcnum;
    return 1;
}
//******************************************************
void adjprint(algraph gra)//输出邻接表
{
    int i, p1;
    for (i = 0;i < gra.vexnum;i++)
    {
        arcnode* p;
        printf("%d->", gra.vertices[i].data);
        p = gra.vertices[i].firstarc;
        while (p != NULL)
        {
            p1 = p->adjvex;
            if (p->nextarc != NULL)printf("%d->", gra.vertices[p1].data);
            else printf("%d", gra.vertices[p1].data);
            p = p->nextarc;
        }
        printf("\n");
    }
}
void BFSTree(MGraph G, int v, CSTree* T) {
    CSTree q = NULL;
    Queue* Q;
    InitQueue(&Q);
       EnQueue(&Q, (*T)); //根结点入队
        while (!QueueEmpty(Q)) {//当队列为空时,证明遍历完成
        bool first = true;
        DeQueue(&Q, &q);//队列首个结点出队
        int v = LocateVex(G, q->data); //判断结点中的数据在数组中的具体位置
        visited[v] = true;  //已经访问过的更改其标志位
        //遍历以出队结点为起始点的所有邻接点
        for (int w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w)) {
            //标志位为false,证明未遍历过
            if (!visited[w]) {
                //新建一个结点 p,存放当前遍历的顶点
                CSTree p = (CSTree)malloc(sizeof(CSNode));
                p->data = G.vexs[w];
                p->lchild = NULL;
                p->nextsibling = NULL;
                //当前结点入队
                EnQueue(&Q, p);
                //更改标志位
                visited[w] = true;
                //如果是出队顶点的第一个邻接点,设置p结点为其左孩子
                if (first) {
                    q->lchild = p;
                    first = false;
                }
                //否则设置其为兄弟结点
                else {
                    q->nextsibling = p;
                }
                q = p;
            }
        }
    }
}
//广度优先搜索生成森林并转化为二叉树
void BFSForest(MGraph G, CSTree* T) {
    (*T) = NULL;
    //每个顶点的标记为初始化为false
    for (int v = 0; v < G.vexnum; v++) {
        visited[v] = false;
    }
    CSTree q = NULL;
    //遍历图中所有的顶点
    for (int v = 0; v < G.vexnum; v++) {
        //如果该顶点的标记位为false,证明未访问过
        if (!(visited[v])) {
            //新建一个结点,表示该顶点
            CSTree p = (CSTree)malloc(sizeof(CSNode));
            p->data = G.vexs[v];
            p->lchild = NULL;
            p->nextsibling = NULL;
            //如果树未空,则该顶点作为树的树根
            if (!(*T)) {
                (*T) = p;
            }
            //该顶点作为树根的兄弟结点
            else {
                q->nextsibling = p;
            }
            //每次都要把q指针指向新的结点,为下次添加结点做铺垫
            q = p;
            //以该结点为起始点,构建广度优先生成树
            BFSTree(G, v, &p);
        }
    }
}
void DFSTree(MGraph G, int v, CSTree* T) {
    //将正在访问的该顶点的标志位设为true
    visited[v] = true;
    bool first = true;
    CSTree q = NULL;
    //依次遍历该顶点的所有邻接点
    for (int w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w)) {
        //如果该临界点标志位为false,说明还未访问
        if (!visited[w]) {
            //为该邻接点初始化为结点
            CSTree p = (CSTree)malloc(sizeof(CSNode));
            p->data = G.vexs[w];
    p->lchild = NULL;
            p->nextsibling = NULL;
        //该结点的第一个邻接点作为孩子结点,其它邻接点作为孩子结点的兄弟结点
            if (first) {
                (*T)->lchild = p;
                first = false;
            }
            else {//否则,为兄弟结点
                q->nextsibling = p;
            }
            q = p;
            //以当前访问的顶点为树根,继续访问其邻接点
            DFSTree(G, w, &q);
        }
    }
}
void DFSForest(MGraph G, CSTree* T) {//深度优先搜索生成森林并转化为二叉树
    (*T) = NULL;
    //每个顶点的标记为初始化为false
    for (int v = 0; v < G.vexnum; v++) {
        visited[v] = false;
    }
    CSTree q = NULL;
    //遍历每个顶点作为初始点,建立深度优先生成树
    for (int v = 0; v < G.vexnum; v++) {
        //如果该顶点的标记位为false,证明未访问过
        if (!(visited[v])) {
            //新建一个结点,表示该顶点
            CSTree p = (CSTree)malloc(sizeof(CSNode));
            p->data = G.vexs[v];
            p->lchild = NULL;
            p->nextsibling = NULL;
            //如果树未空,则该顶点作为树的树根
            if (!(*T)) {
                (*T) = p;
            }
            //该顶点作为树根的兄弟结点
            else {
                q->nextsibling = p;
            }
           //每次都要把q指针指向新的结点,为下次添加结点做铺垫
            q = p;
            //以该结点为起始点,构建深度优先生成树
            DFSTree(G, v, &p);
        }
    }
}
void PreOrderTraverse(CSTree T) {//前序遍历二叉树
    if (T) {
        printf("%d ", T->data);
        PreOrderTraverse(T->lchild);
        PreOrderTraverse(T->nextsibling);
    }
    return;
}
int deletedian(MGraph * G)//删除结点
{
    int v1, v2;
    int x, y, w, k, i, j, g1, g2, vex[20], m, i1;
    for (i = 0;i < 20;i++)
    {
        if (i < G->vexnum)
            vex[i] = i + 1;
        else
            vex[i] = 0;
    }
    printf("请输入你想删除的结点个数和删除结点后减少的弧的个数,例如:(2 3),不包括( )\n");
    scanf("%d %d", &x, &y);
    system("cls");
    g1 = G->vexnum;
    g2 = G->arcnum;
    G->vexnum = G->vexnum - x;
    G->arcnum = G->arcnum - y;
    for (w = 0;w < g1;w++)
    {
        printf("原来的的第%d顶点为 %d \n", w + 1, w + 1);
    }
    for (i = 0;i < x;i++)
    {
        printf("输入你想删除的顶点\n");
        scanf("%d", &m);
        vex[m - 1] = 0;
        for(j=0;j<g1-m;j++)
        G->vexs[m - 1] = G->vexs[m];
        for (i1 = m - 1;i1 < g1;i1++)
            for (j = 0;j < g1 - m;j++)
            G->vexs[m-1+j] = G->vexs[m+j];
        for (i1 = 0;i1 < g1;i1++)
            for (j = m - 1;j < g1;j++)
            {
                G->arcs[i1][j] = G->arcs[i1][j + 1];
            }
    }
    system("cls");
    for (w = 0, i = 0;i < 20;i++)
    {
        if (vex[w] != 0)
        {
            printf("现在的第%d顶点为 %d \n", i + 1, vex[w]);
            w++;
        }
        else
            w++;
    }
    printf("\n");
    printf("图G邻接矩阵删除点成功");
    return G->vexnum;
}
int main()
{
    system("color F0");
    MGraph G;//建立一个图的变量
    CreateDN(&G);//初始化图
    CSTree T;
    algraph gra;
    creatadj(&gra, G);
    int i, j, d, g[20][20];
    char a = 'a';
    printf(" ***********************************************\n");
    printf(" ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^ ^_^\n");
    printf(" ***********************************************\n");
    printf("  _____________________________________________ \n");
    printf("┃                                            ┃\n");
    printf("┃               图遍历生成树演示             ┃\n");
    printf("┃____________________________________________┃\n");
    printf("************************************************\n");
    printf("************************************************\n");
    printf("**            1.显示该图的邻接矩阵           ***\n");
    printf("************************************************\n");
    printf("**            2.显示该图的邻接表             ***\n");
    printf("************************************************\n");
    printf("**            3.广度优先遍历                 ***\n");
    printf("************************************************\n");
    printf("**            4.深度优先遍历                 ***\n");
    printf("************************************************\n");
    printf("**            5.删除一个结点                 ***\n");
    printf("************************************************\n");
    printf("^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^ ^_^ \n");
    printf("************************************************\n");
    int s, r, y = 1, c;
    char y2;
    while (y == 1)
    {
        printf("请输入你要选择的操作\n");
        scanf("%d", &s);
        switch (s)
        {
        case 1:
            system("cls");
            printf(" ***********************************************\n");
            printf("  _____________________________________________ \n");
            printf("┃                                            ┃\n");
            printf("┃               图遍历生成树演示             ┃\n");
            printf("┃____________________________________________┃\n");
            printf("************************************************\n");
            printf("**              邻接矩阵显示如下:            **\n");
            printf("************************************************\n");
            ljjzprint(G);
            break;
        case 2:
            system("cls");
            printf(" ***********************************************\n");
            printf("  _____________________________________________ \n");
            printf("┃                                            ┃\n");
            printf("┃               图遍历生成树演示             ┃\n");
            printf("┃____________________________________________┃\n");
            printf("************************************************\n");
            printf("**                邻接表显示如下:            **\n");
            printf("************************************************\n");
            adjprint(gra);
            break;
        case 3:
            system("cls");
            printf(" ***********************************************\n");
            printf("  _____________________________________________ \n");
            printf("┃                                            ┃\n");
            printf("┃               图遍历生成树演示             ┃\n");
            printf("┃____________________________________________┃\n");
            printf("************************************************\n");
            printf("**             广度优先遍历生成树如下:       **\n");
            printf("************************************************\n");
            BFSForest(G, &T);
            PreOrderTraverse(T);
            printf("\n");
            break;
        case 4:
            system("cls");
            printf(" ***********************************************\n");
            printf("  _____________________________________________ \n");
            printf("┃                                            ┃\n");
            printf("┃               图遍历生成树演示             ┃\n");
            printf("┃____________________________________________┃\n");
            printf("************************************************\n");
            printf("**             深度优先遍历生成树如下:       **\n");
            printf("************************************************\n");
            DFSForest(G, &T);
            PreOrderTraverse(T);
            printf("\n");
            break;
        case 5:
        {
                system("cls");
                system("cls");
                printf(" ***********************************************\n");
                printf("  _____________________________________________ \n");
                printf("┃                                            ┃\n");
                printf("┃               正在删除顶点                 ┃\n");
                printf("┃____________________________________________┃\n");
                printf("************************************************\n");
                d = deletedian(&G);
                creatadj(&gra, G);
                break;
        }
        default:break;
        }
        printf("\n是否继续?若继续请输入 1 否则输入 2 :\n");
        scanf("%d", &y);
        if (y == 2)
        break;
        else
        {
            system("cls");
            printf(" ***********************************************\n");
            printf(" ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^ ^_^\n");
            printf(" ***********************************************\n");
            printf("  ____________________________________________ \n");
            printf("┃                                            ┃\n");
            printf("┃               图遍历生成树演示             ┃\n");
            printf("┃____________________________________________┃\n");
            printf("***********************************************\n");
            printf("***********************************************\n");
            printf("**            1.显示该图的邻接矩阵           **\n");
            printf("***********************************************\n");
            printf("**            2.显示该图的邻接表             **\n");
            printf("***********************************************\n");
            printf("**            3.广度优先遍历                 **\n");
            printf("***********************************************\n");
            printf("**            4.深度优先遍历                 **\n");
            printf("***********************************************\n");
            printf("**            5.删除一个结点                 **\n");
            printf("***********************************************\n");
            printf("^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^ ^_^\n");
            printf("***********************************************\n");
        }
}}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值