Data Structure --- MGraph

//這是一個小小的關於char類型的測驗
//scanf("%c %c") 這樣的話可以輸入 A B 但是輸入完後再輸入換行會在緩衝區中 等待下一個字符 所以應該用temp存儲換行 如果沒有temp那麼輸入換行直接就是出來結果 c3就是換行
//#include<stdio.h>
//int main()
//{
//    char c1,c2,c3,temp;
//    scanf("%c %c",&c1,&c2);
//    scanf("%c",&temp);
//    scanf("%c",&c3);
//    printf("%c %c %c",c1,c2,c3);
//    return 0;
//}
//A B
//C
//A B C
//Process returned 0 (0x0)   execution time : 14.385 s
//Press any key to continue.

//這是另一個小小的關於char類型的測驗
//同樣scanf遇到換行就輸入完畢 但%d是需要輸入空白字符才能表示輸入完畢 空格換行tab都可以 最後一個輸入後需要換行
//鍵盤輸入的會在緩衝區 但是printf輸出的換行不會
//%d%d中間輸入的空白符不會在緩衝區 但是最後一個之後的輸入會在 並且直接影響到後續輸入的%c
//如果scanf("%d%d"),再scanf("%c"),雖然說%d是需要空白符才能表示輸入完 但是這種情況下 前面兩個%d 只有第一個可以 第二個不可以輸入完後輸空白符 否則變成了%c
//#include<stdio.h>
//int main()
//{
//    int ch;
//    char m,n,temp;
//    int i;
//
//    for(i=1;i<=3;i++)
//    {
//         scanf("%c%c %d",&m,&n,&ch);
//         scanf("%c",&temp);       //存儲%d後輸入的換行
//         printf("%c %c %d\n",m,n,ch);
//    }
//
//    return 0;
//}
//AB 3
//A B 3
//CD 2
//C D 2
//EF 5
//E F 5
//
//Process returned 0 (0x0)   execution time : 20.370 s
//Press any key to continue.

#include<stdio.h>
#include<stdlib.h>
#include<limits.h>   //提供INT_MAX
#include<stdarg.h>   //提供va_list va_arg va_start va_end
#define OVERFLOW -2
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAX_VERTEX_NUM 20
#define INFINITY INT_MAX  //無窮大
typedef int ElemType;
typedef int Status;
typedef struct QNode
{
    ElemType data;
    struct QNode *next;
}QNode,*QueuePtr;
typedef struct
{
    QueuePtr front;
    QueuePtr rear;
}LinkQueue;
Status InitQueue(LinkQueue *Q)
{
    (*Q).front=(*Q).rear=(QueuePtr)malloc(sizeof(QNode));
    if(!(*Q).front) exit(OVERFLOW);
    (*Q).front->next=NULL;
    return OK;
}
Status QueueEmpty(LinkQueue Q)
{
    return Q.front==Q.rear?TRUE:FALSE;
}
Status EnQueue(LinkQueue *Q,ElemType e)
{
    QueuePtr p;

    p=(QueuePtr)malloc(sizeof(QNode));
    if(!p) exit(OVERFLOW);
    p->next=NULL;
    p->data=e;

    (*Q).rear->next=p;
    (*Q).rear=p;

    return OK;
}
Status DeQueue(LinkQueue *Q,ElemType *e)
{
    QueuePtr p;

    if((*Q).front==(*Q).rear)
        return ERROR;

    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 int VRType;
typedef char VertexType;
typedef enum
{
    DG,DN,UDG,UDN   //DG 0 digraph 有向圖 DN 1 directed network 有向網  UDG 2 undigraph 無向圖 UDN 3 undirected network 無向網
}GraphKind;  //枚舉類型名 表示創建的圖的類型
//typedef struct
//{
//
//}InfoType;
typedef struct
{
    VRType adj;       //頂點間的關係  vertex relationship type
    //InfoType *info;   //弧相關的信息  information type
}ArcCell,AdjMatrix[MAX_VERTEX_NUM+1][MAX_VERTEX_NUM+1]; //AdjMatrix 鄰接矩陣
typedef struct
{
    VertexType vexs[MAX_VERTEX_NUM+1]; //頂點類型
    AdjMatrix arcs;
    GraphKind kind;
    int vexnum,arcnum;  //arc 弧
    //int IncInfo; //本來打算用來處理弧的相關信息 但我不知道怎麼處理
}MGraph;
Status visited[MAX_VERTEX_NUM+1];  //標誌數組
void (*visitFunc)(VertexType e);   //函數指針變量
Status CreateGraph(MGraph *G)
{
    int n;

    printf("0:有向圖\n");
    printf("1:有向網\n");
    printf("2:無向圖\n");
    printf("3:無向網\n");

    printf("請輸入操作的編號:\n");
    scanf("%d",&n);

    printf("\n");

    (*G).kind=(GraphKind)n;  //不要遺漏這個地方  //不能把整數直接賦值給枚舉類型變量(要對整數進行強制轉換)

    switch(n)
    {
    case 0:
        return CreateDG(G);
        break;
    case 1:
        return CreateDN(G);
        break;
    case 2:
        return CreateUDG(G);
        break;
    case 3:
        return CreateUDN(G);
        break;
    }
}
int LocateVex(MGraph G,VertexType v)
{
    int i;
    for(i=1;i<=G.vexnum;i++)
    {
        if(v==G.vexs[i])
            return i;
    }
    return ERROR;
}
Status CreateDG(MGraph *G)
{
    int i,j,k;
    char temp;  //如果涉及字符輸入的話 換行會在緩衝區 最後被當作字符錄入
    VertexType v1,v2;

    printf("請依次輸入頂點數,弧數:\n");
    scanf("%d%d",&(*G).vexnum,&(*G).arcnum);

    //存取換行
    scanf("%c",&temp);

    //先處理頂點
    printf("請依次輸入頂點:\n");
    for(i=1;i<=(*G).vexnum;i++)
        scanf("%c",&(*G).vexs[i]);   //第一次這裏%c後面有一個空格 出現了問題

    //存取換行
    scanf("%c",&temp);

     //初始化鄰接矩陣
    for(i=1;i<=(*G).vexnum;i++)
    {
        for(j=1;j<=(*G).vexnum;j++)
        {
            (*G).arcs[i][j].adj=0;
        }
    }

    //再處理弧
    printf("請輸入弧:\n");

    for(k=1;k<=(*G).arcnum;k++)
    {
        scanf("%c%c",&v1,&v2);
        scanf("%c",&temp);

        i=LocateVex(*G,v1);
        j=LocateVex(*G,v2);

        if(!i||!j)
            return ERROR;

        (*G).arcs[i][j].adj=1;
    }

    return OK;
}
Status CreateDN(MGraph *G)
{
    int i,j,k;
    VertexType v1,v2;
    char temp;
    VRType w;

    printf("請依次輸入頂點數,弧數:\n");
    scanf("%d%d",&(*G).vexnum,&(*G).arcnum);

    scanf("%c",&temp);

    printf("請依次輸入頂點:\n");
    for(i=1;i<=(*G).vexnum;i++)
        scanf("%c",&(*G).vexs[i]);

    scanf("%c",&temp);

    for(i=1;i<=(*G).vexnum;i++)
    {
        for(j=1;j<=(*G).vexnum;j++)
        {
            (*G).arcs[i][j].adj=INFINITY;
        }
    }

    printf("請輸入弧及相應的權值:\n");

    for(k=1;k<=(*G).arcnum;k++)
    {
        scanf("%c%c %d",&v1,&v2,&w);

        scanf("%c",&temp);  //存取%d後面的換行

        i=LocateVex(*G,v1);
        j=LocateVex(*G,v2);

        if(!i||!j)
            return ERROR;

        (*G).arcs[i][j].adj=w;
    }

    return OK;

}
Status CreateUDG(MGraph *G)
{
    int i,j,k;
    char temp;  //如果涉及字符輸入的話 換行會在緩衝區 最後被當作字符錄入
    VertexType v1,v2;

    printf("請依次輸入頂點數,弧數:\n");
    scanf("%d%d",&(*G).vexnum,&(*G).arcnum);

    //存取換行
    scanf("%c",&temp);

    //先處理頂點
    printf("請依次輸入頂點:\n");
    for(i=1;i<=(*G).vexnum;i++)
        scanf("%c",&(*G).vexs[i]);

    //存取換行
    scanf("%c",&temp);

     //初始化鄰接矩陣
    for(i=1;i<=(*G).vexnum;i++)
    {
        for(j=1;j<=(*G).vexnum;j++)
        {
            (*G).arcs[i][j].adj=0;
        }
    }

    //再處理弧
    printf("請輸入弧:\n");

    for(k=1;k<=(*G).arcnum;k++)
    {
        scanf("%c%c",&v1,&v2);
        scanf("%c",&temp);

        i=LocateVex(*G,v1);
        j=LocateVex(*G,v2);

        if(!i||!j)
            return ERROR;

        (*G).arcs[i][j].adj=1;
        (*G).arcs[j][i].adj=1;
    }

    return OK;
}
Status CreateUDN(MGraph *G)
{
    int i,j,k;
    VertexType v1,v2;
    char temp;
    VRType w;

    printf("請依次輸入頂點數,弧數:\n");
    scanf("%d%d",&(*G).vexnum,&(*G).arcnum);

    scanf("%c",&temp);

    printf("請依次輸入頂點:\n");
    for(i=1;i<=(*G).vexnum;i++)
        scanf("%c",&(*G).vexs[i]);

    scanf("%c",&temp);

    for(i=1;i<=(*G).vexnum;i++)
    {
        for(j=1;j<=(*G).vexnum;j++)
        {
            (*G).arcs[i][j].adj=INFINITY;
        }
    }

    printf("請輸入弧及相應的權值:\n");

    for(k=1;k<=(*G).arcnum;k++)
    {
        scanf("%c%c %d",&v1,&v2,&w);

        scanf("%c",&temp);  //存取%d後面的換行

        i=LocateVex(*G,v1);
        j=LocateVex(*G,v2);

        if(!i||!j)
            return ERROR;

        (*G).arcs[i][j].adj=w;
        (*G).arcs[j][i].adj=w;
    }

    return OK;
}
void ClearGraph(MGraph *G)
{
    (*G).vexnum=0;
    (*G).arcnum=0;
    //(*G).IncInfo=0;
}
VertexType GetVex(MGraph G,int order)  //這裏需要注意給的是頂點下標 不是直接給的頂點
{
   if(order>=1&&order<=G.vexnum)
    return G.vexs[order];
   else return '\0';
}
Status PutVex(MGraph *G,VertexType v,VertexType value)  //這裏需要注意給的直接是頂點
{
    int i;

    i=LocateVex(*G,v);

    if(!i) return ERROR;
    else
    {
        (*G).vexs[i]=value;
        return OK;
    }
}
int FirstAdjVex(MGraph G,VertexType v)
{
    int i,j,t;

    i=LocateVex(G,v);

    if(i)
    {
        if(G.kind%2)      //網
            t=INFINITY;
        else t=0;         //圖

        for(j=1;j<=G.vexnum;j++)
        {
            if(G.arcs[i][j].adj!=t)
                return j;
        }
    }
    return 0;
}
int NextAdjVex(MGraph G,VertexType v,VertexType w)
{
    int i,j,k,t;

    i=LocateVex(G,v);
    j=LocateVex(G,w);

    if(i&&j)
    {
        if(G.kind%2)
            t=INFINITY;
        else t=0;

        for(k=j+1;k<=G.vexnum;k++)
        {
            if(G.arcs[i][k].adj!=t)
                return k;
        }
    }

    return 0;
}
Status InsertVex(MGraph *G,VertexType v)
{
    if((*G).vexnum==MAX_VERTEX_NUM)
        return ERROR;

    int i,j,t;

    i=(*G).vexnum+1;

    (*G).vexs[i]=v;

    if((*G).kind%2)
        t=INFINITY;
    else t=0;

    for(j=1;j<=i;j++)  //這個地方不是j<=(*G).vexnum而是j<=k 因爲增加了頂點 個數增加了 只是這步操作之前原來的頂點個數還需要用到 所以暫時沒有加一 若是原來的 那麼新增的會是亂值
    {
        (*G).arcs[i][j].adj=t;
        (*G).arcs[j][i].adj=t;
    }

    (*G).vexnum++;

    return OK;
}
Status DeleteVex(MGraph *G,VertexType v)  //注意內部處理順序
{
    int i,j,k,t;
    i=LocateVex(*G,v);

    if(!i) return ERROR;

    if((*G).kind%2)
        t=INFINITY;
    else t=0;

    //處理弧數
    for(j=1;j<=(*G).vexnum;j++)
    {
        if((*G).arcs[i][j].adj!=t)
            (*G).arcnum--;

        if((*G).kind%2)
        {
            if((*G).arcs[j][i].adj!=t)
                (*G).arcnum--;
        }
    }

    //處理列
    for(j=1;j<=(*G).vexnum;j++)
    {
        for(k=i+1;k<=(*G).vexnum;k++)
        {
            (*G).arcs[j][k-1].adj=(*G).arcs[j][k].adj;
        }
    }

    //處理行
    for(j=i+1;j<=(*G).vexnum;j++)   //j表示行 k表示列
    {
        for(k=1;k<(*G).vexnum;k++)  //這裏需要注意因爲上述列已經往前覆蓋 所以這裏k不等於(*G).vexnum了
        {
            (*G).arcs[j-1][k]=(*G).arcs[j][k];
        }
    }

    //處理頂點
    for(j=i;j<(*G).vexnum;j++)
        (*G).vexs[j]=(*G).vexs[j+1];

    (*G).vexnum--;

    return OK;

}
Status InsertArc(MGraph *G,VertexType v,VertexType w,VRType adj)
{
    int i,j;

    i=LocateVex(*G,v);
    j=LocateVex(*G,w);

    if(!i||!j)
        return ERROR;

    (*G).arcs[i][j].adj=adj;

    if(!(*G).kind%2)
        (*G).arcs[j][i].adj=adj;

    (*G).arcnum++;

    return OK;
}
Status DeleteArc(MGraph *G,VertexType v,VertexType w)
{
    int i,j,t;

    i=LocateVex(*G,v);
    j=LocateVex(*G,w);

    if(!i||!j)
        return ERROR;

    if((*G).kind%2)
        t=INFINITY;
    else t=0;

    (*G).arcs[i][j].adj=t;

    if((*G).kind%2)
        (*G).arcs[j][i].adj=t;

    (*G).arcnum--;

    return OK;
}
void DFSTraverse(MGraph G,void(visit)(VertexType e))
{
    int v;

    //VisitFunc是全局變量 所以在調用的時候DFS就不用設置參數了

    visitFunc=visit;    //VisitFunc是函數指針 visit是函數名 函數指針的用法是 直接將函數名賦值給函數指針 函數指針在調用的時候 和函數名是一樣的

    for(v=1;v<=G.vexnum;v++)
        visited[v]=FALSE;

    for(v=1;v<=G.vexnum;v++)
    {
        if(!visited[v])
            DFS(G,v);
    }

}
void DFS(MGraph G,int v)
{
    int w;

    visited[v]=TRUE;

    visitFunc(G.vexs[v]);

    for(w=FirstAdjVex(G,G.vexs[v]);w;w=NextAdjVex(G,G.vexs[v],G.vexs[w]))
    {
        if(!visited[w])
            DFS(G,w);
    }
}
void BFSTraverse(MGraph G,void(visit)(VertexType e))
{
    int v,w;
    ElemType e;

    for(v=1;v<=G.vexnum;v++)
        visited[v]=FALSE;

    LinkQueue Q;
    InitQueue(&Q);

    for(v=1;v<=G.vexnum;v++)
    {
        if(!visited[v])
        {
            visited[v]=TRUE;
            visit(G.vexs[v]);
            EnQueue(&Q,v);

            while(!QueueEmpty(Q))
            {
                DeQueue(&Q,&e);

                for(w=FirstAdjVex(G,G.vexs[e]);w;w=NextAdjVex(G,G.vexs[e],G.vexs[w]))
                {
                    if(!visited[w])
                    {
                         visited[w]=TRUE;
                         visit(G.vexs[w]);
                         EnQueue(&Q,w);
                    }
                }
            }
        }
    }
}
void visit(VertexType e)
{
    printf("%c ",e);
}
void PrintGraph(MGraph G)
{
    int i,j;

    if(!G.vexnum&&!G.arcnum)
        printf("這是空(圖)表!\n");
    else
    {
        printf("  ");

        for(i=1;i<=G.vexnum;i++)
            printf("%2c ",G.vexs[i]);
        printf("\n");

        for(i=1;i<=G.vexnum;i++)
        {
            printf("%c ",G.vexs[i]);

            for(j=1;j<=G.vexnum;j++)
            {
                if(G.arcs[i][j].adj==INFINITY)
                    printf("∞ ");  //電腦中輸出無窮大的方法 ctrl+shif+B->數學->尋找無窮大
                else printf("%2d ",G.arcs[i][j]);
            }

            printf("\n");
        }
    }
}
int main()
{
    MGraph G;
    VertexType v;

    CreateGraph(&G);
    PrintGraph(G);

    printf("\n");

    printf("深度遍歷結果是:\n");
    DFSTraverse(G,visit);
    printf("\n");

    printf("廣度遍歷結果是:\n");
    BFSTraverse(G,visit);
    printf("\n");

    v=GetVex(G,2);
    printf("%c\n",v);

    printf("\n");

    PutVex(&G,v,'H');

    InsertVex(&G,'I');

    DeleteVex(&G,'H');

    InsertArc(&G,'I','D',2);

    DeleteArc(&G,'D','C');

    PrintGraph(G);

    printf("\n");

    printf("深度遍歷結果是:\n");
    DFSTraverse(G,visit);
    printf("\n");

    printf("廣度遍歷結果是:\n");
    BFSTraverse(G,visit);
    printf("\n");

    return 0;
}


測試結果:
0:有向圖
1:有向網
2:無向圖
3:無向網
請輸入操作的編號:
1

請依次輸入頂點數,弧數:
6 10
請依次輸入頂點:
ABCDEF
請輸入弧及相應的權值:
AB 5
AD 7
BC 4
CA 8
CF 9
DC 5
DF 6
ED 5
FA 3
FE 1
   A  B  C  D  E  F
A ∞  57 ∞ ∞
B ∞ ∞  4 ∞ ∞ ∞
C  8 ∞ ∞ ∞ ∞  9
D ∞ ∞  5 ∞ ∞  6
E ∞ ∞ ∞  5 ∞ ∞
F  3 ∞ ∞ ∞  1 ∞

深度遍歷結果是:
A B C F E D
廣度遍歷結果是:
A B D C F E
B

   A  C  D  E  F  I
A ∞ ∞  7 ∞ ∞ ∞
C  8 ∞ ∞ ∞  9 ∞
D ∞ ∞ ∞ ∞  6 ∞
E ∞ ∞  5 ∞ ∞ ∞
F  3 ∞ ∞  1 ∞ ∞
I ∞ ∞  2 ∞ ∞ ∞

深度遍歷結果是:
A D F E C I
廣度遍歷結果是:
A D F E C I

Process returned 0 (0x0)   execution time : 66.828 s
Press any key to continue.



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章