1. 程式人生 > >有向圖鄰接表求入度,出度,刪除、增加頂點,弧,深度遍歷及其生成樹等

有向圖鄰接表求入度,出度,刪除、增加頂點,弧,深度遍歷及其生成樹等

#include "stdio.h"
#include "math.h"
#include"malloc.h"
#include "stack"
#include <queue>
#define OK 1
#define ERROR -1
#define MAX 32764 // 最大值∞
//#define MaxLen 1000 
#define  STACK_INIT_SIZE  100
#define  STACKINCREMENT  10
#define MAX_VERTEX_NUM 50 // 最大頂點個數
typedef enum {DG, DN, AG, AN} GraphKind; //{有向圖,有向網,無向圖,無向網}
typedef int status;
typedef int VRType;
typedef int InfoType;
typedef char VertexType;
typedef char TElemType;
typedef char QElemType;

/*--------------------圖的鄰接矩陣儲存表示---------------------*/
typedef struct ArcCell {
 VRType adj; // VRType是頂點關係型別。對無權圖,用1或0表示相鄰否;
 // 對帶權圖,則為權值型別。
 InfoType *info; // 該弧相關資訊的指標
}ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct{
 VertexType vexs[MAX_VERTEX_NUM]; // 頂點向量
 AdjMatrix arcs; // 鄰接矩陣
 int vexnum, arcnum; // 圖的當前頂點數和弧數
 GraphKind kind; // 圖的種類標誌
}MGraph;


/*------------------------圖的鄰接表儲存表示-----------------*/
typedef struct ArcNode {
 int weight;
 int adjvex; // 該弧所指向的頂點的位置
 struct ArcNode *nextarc; // 指向下一條弧的指標
 InfoType *info; // 該弧相關資訊的指標
}ArcNode;
typedef struct VNode {
 VertexType data; // 頂點資訊
 ArcNode *firstarc; // 指向第一條依附該頂點的弧
}VNode, AdjList[MAX_VERTEX_NUM];
typedef struct {
 AdjList vertices;
 int vexnum, arcnum; // 圖的當前頂點數和弧數
 GraphKind kind; // 圖的種類標誌
}ALGraph;


/*------------------------樹的孩子兄弟儲存表示-----------------*/
typedef struct CSNode{
 TElemType        data;
 struct CSNode    *firstchild,*nextsibling;
} CSNode, *CSTree;


/*------------------------佇列的儲存結構-------------------------*/
typedef  struct  QNode{
 QElemType  data;
 struct QNode *next;
} QNode, *QueuePtr;
typedef  struct  {
 QueuePtr   front;
 QueuePtr   rear;
} LinkQueue;


/*----------------------單鏈佇列的相關演算法-------------------------*/
//構造空佇列
status InitQueue(LinkQueue &Q){
 Q.rear=Q.front=(QueuePtr)malloc(sizeof(QNode));
    if(!Q.front)  return (OVERFLOW);
 Q.front->next=NULL;
    return OK;
}

//隊是否為空
bool QueueEmpty(LinkQueue Q){  
 if(!Q.front->next)
  return (true);
 return (false);
}

//入隊
status EQueue(LinkQueue &Q, QElemType e){ 
 QNode *p;
 p=(QNode *)malloc( sizeof(QNode));
 if (!p) return (OVERFLOW);
 p->data= e;
 p->next=NULL;
 Q.rear->next=p;
 Q.rear=p;
 return(OK);
}
//出隊
status DeQueue(LinkQueue &Q, QElemType &e){ 
 QNode *p;
 if(!Q.front)  return (OVERFLOW);
 p=Q.front->next;
    e=p->data;
 Q.front->next=p->next;
    if(Q.rear==p)  Q.rear=Q.front;
 free(p);
 return (OK);
}


/*--------------------------棧的基本操作-------------------------------------------*/
//棧的儲存結構
typedef char SElemType;
typedef struct {
    SElemType  *base; //棧底指標  
    SElemType   *top;  //棧頂指標
    int  stacksize;    //棧的大小
}SqStack;

//構造空棧
status InitStack (SqStack &S){  
 S.base=(SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType));
 if (!S.base)   return(OVERFLOW);
 S.stacksize = STACK_INIT_SIZE;
 S.top = S.base;
 return(OK);
}

//出棧
status Pop(SqStack &S, SElemType &e){
 if(S.base == S.top) return(ERROR);//棧空
 e=*--S.top;
 return(OK);
 
}

//入棧
status Push(SqStack &s,SElemType e)
{
 if(s.top-s.base>=s.stacksize)
  return OVERFLOW;
 *s.top++=e;
 return OK;
}

//銷燬棧
status DestroyStack(SqStack &S)
{
 
 S.top=NULL;
 S.base=NULL;
 delete[] S.base;
 S.stacksize=0;
 return OK;
}

//判斷棧是否為空
int EmptyStack(SqStack s)
{
 if(s.top==s.base) return 1;
 else          return 0;
}

//得到棧頂元素
status GetTop(SqStack &s,SElemType &e)
{
 if(s.top==s.base) return ERROR;
 e=*(s.top-1);
 return OK;
}

//棧的長度
int StackLength(SqStack s)
{
 return s.top-s.base;
}

//得到棧的所有元素值
status Get(SqStack s){
 int i,n;
 n=StackLength(s);
 if(!n) return ERROR;
 for(i=0;i<n;i++)
  printf("%c/t",*(s.base+i));
 return OK;
}

/*-----------------------建立有向圖的鄰接矩陣-----------------*/

//元素在圖中的位置
int locateMG(MGraph g,VertexType v){
 for(int i=0;i<g.vexnum;i++){
  if(g.vexs[i]==v)
   return i;
 }
 return -1;
}

//邊是否存在
status arcExist(MGraph g,int i,int j){
    if(g.arcs[i][j].adj==MAX)
        return 0;
  return 1;
 
}

//圖是否存在
int ExistM(MGraph g){
 if(g.vexnum<0){
  printf("圖不存在,請先建立圖/n");
  return 0;
 }
 return 1;
}
//建立有向圖的鄰接矩陣
status createMDG(MGraph &g){
 int i,j,k,n,l;
 VertexType v,v1,v2;
 printf("請輸入有向圖的頂點數:");
 scanf("%d",&g.vexnum);
 i=g.vexnum*(g.vexnum-1);
 printf("請輸入有向圖的弧數:");
 scanf("%d",&g.arcnum); 
 while(g.arcnum>i){
  printf("/n輸入有誤,邊數不能超過%d,請重新輸入!",i);
  printf("/n請輸入有向圖的弧數:");
  scanf("%d",&g.arcnum);
 }
 for(i=0;i<g.vexnum;i++)//初始化鄰接矩陣
  for(j=0;j<g.vexnum;j++)
   g.arcs[i][j].adj=MAX;
 printf("請依次輸入有向圖的各個頂點(用回車分隔):");
 for(i=0;i<g.vexnum;i++){//輸入頂點資訊
  getchar();
  scanf("%c",&v);
  l=locateMG(g,v);
  if(l>0){
   printf("輸入的頂點重複,請重新輸入/n");
   i--;
   continue;
  }
  g.vexs[i]=v;
 }
  for(k=1;k<=g.arcnum;k++){//構造鄰接矩陣
   getchar();
   printf("請輸入第%d條弧的起點與終點(用逗號分隔):",k);
   scanf("%c,%c",&v1,&v2);
   i=locateMG(g,v1);
   j=locateMG(g,v2);
   if(i<0||j<0||i==j||arcExist(g,i,j)){
    printf("輸入錯誤,請重新輸入/n");
    k--;
    continue;
   }
   printf("請輸入第%d條弧的權值:",k);
   scanf("%d",&n);
   g.arcs[i][j].adj=n;
  }
  printf("有向圖的鄰接矩陣建立成功/n");
  return OK;
}

/*---------------------建立有向圖的鄰接表--------------------*/

//元素在圖中的位置
int locateALG(ALGraph g,VertexType v){
 for(int i=0;i<g.vexnum;i++){
  if(g.vertices[i].data==v)
   return i;
 }
 return -1;
}

//當前有向圖中是否存在邊<i,j>
int GraphExist(ALGraph G,int i,int j){
 ArcNode *s;
 s=G.vertices[i].firstarc;
 while(s&&s->adjvex!=j)
  s=s->nextarc;
 if(s)   return 1;
 else    return 0;
}
//圖是否存在
int ExistG(ALGraph g){
 if(g.vexnum<0){
  printf("圖不存在,請先建立圖/n");
  return 0;
 }
 return 1;
}
status CreateADG(ALGraph &g){
 int i,j,k,l,n;
 ArcNode *p;
 VertexType v1,v2;
 char c;
 printf("請輸入有向圖的頂點數:");
 scanf("%d",&g.vexnum);
 while(g.vexnum>MAX_VERTEX_NUM){
  printf("/n輸入有誤,頂點數不能超過%d,請重新輸入!",MAX_VERTEX_NUM);
  printf("/n請輸入有向圖的頂點數:");
  scanf("%d",&g.vexnum);
 }
 i=g.vexnum*(g.vexnum-1);
 printf("請輸入有向圖的邊數:");
 scanf("%d",&g.arcnum); 
 while(g.arcnum>i){
  printf("/n輸入有誤,邊數不能超過%d,請重新輸入!",i);
  printf("/n請輸入有向圖的邊數:");
  scanf("%d",&g.arcnum);
 }
 printf("請依次輸入有向圖的各個頂點(用回車分隔):");
 for(i=0;i<g.vexnum;i++){//輸入頂點資訊
  getchar();
  scanf("%c",&c);
  l=locateALG(g,c);
  if(l>=0){
   printf("輸入的頂點重複,請重新輸入/n");
   i--;
   continue;
  }
  g.vertices[i].data=c;
  g.vertices[i].firstarc=NULL;
 }
 for(k=0;k<g.arcnum;k++){//輸入邊的資訊
  getchar();
  printf("請輸入第%d條弧的起點與終點(用逗號分隔):",k+1); 
        scanf("%c,%c",&v1,&v2);  
  i=locateALG(g,v1);
  j=locateALG(g,v2);
  if(i<0||j<0||i==j||GraphExist(g,i,j)){
   printf("輸入錯誤,請重新輸入/n");
   k--;
   continue;
  }
  p=(ArcNode*)malloc(sizeof(ArcNode));//建立結點
  if(!p) return ERROR;
  printf("請輸入第%d條弧的權值:",k+1);
  scanf("%d",&n);
  p->adjvex=j;
  p->nextarc=g.vertices[i].firstarc;//頂點i的連結串列
  g.vertices[i].firstarc=p;//新增到最左邊
  p->weight=n;
 }
 printf("有向圖的鄰接表建立成功/n");
 return OK;
}
/*------------------------------輸出圖的資訊-------------------*/
void printGra(ALGraph G){
 ArcNode *p;
 int i;
  printf("圖中有%d個頂點,%d條弧:/n",G.vexnum,G.arcnum);
  for(i=0;i<G.vexnum;i++){
   p=G.vertices[i].firstarc;
   printf("%c/t",G.vertices[i].data);
   while(p){
    printf("<%c,%c,%d>/t",G.vertices[i].data,G.vertices[p->adjvex].data,p->weight);
    p=p->nextarc;
   }
   printf("/n");
  }
}
void printMg(MGraph g){
 int i,j;
 for(i=0;i<g.vexnum;i++){
  printf("%c/t",g.vexs[i]);
  for(j=0;j<g.vexnum;j++)
  {
     if (g.arcs[i][j].adj!=MAX)
      printf("<%c,%c,%d>/t",g.vexs[i],g.vexs[j],g.arcs[i][j].adj);
  }
  printf("/n");
 }
}

/*--------------------鄰接表深度優先遍歷並判斷圖的連通性 -----------------*/

ArcNode *nextnode=NULL;//全域性變數
bool visited[21];//全域性變數

//得到i號頂點的第一個鄰接點
int FirstAdjVex(ALGraph g,int i){
 ArcNode *p;
 p=g.vertices[i].firstarc;
 if(!p) return -1;
 nextnode=p->nextarc;
 return(p->adjvex);
}

//得到i號頂點的下一個鄰接點
int NextAdjVex(ALGraph g,int i){
 if(!nextnode) return -1;
 int m=nextnode->adjvex;
 nextnode=nextnode->nextarc;
 return m;
}

//訪問圖中的i號頂點
void visitvex(ALGraph g,int i){
 printf("%c/t",g.vertices[i].data);
}

//從圖某個頂點進行深度優先遍歷
int DFS(ALGraph g,int i){
 int w;
 visited[i]=true;
 visitvex(g,i);
 for(w=FirstAdjVex(g,i);w>=0;w=NextAdjVex(g,i))
  if(!visited[w])  DFS(g,w);
  return OK;
}


//對圖進行深度優先遍歷
status DFSTraverse(ALGraph g){
 int v,u,x;
 int count[100];
 for(v=0;v<g.vexnum;v++){
  count[v]=0;
  printf("從%c開始深度優先遍歷的結果:",g.vertices[v].data);
  for(u=0;u<g.vexnum;u++)  visited[u]=false;
  for(x=v;x<g.vexnum+v;x++){
   int a;
   a=x;
   a=a%g.vexnum;
   if(!visited[a]){
    DFS(g,a);
    count[v]++;
   }
  }
  printf("/n");
 }
 int min;
 min=count[0];
 for(int i=0;i<g.vexnum;i++){
  if(min>count[i])
   min=count[i];
 }
 if(min!=1)
  printf("/n該有向圖是不連通圖!連通分量為:%d/n",min);
 else
  printf("/n該有向圖是連通圖!/n");
 return OK;
}

/*---------------------返回當前有向圖中的每個頂點的入度與出度----------------*/

//圖中某個頂點的入度
status InDegree(ALGraph G,int i){
 int j;
 int n=0;
 for(j=0;j<G.vexnum;j++){
  if(GraphExist(G,j,i)) n++;
    }
 return n;
}
//圖中某個頂點的出度
status OutDegree(ALGraph G,int i){
 ArcNode *p;
 int j=0;
 p=G.vertices[i].firstarc;
 while(p!=NULL){
  j++;
  p=p->nextarc;
 } 
 return j;
}

//每個頂點的與出度入度
void degree(ALGraph G){
 int i,n,m;
 char a;
 for(i=0;i<G.vexnum;i++){
  a=G.vertices[i].data;
  n=InDegree(G,i);
  m=OutDegree(G,i);
  printf("頂點%c的入度是%d,出度是%d/n",a,n,m);
    }  
}


/*-------------------------------當前有向圖插入弧-----------------------*/
int GraphAdd(ALGraph &G){
 int n,k,i,j,w;
 ArcNode *p;
    VertexType v1,v2;
 k=G.vexnum*(G.vexnum-1)-G.arcnum;
 printf("請輸入要增加的弧數:");
 scanf("%d",&n);
 while(n>k){
  printf("/n輸入有誤,增加的邊數不能超過%d,請重新輸入!",k);
  printf("/n請輸入有向圖的邊數:");
  scanf("%d",&n);
 }
 for(k=0;k<n;k++){
  getchar();
  printf("請輸入要增加的弧的起點與終點(用逗號分隔):"); 
  scanf("%c,%c",&v1,&v2);  
  i=locateALG(G,v1);
  j=locateALG(G,v2);
  if(i<0||j<0||i==j||GraphExist(G,i,j)){
   printf("輸入有誤,請重新輸入/n");
   k--;
   continue;
  }
  printf("請輸入第%d條弧的權值:",k+1);
  scanf("%d",&w);
  p=new ArcNode;  
  p->adjvex=j;
  p->weight=w;
  p->nextarc=G.vertices[i].firstarc;
  G.vertices[i].firstarc=p; 
  G.arcnum++;
  printf("插入弧成功/n");
 }
 return 1;
}

/*--------------------------當前有向圖中插入頂點-----------------------*/
int NodeAdd(ALGraph &G){
 int i,l,n;
 char c;  
 printf("請輸入要增加的頂點個數:");
 scanf("%d",&n);
 //增加的定點個數判斷
 if(G.vexnum+n>MAX_VERTEX_NUM){
  printf("輸入錯誤,最多有50個頂點/n");
  return ERROR;
 }
 for(i=0;i<n;i++){//輸入頂點資訊
  getchar();
  printf("請輸入要增加的頂點:");
  scanf("%c",&c);
  l=locateALG(G,c);
  if(l>=0){
   printf("輸入的頂點重複,請重新輸入/n");
   i--;
   continue;
  }
  G.vertices[G.vexnum].data=c;
  G.vertices[G.vexnum].firstarc=NULL;
  G.vexnum++;
  printf("增加頂點成功/n");
 }
 return OK;
}

/*---------------------------當前有向圖刪除弧-------------------*/
int delArc(ALGraph &G,int i,int j){
 ArcNode *p,*q;
 p=G.vertices[i].firstarc;
 if(p->adjvex==j){
  G.vertices[i].firstarc=p->nextarc;
  free(p);
 }
 else{
  while(p->nextarc&&p->nextarc->adjvex!=j)
   p=p->nextarc;
  if(p){
   q=p->nextarc;
   p->nextarc=q->nextarc;
   free(q);
  }
 }
 G.arcnum--;
 return OK;
}
int GraphDel(ALGraph &G){
 int n,k,i,j;
    VertexType v1,v2;
 printf("請輸入要刪除的弧數:");
 scanf("%d",&n);
 while(n>G.arcnum){
  printf("刪除的弧數不能超過%d,請重新輸入/n",G.arcnum);
  printf("請輸入要刪除的弧數:");
     scanf("%d",&n);
 }
 for(k=0;k<n;k++){
  getchar();
  printf("請輸入要刪除的弧的起點與終點(用逗號分隔):"); 
  scanf("%c,%c",&v1,&v2);  
  i=locateALG(G,v1);
  j=locateALG(G,v2);
  if(i<0||j<0||i==j||(!GraphExist(G,i,j))){
   printf("輸入有誤,請重新輸入/n");
   k--;
   continue;
  }
  delArc(G,i,j);
 }
 return 1;
}

/*---------------------------當前有向圖刪除頂點-------------------*/
int NodeDel(ALGraph &G){
 int i,l,n,k;
 char c;
 ArcNode *p;
 printf("請輸入要刪除的頂點個數:");
 scanf("%d",&n); 
    if(n>G.vexnum){
  printf("輸入錯誤/n");
        return ERROR;
 }
 for(k=0;k<n;k++){//輸入要刪除頂點資訊
  getchar();
  printf("請輸入要刪除的頂點:");
  scanf("%c",&c);
  l=locateALG(G,c);
  if(l<0){
   printf("輸入的頂點不存在,請重新輸入/n");
   k--;
   continue;
  }
  for(i=0;i<G.vexnum;i++){
   //刪除與此頂點相關的弧
   if(GraphExist(G,i,l)){
    delArc(G,i,l);
   } 
   if(GraphExist(G,l,i)){
    delArc(G,l,i);
   }
   //修改必要表結點的頂點的位置值
   p=G.vertices[i].firstarc;
            while(p){
    if(p->adjvex>l){  p->adjvex--;
    }
    p=p->nextarc;
   }
  }
  //釋放空間,頂點c後的頂點前移
  for(i=l;i<G.vexnum-1;i++){
   G.vertices[i]=G.vertices[i+1];
  } 
  G.vexnum--;
  printf("刪除頂點成功/n");
 }
 return OK;
}


/*--------------------------儲存結構的轉換-----------------------*/
//將鄰接錶轉換成鄰接矩陣
status TranlateAl(ALGraph G1, MGraph &G2){
 //設定引數
 int i,j;
 ArcNode *p;
 G2.kind = G1.kind;
 G2.vexnum = G1.vexnum;
 G2.arcnum = G1.arcnum;
 //複製頂點
 for(i=0;i<G1.vexnum;i++)
  G2.vexs[i] = G1.vertices[i].data;
 //複製弧
 for(i=0;i<G2.vexnum;i++)
  for(j=0;j<G2.vexnum;j++)
   G2.arcs[i][j].adj=MAX; 
  for(i=0;i<G1.vexnum;i++){//複製G1每個頂點的鄰接點
   p=G1.vertices[i].firstarc;
   while(p){
    G2.arcs[i][p->adjvex].adj=p->weight;
    p=p->nextarc;
   }
  }
  printf("轉換成功/n");
  return OK;
}
//將鄰接矩陣轉換成鄰接表 
status TranlateDG(MGraph G1,ALGraph &G2){
 int i,j;
 ArcNode *p;
 //設定引數
 G2.kind= G1.kind;
 G2.vexnum = G1.vexnum;
 G2.arcnum = G1.arcnum;
 //複製頂點
 for(i=0;i<G1.vexnum;i++){
  G2.vertices[i].data=G1.vexs[i];
  G2.vertices[i].firstarc=NULL;
 }
 //複製弧
 for(i=0;i<G1.vexnum;i++){
  for(j=0;j<G1.vexnum;j++){
   if(G1.arcs[i][j].adj!=MAX){
    p=(ArcNode*)malloc(sizeof(ArcNode));//建立結點
    if(!p) return ERROR;
    p->weight=G1.arcs[i][j].adj;
    p->adjvex=j;
    p->nextarc=G2.vertices[i].firstarc;//頂點i的連結串列
    G2.vertices[i].firstarc=p;//新增到最左邊
   }
  }
 }
 printf("轉換成功/n");
 return OK;
}

/*-----------------深度優先生成樹-------------------*/
char GetVex(ALGraph G,int i){
 return G.vertices[i].data;
}
void DFSTree(ALGraph G,int i, CSTree &T){
 //從第i個頂點出發深度優先遍歷有向圖G,建立以T為根的生成樹
 int w;
 CSNode *p,*q;
 visited[i]=true;
 bool first=true;
 for(w=FirstAdjVex(G,i);w>=0;w=NextAdjVex(G,i))
  if(!visited[w]){
   p=(CSTree)malloc(sizeof(CSNode));
   p->data=GetVex(G,w);
   p->firstchild=NULL;
   p->nextsibling=NULL;
   if(first){ //w是i的第一個未被訪問的鄰接頂點
    T->firstchild=p;//是根的左孩子結點
    first=false;
   }
   else{   //w是i的其他未被訪問的鄰接頂點
    q->nextsibling=p;  //是上一鄰接頂點的右兄弟結點
   }
   q=p;
   DFSTree(G,w,q);
  }
}
status DFSforest(ALGraph G,CSTree &T){
 //建立有向圖的深度優先生成森林/生成樹
 int i;
 CSNode *p,*q;
 T=NULL;
 for(i=0;i<G.vexnum;i++)  visited[i]=false;
 for(i=0;i<G.vexnum;i++)
  if(!visited[i]){    //第i頂點為新的生成樹的根節點
   p=(CSTree)malloc(sizeof(CSNode));
            p->data=GetVex(G,i);
   p->firstchild=NULL;
   p->nextsibling=NULL;
   if(!T) T=p;          //是第一棵生成樹的根(T的根)
   else q->nextsibling=p;  //是其他生成樹的根
   q=p;                    //q指示當前生成樹的根
   DFSTree(G,i,p);         //建立以p為根的生成樹
  }
  printf("圖的深度優先生成森林成功/n");
  return OK;
}

//樹的先根遍歷
void Preorder(CSTree T){
 if (!T)  return;
 printf("%c/t",T->data);                    // 訪問根結點
 Preorder(T->firstchild); // 遍歷左子樹 
 Preorder(T->nextsibling); // 遍歷右子樹
}

/*---------------------是否存在路徑,並輸出一條簡單路徑-------------------*/

//判斷有向圖G中頂點i到頂點j是否有路徑
status DfsReachable(ALGraph g, int i, int j){  
 int n,k;
    LinkQueue Q;
    ArcNode *p; 
 char v,v1;
    InitQueue(Q);
 v1=g.vertices[i].data;
 EQueue(Q,v1);
 while(!QueueEmpty(Q)){     //佇列不空時迴圈
  DeQueue(Q,v);
        n=locateALG(g,v);
  visited[n]=true;
  for(p=g.vertices[n].firstarc;p;p=p->nextarc){
   k=p->adjvex;
   v=g.vertices[k].data;  
   if(j==k){
    return 1;
   }
   if(!visited[k]){
    EQueue(Q,v);
   }
  }
 }
 return 0;
}

//找簡單路徑
bool found;
void reacher(ALGraph G,int i,int j,SqStack &s){
 VertexType v;
 int w;
 ArcNode *p;
 visited[i]=true;
 v=G.vertices[i].data;
 Push(s,v);
 for(p=G.vertices[i].firstarc;p;p=p->nextarc){
  int k=p->adjvex;
  if(!found){
   v=G.vertices[k].data;
   if(j==k){
    found=true;
    Push(s,v);
    break;
   }
   else
    if(!visited[k]){
     reacher(G,k,j,s);
    }
  }
 }
 if(!found){
  Pop(s,v);
 }
}

int exist_path(ALGraph G){
 SqStack s;
 InitStack(s);
 int n,i,j;
 VertexType v1,v2;
 found=false;
 for(n=0;n<G.vexnum;n++)
  visited[n]=false;
 printf("請輸入起點與終點(用逗號分隔):");
 getchar();
 scanf("%c,%c",&v1,&v2);
 i=locateALG(G,v1);
 j=locateALG(G,v2); 
 if (i<0||j<0||i==j)
 {
  printf("輸入錯誤/n");
  return -1;
 }
 if(DfsReachable(G,i,j)){
  for(n=0;n<G.vexnum;n++)
   visited[n]=false;
  reacher(G,i,j,s);
  printf("頂點%c到頂點%c存在路徑,其一條簡單路徑為:",v1,v2);
  
  Get(s);
  DestroyStack(s);
 }
 else
  printf("頂點%c到頂點%c不存在路徑/n",v1,v2);
 return OK;
}

/*--------------------------拓撲排序判斷是否存在環--------------*/

status ToplogicalSort(ALGraph G){
 char v;
 LinkQueue Q;
 ArcNode *p;
 int k;
 int i,j;
 int n=G.vexnum;
 int indegree[21];
 for(i=0;i<n;i++)
  indegree[i]=InDegree(G,i);
 InitQueue(Q);
 for(i=0;i<n;i++){
  if(!indegree[i]){
   v=G.vertices[i].data;
   EQueue(Q,v);
  }
 }
 int count=0;           //對輸出頂點計數
 while (!QueueEmpty(Q)){
  DeQueue(Q,v);
  ++count; 
  j=locateALG(G,v);
  for(p=G.vertices[j].firstarc;p;p=p->nextarc){
   k=p->adjvex;
   --indegree[k];  // 弧頭頂點的入度減1
   if(!indegree[k]){
    v=G.vertices[k].data;
    EQueue(Q,v);
   }
  }     
 }//while
 if (count<n){
  printf("此有向圖中存在環/n");
  return ERROR;
 }
    printf("此有向圖中不存在環/n");
    return OK;
}


/*---------------------源點到其他頂點的最短路徑----------------------*/
int prev[50];//prev[v]表示從源s到頂點v的最短路徑上頂點的前驅頂點。
bool P[50][50]; //p[i][w]為true時w為v到i當前求的最短路徑上的頂點
int D[50];   //D[w]存放頂點w的權值

//得到邊<i,j>的權值
int getWei(ALGraph G,int i,int j){
 ArcNode *s;
 s=G.vertices[i].firstarc;
 while(s&&s->adjvex!=j){
  s=s->nextarc;
 }
 if(s)   return s->weight;
 else    return MAX;
}

void ShortestPath_DIJ(ALGraph G,int v){
 int i=0,j,v0,w,min;
    bool final[50];    //當final[w]為true,已經求的從v到w得最短路徑
 for(v0=0;v0<G.vexnum;v0++){
  prev[v0]=-1;
  final[v0]=false;
  D[v0]=getWei(G,v,v0);
  for(w=0;w<G.vexnum;++w)   P[v0][w]=false;   // 設空路徑
  if(D[v0]<MAX){ //頂點i與源點v鄰接
   prev[v0]=v;
   P[v0][v]=true;  
   P[v0][v0] =true;
  }
 }
 D[v]=0;   final[v]=true;
 //主迴圈,每次求得v0到某個頂點v的最短路徑,並將v加到S集中
 for(i=1;i<G.vexnum;++i){
  //當前所知離v頂點的最近距離
        min=MAX;
        for(w=0;w<G.vexnum;++w){
   if(!final[w])
    if(D[w]<min){
     v0=w;   min=D[w];
    }
  }
  if(v0==G.vexnum){
   break;
  }
  final[v0]=true;      //更新當前最短路徑及距離
  for(w=0;w<G.vexnum;++w)
   if(!final[w]&&(min+getWei(G,v0,w)<D[w])){
    prev[w]=v0;
    D[w]=min+getWei(G,v0,w);
    for(j=0;j<G.vexnum;j++) P[w][j]=P[v0][j];
    P[w][w]=true;
   }//if
 }//for
}
//輸出最短路徑
void printPath(ALGraph G,int v){
 int i,k;
 SqStack s;
 InitStack(s);
    SElemType a;
 for(i=0;i<G.vexnum;i++){
  if(i!=v){
   if(D[i]!=MAX){
    printf("%c到%c的最短路徑長度為:%d/n",G.vertices[v].data,G.vertices[i].data,D[i]);
    printf("%c到%c的最短路徑為:",G.vertices[v].data,G.vertices[i].data);
    a=G.vertices[i].data;
    Push(s,a);
    for(k=prev[i];k>-1;k=prev[k]){
     a=G.vertices[k].data;
     Push(s,a);
    }//for(k)
    while(!EmptyStack(s)){
     Pop(s,a);
     printf("%c/t",a);
    }//while
    printf("/n");
   }//if(D[i]!=MAX)
   else
    printf("%c到%c不存在最短路徑/n",G.vertices[v].data,G.vertices[i].data);
  }//if(i!=v)
 }//for(i)
}

/*---------------------任兩點間的最短路徑----------------------*/
void AllShortestPath(ALGraph G){
 int i;
 for(i=0;i<G.vexnum;i++){
  ShortestPath_DIJ(G,i);
  printPath(G,i);
 }
}

/*-------------------------選單----------------------*/

void menu(){
 MGraph m;
 ALGraph a;
 CSTree T=NULL;
 int n;
 while(n){
  printf("/n");
  printf("/t****************************選擇菜**********************************/n"); 
  printf("/t/t/t1:建立有向圖的鄰接表/n");
  printf("/t/t/t2:建立有向圖的鄰接矩陣/n");
  printf("/t/t/t3:求每個頂點的入度,出度/n");
  printf("/t/t/t4:深度優先遍歷有向圖,並判斷其連通性/n");
  printf("/t/t/t5:在有向圖中插入弧/n");
  printf("/t/t/t6:在有向圖中刪除弧/n");
  printf("/t/t/t7:在有向圖中插入頂點/n");
  printf("/t/t/t8:在有向圖中刪除頂點/n");
  printf("/t/t/t9:鄰接矩陣轉換成鄰接表/n");
  printf("/t/t/t10:鄰接錶轉換成鄰接矩陣/n");
  printf("/t/t/t11:有向圖深度優先生成樹,並進行遍歷/n");
  printf("/t/t/t12:判斷有向圖中是否存在環/n");
  printf("/t/t/t13:兩頂點是否存在路徑,存在時輸出一條簡單路徑/n");
  printf("/t/t/t14:某頂點到其他頂點的最短路徑/n");
  printf("/t/t/t15:任兩點間的最短路徑/n");
  printf("/t/t/t0:退出/n");
        printf("/t********************************************************************/n"); 
  printf("請選擇選單號:");
  scanf("%d",&n); 
  switch(n){
  case 1:
   CreateADG(a);
   printGra(a);
    break;
  case 2:
   createMDG(m);  
   break;
        case 3:
   if(!ExistG(a))
         break;
   printGra(a);
   degree(a);
            break;
  case 4:
   if(!ExistG(a))
    break;
   printGra(a);
   DFSTraverse(a); break;
  case 5:
   if(!ExistG(a))
    break;
   GraphAdd(a);
   printGra(a); break;
  case 6:
   if(!ExistG(a))
    break;
   GraphDel(a);
   printGra(a);  break;
  case 7:
   if(!ExistG(a))
    break;
   NodeAdd(a);
            printGra(a);   break;
  case 8:
   if(!ExistG(a))
    break;
            NodeDel(a);  
   printGra(a);  break;
  case 9:
   if(!ExistM(m))
    break;
   TranlateDG(m,a);
   printGra(a);
    break;
  case 10:
   if(!ExistG(a))
    break;
   TranlateAl(a,m);
   printMg(m);
   break;
  case 11:
   if(!ExistG(a))
    break;
   printGra(a);
   DFSforest(a,T);
   printf("對生成樹進行遍歷的結果:");
            Preorder(T);   break;
  case 12:
   if(!ExistG(a))
    break;
   printGra(a);
   ToplogicalSort(a); break;      
  case 13:
   if(!ExistG(a))
    break;
   printGra(a);
   exist_path(a);   break;
  case 14:
   if(!ExistG(a))
    break;
   SqStack s;
   InitStack(s);
   char c;
   int m;
   printGra(a);
   printf("請輸入源點:");
   getchar();
   scanf("%c",&c);
   m=locateALG(a,c);
   if(m<0){
    printf("輸入錯誤/n");
    break;
   }
   ShortestPath_DIJ(a,m);
   printPath(a,m);
   break;
  case 15:
   if(!ExistG(a))
    break;
   printGra(a);
   AllShortestPath(a);   break;
  default:
   break;
  }
 }
}

void main(){
 menu();
}