比较无聊的一个东西:用数据结构的内容整合成的一个程序900多行代码.

本文深入探讨了数据结构中的图论概念,包括图的多种表示方法如邻接矩阵和邻接表,以及图的遍历算法如深度优先搜索和广度优先搜索。此外,还介绍了最小生成树算法(普里姆算法和克鲁斯卡尔算法)和最短路径算法(迪杰斯特拉算法和弗洛伊德算法),并通过示例代码详细解释了这些算法的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//这个是学数据结构是学完后做的一个终结.

#include<stdio.h>

#include<stdlib.h>
#include<string.h>
#define DEGREE 5 //树的高度
#define QUEUESIZE 10
#define MAX_NODE_NUM 100
#define INF 23764
#define TRUE  10
#define FALSE 0 
#define MAX 20
#define ERROR  0
#define OK  1
 
typedef enum{Link, Thread} PointerTag;      //link = 0表示指向左右孩子指针
                                            //Thread = 1表示指向前驱或后继的线索
int visited[MAX];
                                    //图的邻接链表定义 
typedef struct arcbox
{
int tailvex;//其值表示为于当前接点链接的图的另一个顶点数据,我们可以在此结构体中添加其它数据,以表示在建立
//           的图中的数据其它增加方面 
struct arcbox *hlink;//其表示为于数据图中一个节点链接的其它节点数据,我们要是将其建立成为链表型的,可以使数
//                    据更加,具有可读性,其 
                   //hlink所指向的数据为节点链接的节点方向,我们只需访问第一个数据即可,在hlink中访问所有数据。 
}arcbox;
typedef struct vexnode
{
char ch;//其表示为当前我们所进行操作数据的名称 
arcbox *firstin;//其指向我们进行整理的数据中第一个顶点数据的位置 
}vexnode;
typedef struct
{
vexnode xlist[MAX];//表示建立的图数据的所有数据类型 
int vexnum,srcnum;//建立图数据中顶点的个数与链接边的个数 
}*olgraph,graph; 
                                   //图的邻接矩阵定
//所谓图数据的矩阵表示方式,其表示为在矩阵中我们初始定义的数据均为0,其表示在矩阵中纵横坐标代表的顶点是不相连的,
//而其他数据则表示的为是相连的。 
typedef struct 
{
char vex[10];//顶点数据名称 
int arcs[10][10];//矩阵数据的建立 
//  比如在此可以在进行 建立其他数据域,可以针对此图的特性进行其他的操作 
int vexnum,arcnum;//建立数据中的顶点个数,和其边个数 
}*mgraph,mg;




                                 //最小成树普里姆结构定义 
/*
1.
生成树一个连通图的生成树是它的极小连通子图,在n个顶点的情形下,有n-1条边。生成树是对连通图而言的,是连通图的极
小连通子图,包含图中的所有顶点,有且仅有n-1条边。非连通图的生成树则组成一个生成森林;若图中有n个顶点,m个连通分
量,则生成森林中有n-m条边。
2.
树的遍历相似,若从图中某顶点出发访遍图中每个顶点,且每个顶点仅访问一次,此过程称为图的遍历,(Traversing Graph)。
图的遍历算法是求解图的连通性问题、拓扑排序和求关键路径等算法的基础。图的遍历顺序有两种:深度优先搜索(DFS)和广
度优先搜索(BFS)。对每种搜索顺序,访问各顶点的顺序也不是唯一的。
3.
在一个无向连通图G中,其所有顶点和遍历该图经过的所有边所构成的子图G′称做图G的生成树。一个图可以有多个生成树,从
不同的顶点出发,采用不同的遍历顺序,遍历时所经过的边也就不同。
*/






//                             增加知识部分






/*在图论中,常常将树定义为一个无回路连通图。对于一个带权的无向连通图,其每个生成树所有边上的权值之和可能不同,我
们把所有边上权值之和最小的生成树称为图的最小生成树。求图的最小生成树有很多实际应用。例如,通讯线路铺设造价最优问
题就是一个最小生成树问题
*/ 
typedef struct
{
char adjvex,ldjvex;
int lowcost;
}closedg;
                                //最小成树克鲁斯卡尔算法结构定义 
typedef struct
{
int bigeht,end;
int score;
}treeedg;
                                     //普里姆成树结构体定义 
typedef struct st1//树节点的类型
{
        char data;//数据域,采用char星
        struct st1 *children[DEGREE];//指向孩子节点的指针域
}CTreeNode;
                                     //普里姆成树转换成二叉树的结构体定义 
typedef struct st2
{
        char data;//数据域
        PointerTag ltag;                        //左右标志
        PointerTag rtag;
        struct st2 *lchild,*rchild;//左右孩子节点的指针
}BTreeNode,*BiTree;
BiTree pre;
//树队列结构体类型
typedef struct nodeCTree
{
        CTreeNode *CTreeArray[MAX_NODE_NUM];//结构体指针数组,存放节点的地址
        //struct nodeCTree *next;
        int CTreeFront,CTreeRear;
}QueueCTree;
//二叉树队列结构类型
typedef struct nodeBTree
{
        BTreeNode *BTreeArray[MAX_NODE_NUM];//结构体指针数组,存放节点的地址
        //struct nodeBTree *next;
        int BTreeFront,BTreeRear;
}QueueBTree;


//初始化树队列
void initQueueCTree(QueueCTree *&q)
{
        q=(QueueCTree *)malloc(sizeof(QueueCTree));
        q->CTreeFront=q->CTreeRear=0;
}
//初始化二叉树队列
void initQueueBTree(QueueBTree *&q)
{
        q=(QueueBTree *)malloc(sizeof(QueueBTree));
        q->BTreeFront=q->BTreeRear=0;
}


//树队列元素入队
int addQueueCTree(QueueCTree *&q,CTreeNode *ctroot)
{
        if((q->CTreeRear+1)%MAX_NODE_NUM==q->CTreeFront)//队满
                return 0;
        q->CTreeRear=(q->CTreeRear+1)%MAX_NODE_NUM;
        q->CTreeArray[q->CTreeRear]=ctroot;
        return 1;//入队列
}
//二叉树队列元素入队
int addQueueBTree(QueueBTree *&q,BTreeNode *btroot)
{
       
        if((q->BTreeRear+1)%MAX_NODE_NUM==q->BTreeFront)//队满
                return 0;
        q->BTreeRear=(q->BTreeRear+1)%MAX_NODE_NUM;
        q->BTreeArray[q->BTreeRear]=btroot;
        return 1;//入队列
}


//树的队列判空
int QueueCTreeEmpty(QueueCTree *q)
{
        return(q->CTreeFront==q->CTreeRear);
}
//二叉树队列判空
int QueueBTreeEmpty(QueueBTree *q)
{
        return(q->BTreeFront==q->BTreeRear);
}


//树队列元素出队
CTreeNode *delQueueCTree(QueueCTree *q)
{
        CTreeNode *ctroot;
        if(q->CTreeFront==q->CTreeRear)//队空
                return NULL;//返回空指针
        q->CTreeFront=(q->CTreeFront+1)%MAX_NODE_NUM;
        ctroot=q->CTreeArray[q->CTreeFront];
        return ctroot;//返回节点
}
//中序遍历进行中序线索化
void InThreading(BiTree p)
{
    if(p)
    {
        InThreading(p->lchild);              //递归左子树线索化
        if(!p->lchild)                       //没有左孩子
        {
            p->ltag = Thread;                //前驱线索
            p->lchild = pre;             //左孩子指针指向前驱,这里是第3步
        }
        else//                      在此中序线索二叉树树种我们针对于pre
//                         进行操作,将其运行在二叉树中在进行中序遍同时将在二叉树中针对于分别于根指针相连的两个节点查找出来
//                         其中一个是在左子树中其左孩子没有分支的一个节点,和其右子树中和其右子树没有孩子的分支,使整个二叉树可进行
//                         部分比较简单的递归型数据的运行。 
        p->ltag =Link; 
        if(!pre->rchild)                 //没有右孩子,进行查找上边所需要的数据 
        {
            pre->rtag = Thread;              //后继线索
            pre->rchild = p;             //前驱右孩子指针指向后继(当前结点p)
        }
        else
        p->rtag  =Link;
        pre = p;
        InThreading(p->rchild);              //递归右子树线索化
    }
}
//建立头结点,中序线索二叉树
int InOrderThread_Head(BiTree h, BiTree t)
{
    if(h == NULL)
    {
        return ERROR;
    }
    if(!t)      //如果为NULL,则证明此二叉树为空,不必进行线索化处理 
    {
        h->lchild = h;
        h->ltag = Link;
    }
    else         //针对其进行线索化处理 
    {
        pre = h;
        h->lchild = t;        //第一步
        h->ltag = Link;
        InThreading(t);         //找到最后一个结点
        pre->rchild = h;        //第四步
        pre->rtag = Thread;
        h->rchild = pre;      //第二步
    }

//                             遍历中序线索二叉树   
int InOrderThraverse_Thr(BiTree t)
{
    BiTree p;
    p = t->lchild;           //p指向根结点
    while(p != t)
    {
        while(p->ltag == Link)   //当ltag = 0时循环到中序序列的第一个结点
        {
            p = p->lchild;
        }
        printf("%c ", p->data);  //显示结点数据,可以更改为其他对结点的操作
        while(p->rtag == Thread && p->rchild != t)
        {
            p = p->rchild;
            printf("%c ", p->data);
        }
        p = p->rchild;           //p进入其右子树
    }
 
    return OK;
}
BTreeNode *delQueueBTree(QueueBTree *q)
{
        BTreeNode *btroot;
        if(q->BTreeFront==q->BTreeRear)//队空
                return NULL;//返回空指针
        q->BTreeFront=(q->BTreeFront+1)%MAX_NODE_NUM;
        btroot=q->BTreeArray[q->BTreeFront];
        return btroot;//返回节点
}
//                            中序输出二叉树,只需更改printf的位置即可,转化成为其类型的输出 
void Preorder(BTreeNode *T)
{
        if(T)
        {
                Preorder(T->lchild);
                printf("%c,",T->data);
                Preorder(T->rchild);
        }
}
//                              极品版将树转换成为二叉树,然后针对于二叉树进行其他操作 
void TreeToBTree(CTreeNode *ctroot,BTreeNode *&btroot)//树转化为二叉树ctroot指向树的根节点,btroot,指向二叉树的跟
{
        QueueCTree *VisitedCTreeNodes;
        QueueBTree *VisitedBTreeNodes;//辅助队列
        initQueueCTree(VisitedCTreeNodes);
        initQueueBTree(VisitedBTreeNodes);//初始化队列
        CTreeNode *ctnode;
        BTreeNode *btnode,*p,*LastSibling;
        int i;
        btroot=(BTreeNode *)malloc(sizeof(BTreeNode));//添加开辟内存空间语句
        btroot->data=ctroot->data;//树的根节点作为二叉树的根节点
        btroot->lchild=btroot->rchild=NULL;
       
       
        addQueueCTree(VisitedCTreeNodes,ctroot);//树的跟节点入队
       
        addQueueBTree(VisitedBTreeNodes,btroot);//二叉树的跟节点入队
               
        while(!QueueCTreeEmpty(VisitedCTreeNodes))
        {
                ctnode=delQueueCTree(VisitedCTreeNodes);//树节点出队
       
                btnode=delQueueBTree(VisitedBTreeNodes);//二叉树节点出队
       
                for(i=0;i<DEGREE;i++)//访问节点所有的孩子节点
                {
                        if(ctnode->children[i]==NULL)//孩子节点访问完毕
                                break;
                        p=(BTreeNode *)malloc(sizeof(BTreeNode));//分配二叉树节点
                        p->data=ctnode->children[i]->data;
               
                        p->lchild=p->rchild=NULL;
                        if(i==0)
                                btnode->lchild=p;//长子,作为父节点的做孩子
                        else
                                LastSibling->rchild=p;//作为上一个兄弟节点的右孩子
                        LastSibling=p;
                       
                        addQueueCTree(VisitedCTreeNodes,ctnode->children[i]);//树节点进队列
                        addQueueBTree(VisitedBTreeNodes,p);//二叉树节点进门队列
                }
               
        }
}
//建立链表型的有向图 不带权值的,其连接特性于链表相识,不过其表示的是针对一个顶点数据我们知道数据的名称,然后在是对此数据进行链接,其指向的
//一个链表,表示的是链表中所有的数据顶点均是于我们所已知数据顶点相连的数据,然后我们在针对其进行操作,比如进行,查找器 最短路劲等等一系列的
//操作,然后再是针对于我们建立的图进行遍历的操作,分别是深度和广度遍历 
void greatege(olgraph g)
{
arcbox *p;
int i,j,k;
printf("请输入当前图的顶点数和其弧数\n");
scanf("%d %d",&(g->vexnum ),&(g->srcnum ));
rewind(stdin);
printf("请输入每个顶点的名称\n");
for(i=0;i<g->vexnum ;i++)
{
scanf("%c",&(g->xlist [i].ch));
g->xlist [i].firstin=NULL;
rewind(stdin);//清除数据的缓冲域,以防止数据的冲突,这也是在下边,进行其他数据操作所必要的函数 
}
for(k=0;k<g->srcnum ;k++)
{
printf("请输入第%d个弧的起点和终点名称\n",k+1);
scanf("%d %d",&i,&j);
p=(arcbox *)malloc(sizeof(arcbox));
p->tailvex =j;
p->hlink =g->xlist [i].firstin;//首先让当前节点的指向指针位置赋予新建连接节点的指向位置,然后在下边,对当前节点的指针指向重新赋予指向位置 
g->xlist [i].firstin=p;//也就是建立好的数据指针指向位置,这样就可以避免重复的对数据进行查找一直找到空指针位置,再进行插入 
rewind(stdin);
}
}
//建立无相图,不带权值型,其基本操作与上边的有向图一致,就是在要针对于两天同时进行连接 
void greatege1(olgraph g)
{
arcbox *p,*q;
int i,j,k;
printf("请输入当前图的顶点数和其弧数\n");
scanf("%d %d",&(g->vexnum ),&(g->srcnum ));
rewind(stdin);
printf("请输入每个顶点的名称\n");
for(i=0;i<g->vexnum ;i++)
{
scanf("%c",&(g->xlist [i].ch));
g->xlist [i].firstin=NULL;
rewind(stdin);
}
for(k=0;k<g->srcnum ;k++)
{
printf("请输入第%d个弧的起点和终点名称\n",k+1);
scanf("%d %d",&i,&j);
p=(arcbox *)malloc(sizeof(arcbox));
p->tailvex =j;
p->hlink =g->xlist [i].firstin;
g->xlist [i].firstin=p;
q=(arcbox *)malloc(sizeof(arcbox));
q->tailvex =i;
q->hlink =g->xlist [j].firstin;
g->xlist [j].firstin=q;
rewind(stdin);
}
}
//矩阵型有向图,带权值,而针对于矩阵中的数据存在我们进行的是将图中的数据运用,坐标表示出来更加简单便捷 
void creatmgraph(mgraph g)
{
int i,j,k=0,weight;
printf("请输入顶点数和边数.\n");
scanf("%d%d",&(g->vexnum  ),&(g->arcnum  ));
rewind(stdin);
printf("初始化矩阵数据.\n");
printf("请输入顶点数据:\n");
for(i=0;i<g->vexnum ;i++)
{
scanf("%c",&g->vex [i]);
   rewind(stdin);
}
for(i=0;i<g->vexnum;i++)
for(i=0;i<g->vexnum ;i++)
{
for(j=0;j<g->vexnum  ;j++)
g->arcs [i][j]=INF;

printf("请输入各顶点之间的关系,且输入其路径的权值:\n");
while(g->arcnum --)
{
printf("请输入第%d个关系\n",++k);
scanf("%d %d %d",&i,&j,&weight);
g->arcs [i][j]=weight;
rewind(stdin);
}
}
//矩阵型无向图,有权值,相对于我们上边进行的链表的存在而言这个则更加快捷,但是我觉得还是可以像我们在链表型图进行的其操作一样 
//不过是在表达上发生了变化 
void creatmgraph1(mgraph g)
{
int i,j,k=0,weight;
printf("请输入顶点数和边数.\n");
scanf("%d%d",&(g->vexnum  ),&(g->arcnum  ));
rewind(stdin);
printf("初始化矩阵数据.\n");
printf("请输入顶点数据:\n");
for(i=0;i<g->vexnum ;i++)
{
scanf("%c",&g->vex [i]);
   rewind(stdin);
}
for(i=0;i<g->vexnum;i++)
for(i=0;i<g->vexnum ;i++)
{
for(j=0;j<g->vexnum  ;j++)
g->arcs [i][j]=INF;

printf("请输入各顶点之间的关系,且输入其路径的权值:\n");
while(g->arcnum --)
{
printf("请输入第%d个关系\n",++k);
scanf("%d %d %d",&i,&j,&weight);
g->arcs [i][j]=weight;
g->arcs [j][i]=weight;
rewind(stdin);
}
}
//链表图的深度优先遍历,针对于图的深度和广度优先遍历的函数还未完全建立成功,所以现在先针对其进行介绍然后在对其进行操作,不过好像是应为
//建立的图的结构体的数据类型不是一样的,所以在表示上有点差异,所以无法进行对其完整型的操作。
/*
  我们针对进行深度和广度优先遍历是为了进行数据的查找所以在遍历时针对数据进行采用,防止重复遍历,于是就建立一个辅助数组进行操作 
  
  
  1.假设初始状态是图中所有顶点都未曾被访问,则深度优先遍历搜索可以从图中的任意 一个顶点V出发,访问此顶点,然后依次从V的未被访问的邻接顶点
  出发进行深度优先遍历全图,直至图中所有和V有路径想通的顶点都被访问到;若此图尚有顶点未被访问,则另选图中一个未曾被访问的顶点做为起始点,重复
  上述操作,直至图中所有顶点都被访问到为止,这就是深度优先遍历。 
  
  
   2.假设从图中某顶点v开始出发,在访问了v之后一次访问v的各个未曾访问的邻接点,然后从中这些邻接点出发依次访问他们的邻接点,并是“先被访问的顶点的邻接点”
   先于“后被访问的顶点邻接点”被访问,直到途中使用已被访问的顶点的邻接点都被访问到。若图宏有顶点未被访问,则重新选定节点进行上述操作,直到所有节点访问
   完全为止。
   
   这就是我们针对于图进行的查找的操作,还有就是我们可以将此图数据进行转换成二叉树数据,然后对二叉树进行数据排序,运用到红黑树,或者二叉平衡树原理,
   但是要对我们进行建立的二叉树排序树的,排序原理进行修改,重新建立排序规则,然后在对其进行整理运用,比如字母型的,或者数字型的。 
*/ 
int  DFS(olgraph g,int i)
{
arcbox  *p;
visited[i]=1;
p=g->xlist [i].firstin;
printf("%3c",g->xlist [i].ch);
while(p!=NULL)
{
   if(visited[p->tailvex ]==0)
      DFS(g,p->tailvex );
   p=p->hlink ;
}
}
/*
   //然后就是在图中没有建立成功的其它操作,如拓扑排序宏针对于链接通量的运用等等 
*/ 
//链表图的输出 
void greaget(olgraph g)
{

int i;
arcbox *p;
printf("顶点数据位:\n");
for(i=0;i<g->vexnum ;i++)
printf("%c  ",g->xlist [i].ch);
printf("\n");
for(i=0;i<g->vexnum ;i++)
{
p=g->xlist [i].firstin;
printf("其中%c的连接的有:",g->xlist [i].ch);
while(p!=NULL)
{
printf("(%c)",g->xlist [p->tailvex].ch );
p=p->hlink ;
}
printf("\n");
}

}
//图的输出方式的一种 (矩阵型) 
void arrayout(mgraph g) 
{
int i,j;
printf("则其顶点数据为:");
for(i=0;i<g->vexnum;i++)
printf("%3c",g->vex [i]);
for(i=0;i<g->vexnum ;i++)
{
for(j=0;j<g->vexnum ;j++)
   printf("%3d",g->arcs [i][j]);
   printf("/n");
}
}
//狄杰斯特拉算法
void  Dijkstra(mgraph g,int v0) 
{
int  p[10][10],d[10];
int i,j,v,w,min;
bool final[10];
for(v=0;v<g->vexnum ;v++)
{
final[v]=FALSE;
d[v]=g->arcs [v0][v];
for(w=0;w<g->vexnum ;w++)
p[v][w]=FALSE;
if(d[v]<INF)
{
p[v][v0]=TRUE;
p[v][v]=TRUE;
}
}
d[v]=0;
final[v0]=TRUE;
for(i=1;i<g->vexnum  ;i++)
{
min=INF;//在此我们针对于min进行赋予一个无穷大的值,以便判断在下边要进行的操作 
for(w=0;w<g->vexnum  ;w++)
if(!final[w])
if(d[w]<min)//针对于在矩阵中的图我们进行建立的模型,判断两点的路径是否为通路,若为通路,则进行将数据进行调换,让其最短路径的值
//          变成此时两点的直接路径值 
{
v=w;
min=d[w];
}
final[v]=TRUE;
for(w=0;w<g->vexnum;w++)
if(!final[w]&&(min+g->arcs [v][w]<d[w]))//d[w]中表示的从v0到w的直接的路径,arecs[v][w]从v到w的路径长度,然后加上min表示的是从其他路径测试的距离
//                                     然后与以前建立起来的数据进行整理对比,然后确定是否为正真的最短路劲数据 
{
d[w]=min+g->arcs [v][w];
for(j=0;j<g->vexnum ;j++)//若我们建立的路劲被替换掉是要进行将min进行修改,以便于在我们为查找完全的路径中继续查找未完成的路劲,直到所有与当
//                       前两个节点的有关的路径测试完毕为止 
p[w][j]=p[v][j];
p[w][w]=v;//在此for中应该是记录两点路径的大小和经过的数据,不过此推论还不够完善,要继续修改。 
}
}
printf("%d到的最短路径长度为 经过\n",v0);
for(i=1;i<g->vexnum ;i++)
{
printf("到%d的最短长度为%d:",i,d[i]);
printf("经过:");
for(j=0;j<g->vexnum;j++)
if(p[i][j])
if(p[i][j]!=10)
printf("%d\t",p[i][j]);
printf("\n");
}
}
//                        弗洛伊德求最短路径算法(未完成部分) 
void ShortestPath_FLOYD(mgraph g)
{
int v,w,u,i,j;
int d[10][10],p[10][10][10];
for(v=0;v<g->vexnum ;v++)
for(w=0;w<g->vexnum ;w++)
{
d[v][v]=0; 
d[v][w]=g->arcs [v][w];
for(u=0;u<g->vexnum ;u++)
p[v][w][u]=FALSE;
if(d[v][w]<INF)
{
p[v][w][v]=p[w][w][w]=TRUE;
}
}
for(u=0;u<g->vexnum ;u++)
for(v=0;v<g->vexnum ;v++)
if(d[v][u]<INF)
for(w=0;w<g->vexnum ;w++)
if(d[v][u]+d[u][w]<d[v][w])
{
d[v][w]=d[v][u]+d[u][w];
for(i=0;i<g->vexnum ;i++)
p[v][w][i]=(p[v][u][i]||p[u][w][i]);
}
for(i=0;i<g->vexnum ;i++)
{
   for(j=0;j<g->vexnum ;j++)
   if(d[i][j]==0)
   {
    if(i!=j)
    printf("从%c到%c此路径不存在\n",g->vex [i],g->vex [j]);
}
else
   {
  printf("从%c到%c的最短长度为%d:",g->vex [i],g->vex [j],d[i][j]);
  printf("经过:");
  for(w=0;w<g->vexnum ;w++)
  if(p[i][j][w])
  printf("%c\t",g->vex [w]);
  printf("%c\t",g->vex [j]);
  printf("\n");
  }
}
}
//                       在最小成树运用到的部分,其表示为将数据进行求小部分 
void min(closedg edg[],int &min)
{
int i;
for(i=0;i<10;i++)
if(edg[i].lowcost!=0)
{
min=i;
   for(i=0;i<10;i++)
   if(edg[i].lowcost !=0&&edg[i].lowcost <edg[min].lowcost )
   min=i;
}
}
//                                  普利姆最小成树(有向图)
/*
                                   其构造思想
算法的基本思想:
普里姆算法的基本思想:普里姆算法是另一种构造最小生成树的算法,它是按逐个将顶点连通的方式来构造最小生成树的。
从连通网络N = { V, E }中的某一顶点u0出发,选择与它关联的具有最小权值的边(u0, v),将其顶点加入到生成树的顶点
集合U中。以后每一步从一个顶点在U中,而另一个顶点不在U中的各条边中选择权值最小的边(u, v),把该边加入到生成树的边
集TE中,把它的顶点加入到集合U中。如此重复执行,直到网络中的所有顶点都加入到生成树顶点集合U中为止。
假设G=(V,E)是一个具有n个顶点的带权无向连通图,T(U,TE)是G的最小生成树,其中U是T的顶点集,TE是T的边集,则构造G的最小生成树T的步骤如下:
(1)初始状态,TE为空,U={v0},v0∈V;
(2)在所有u∈U,v∈V-U的边(u,v)∈E中找一条代价最小的边(u′,v′)并入TE,同时将v′并入U;
重复执行步骤(2)n-1次,直到U=V为止 
*/ 
void primtree(mgraph g)
{
int i,j,k,l;
printf("请输入你需要构建树的顶点:/n");
scanf("%d",&i);
closedg edg[10],egd[10];
for(j=0;j<10;j++)
if(j!=i)
{
edg[j].ldjvex =g->vex [j]; 
edg[j].adjvex =g->vex [i];
edg[j].lowcost =g->arcs [i][j];
}
edg[i].lowcost=0;
for(l=0;l<g->vexnum -1 ;l++)
{
min(edg,k);
egd[l]=egd[k];
printf("%c %c %d\n",edg[k].adjvex ,edg[k].ldjvex,edg[k].lowcost );
edg[k].lowcost =0;
for(j=0;j<g->vexnum ;j++)
if(g->arcs [k][j]<edg[j].lowcost )
{
edg[j].lowcost =g->arcs [k][j];
edg[j].adjvex =g->vex [k];
edg[j].ldjvex =g->vex [j];
}
}
}
void sort(mgraph g,treeedg  edg[])
{
int i,j,k=0,p;
treeedg temp;
for(i=0;i<g->vexnum ;j++)
for(j=0;j<i;j++)
if(g->arcs[i][j]<INF)
{
edg[k].bigeht=i;
edg[k].end=j;
edg[k].score=g->arcs [i][j];
k++;

for(i=0;i<k-1;i++)
{
p=i;
for(j=i;j<k;j++)
if(edg[j].score<edg[p].score)
p=j;
if(p!=i)
{
temp=edg[i];
edg[i]=edg[p];
edg[p]=temp;
}
}
}
//                           克鲁斯卡尔最小成树 (有向图)  
void kruskal(treeedg edg[],treeedg tree[],int n)
{
int v=0,j,k,sum=0;
int cnvx[MAX];
for(j=0;j<n;j++)
cnvx[j]=j;
for(k=0;k<n-1;k++)//更改部分 
{
if(cnvx[edg[v].bigeht]==0&&cnvx[edg[v].end]==0)//针对这我采用的是将数据宏我们使用过的顶点数据进行重置,如当这个顶点作为我们建立的树中的
//          起始点存在时将其代表起点数据的使用性转换成为0,这样我们在下次使用时判断是否可以当做起点使用,就可以判断是否为0即可,而尾同样
//         如此其应该不书上的简单些 
v++;
else
{
tree[k]=edg[v];
   sum+=edg[v].score;
    cnvx[edg[v].end]=0;
    cnvx[edg[v].bigeht]=0; 
    v++;
}
}
printf("最小成树如下所述:/n起点/t终点/t权值/n");
for(j=0;j<n-1;j++)
{
printf("%d/t%d/t%d",tree[j].bigeht,tree[j].end,tree[j].score);
printf("最小成数的权值和为:%d",sum);
}
}
CTreeNode *SearchCTree(CTreeNode *root ,char data)
{
        int i;
        CTreeNode *returnNode;
        if(root->data==data)
                return root;
        else
        {
                for(i=0;i<DEGREE;i++)
                {
                        if(root->children[i]==NULL)
                        {
                        return NULL;//returnNode->data =data;                     return returnNode; 
}
                        else
                        {
                                returnNode=SearchCTree(root->children[i],data);//递归查找
                                if(returnNode!=NULL)
                                    {
                                  return returnNode;//returnNode->data =data;     return returnNode;
}
                        }
                }
        }
}
//                                     普利姆最小成树无向图部分,不过要配合上面的将树转换成二叉树进行综合使用 
void primtree1(mgraph g,CTreeNode *&root)
{
int i,j,k,l,n,m;
    char data, parent;
    closedg edg[10],egd[10];
    CTreeNode *parentNode,*node;
    n=g->vexnum  -1;
    if(n==0)
    printf("为空树\n") ;
printf("请输入你需要构建树的顶点:/n");
scanf("%d",&i);
fflush(stdin);
    root=(CTreeNode *)malloc(sizeof(CTreeNode));
    root->data=g->vex [i];
    for(j=0;j<DEGREE;j++)
root->children[j]=NULL;
for(j=0;j<10;j++)
if(j!=i)
{
edg[j].ldjvex =g->vex [j]; 
edg[j].adjvex =g->vex [i];
edg[j].lowcost =g->arcs [i][j];
}
edg[i].lowcost=0;
for(l=0;l<g->vexnum -1 ;l++)
{
min(edg,k);
egd[l]=egd[k];
node=(CTreeNode *)malloc(sizeof(CTreeNode));
        node->data=edg[k].ldjvex;
        for(m=0;m<DEGREE;m++)
        node->children[m]=NULL;
        parentNode=SearchCTree(root,edg[k].adjvex);
        for(m=0;m<DEGREE;m++)
        {
            if(parentNode->children[m]==NULL)
            {
                parentNode->children[m]=node;
                break;
            }
        }
printf("%c %c %d\n",edg[k].adjvex ,edg[k].ldjvex,edg[k].lowcost );
edg[k].lowcost =0;
for(j=0;j<g->vexnum  ;j++)
if(g->arcs [k][j]<edg[j].lowcost )
{
edg[j].lowcost =g->arcs [k][j];
edg[j].adjvex =g->vex [k];
edg[j].ldjvex =g->vex [j];
}
}
}
//
void preorderTree(CTreeNode *ctroot)//遍历每个节点的操作就是输出该节点的data域
{
        CTreeNode *ctchild;
        int i;
        printf("%c",ctroot->data);//先遍历根节点
        for(i=0;i<DEGREE;i++)//依次先序遍历孩子节点
        {
                ctchild=ctroot->children[i];
                if(ctchild==NULL)
                        break;//孩子节点遍历结束,退出
                else
                        preorderTree(ctchild);//递归先序遍历
        }
}


int main()
{
int i,j,k;
olgraph g,g1;
g1=g=(olgraph )malloc(sizeof(graph));
mgraph G,G1;
G1=G=(mgraph )malloc(sizeof(mg));
while(1)
{
   printf("\n\t                         图的建立                                 ");
        printf("\n\t******************************************************************");
        printf("\n\t*          1-----创建有向图的邻接表                              *");
        printf("\n\t*          2-----创建有向图的邻接矩阵                            *");
        printf("\n\t*          3-----创建无向图的邻接表                              *");  
   printf("\n\t*          4-----创建无向图的邻接矩阵                            *");
        printf("\n\t*          0-----结束                                            *");
        printf("\n\t******************************************************************");
        printf("\n\t   选择菜单序号(0--4):");
        scanf("%d",&i);
        rewind(stdin);
        switch(i)
        {
        case 1: 
{
greatege(g);
printf("\n\t                         图的遍历                                 ");
                printf("\n\t******************************************************************");
                printf("\n\t*          1-----有向图的深度遍历                                *");
                printf("\n\t*          2-----有向图的广度遍历                                *");
                printf("\n\t******************************************************************");
                printf("\n\t   选择菜单序号(0--2):");
                scanf("%d",&i) ;
                rewind(stdin);
                switch(i)
                {
                case 1:
{
printf("输出所建立图的数据:\n");
                      greaget(g);
                      printf("深度优先遍历:请输入遍历开始的顶点\n");
                      scanf("%d",&i);
                    DFS(g,i);
                    rewind(stdin);
}break; 
case 2:
{
printf("抱歉正在整合中暂无资源/n");
}break;
}
}break;
        case 2: 
{
greatege1(g1);
printf("\n\t                         图的遍历                                 ");
                printf("\n\t******************************************************************");
                printf("\n\t*          1-----无向图的深度遍历                                *");
                printf("\n\t*          2-----无向图的广度遍历                                *");
                printf("\n\t******************************************************************");
                printf("\n\t   选择菜单序号(0--2):");
                scanf("%d",&i) ;
                rewind(stdin);
                switch(i)
                {
                case 1:
{
                      printf("深度优先遍历:请输入遍历开始的顶点\n");
                      scanf("%d",&i);
                    DFS(g1,i);
                    rewind(stdin);
}break; 
case 2:
{
printf("抱歉正在整合中暂无资源/n");
}break;
case 0:  exit(0);
}
}break;
        case 3: 
{
int a,b;
creatmgraph (G);
printf("是否输出图内数据(1,0)?");
scanf("%d",&a);
if(a)
arrayout(G);
printf("\n\t           现在我们开始对无向进行操作图                           ");
                printf("\n\t******************************************************************");
                printf("\n\t*          1-----求单源顶点到所有顶点的最短路径(迪杰斯特拉算法)  *");
                printf("\n\t*          2-----求所有顶点到其他顶点的最短路径(弗洛伊德算法)    *");
                printf("\n\t******************************************************************");
                printf("\n\t   选择菜单序号(0--2):");
                scanf("%d",&i);
rewind(stdin);
switch(i)
{
case 1:
{
printf("请输入要建立的路径的起始顶点.\n");
                       scanf("%d",&b);
                       Dijkstra(G,b);
}break;
case 2:
{
printf("输出其内部数据/n");
ShortestPath_FLOYD(G);
}break;
case 0:  exit(0);

}break;
        case 4:
{
int a1,b1;
   creatmgraph1 (G1);
   printf("是否输出图内数据(1,0)?");
scanf("%d",&a1);
if(a1)
arrayout(G1);
printf("\n\t           现在我们开始对无向进行操作                             ");
                printf("\n\t******************************************************************");
                printf("\n\t*          1-----最小成树普里姆算法                              *");
                printf("\n\t*          2-----最小成树克鲁斯卡尔算法                          *");
                printf("\n\t******************************************************************");
                printf("\n\t   选择菜单序号(0--2):");
                scanf("%d",&b1);
                rewind(stdin);
                switch(b1)
                {
                case 1:
                {
                CTreeNode *Tree;
                BTreeNode *BTree;
                BiTree temp;
                            temp =(BiTree)malloc(sizeof(BTreeNode));
                printf("开始普里姆算法\n");
                       primtree(G1);
                       printf("现在我们开始将普里姆算法构建成一颗真正的树。\n");
                       primtree1(G1,Tree);
printf("树的先序遍历结果为:\n");
preorderTree(Tree);
printf("现在我们将构建成的树转换成二叉树\n");
                       TreeToBTree(Tree,BTree);       
                            printf("转换后的二叉树,中序遍历的结果为:\n");
                            Preorder(BTree);
                            InOrderThread_Head(temp,BTree );       //加入头结点,并线索化
                            printf("输出中序线索二叉树的内容:\n");
                            InOrderThraverse_Thr(temp);
}break;
   case 2:
    {
    treeedg edg[MAX*MAX],tree[MAX] ;
    printf("开始克鲁斯卡尔算法(但是有漏洞)");
sort(G1,edg);
                       kruskal(edg,tree,G1->arcnum );
}break; 
case 0:  exit(0);
}
} break;
        case 0:  exit(0);
}
}
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值