【数据结构笔记】6:无向图的邻接多重表存储结构

邻接多重表的实现。这次研讨确实有难度,除了实现这个还要完成最小生成树。

直接上代码吧。
边节点Arc.h

    #ifndef ARC_H
    #define ARC_H
     
    #ifndef NULL
    #define NULL 0
    #endif
     
    struct Arc
    {
        bool tag;
        int weight;
        int adjVex1, adjVex2;
        Arc* nextArc1;
        Arc* nextArc2;
        Arc(int w, int ad1, int ad2, Arc* next1 = NULL, Arc* next2 = NULL);//3~5参构造器
    };
     
    Arc::Arc(int w, int ad1, int ad2, Arc* next1, Arc* next2)
    {
        tag = 0;
        weight = w;
        adjVex1 = ad1;
        adjVex2 = ad2;
        nextArc1 = next1;
        nextArc2 = next2;
    }
     
    #endif

顶点节点Vex.h

    #ifndef VEX_H
    #define VEX_H
    #include "Arc.h"
    struct Vex
    {
        char data;
        Arc* firstArc;
     
        Vex();
        Vex(char myData, Arc* myFirstArc);
    };
     
    Vex::Vex()//无参的构造器
    {
        data = '?';
        firstArc = NULL;
    }
     
    Vex::Vex(char myData, Arc* myFirstArc) //给1~2个参数的构造器
    {
        data = myData;
        firstArc = myFirstArc;
    }
    #endif

邻接多重表NetWork.h

    #ifndef NETWORK_H
    #define NETWORK_H
    #include "Vex.h"
    #include <iostream>
    using namespace std;
    struct NetWork
    {
        Vex* arrayVex;
        int size;
     
        NetWork(int mySize, char myVex[], int **myArc);//构造函数
        void DeleteEdge(int a, int b);//删除a<->b这条边
        void InsertEdge(int a, int b,int numK);//插入a<->b这条边
        void ChangeEdge(int a, int b, int numK);//修改a<->b这条边的权值
        void Show();//显示
    };
     
    //3参数构造器
    NetWork::NetWork(int mySize, char myVex[], int **myArc)
    {
        arrayVex = new Vex[size = mySize]; //分配顶点数组的空间
        for (int i = 0; i < size; i++)
        {
            arrayVex[i].data = myVex[i]; //顶点的字符
        }
     
        Arc *q;//辅助指针,q用于记录new对象的地址
        int numK;//辅助数字,简化计算
     
        //该循环建立全部边节点
        for (int i = 0; i < size; i++)
        {
            for (int j = i+1; j < size; j++)
            {
                numK = *((int *)myArc + size*i + j); //即numK=myArc[i][j]
                if (numK>0) //如果存在这条边
                {
                    q = new Arc(numK, i, j);//建立这个边
                    q->nextArc1 = arrayVex[i].firstArc;//i的first边一定具有i,可以作为新边的next1
                    q->nextArc2 = arrayVex[j].firstArc;//j的first边一定具有j,可以作为新边的next2
                    arrayVex[i].firstArc = q;//头插这条边
                    arrayVex[j].firstArc = q;//头插这条边
                }
                //如果不存在这条边,什么都不做
            }
        }
    }
     
    //删除边a<->b
    void NetWork::DeleteEdge(int a, int b)
    {
        if (a == b || a < 0 || b < 0 || a >= size || b >= size)
        {
            cout << "输入不合法!" << endl;
            return;
        }
        //find记录是否找到a->b,如果找不到的话就不需要找b->a了
        //next记录q(或r)是p的next1还是next2
        bool find = 0,next=0;
        int c;
        Arc* p,*q,*r;
        if (a > b)//交换使得a<b
        {
            c = b;
            b = a;
            a = c;
        }
     
        //先考虑a->b(从a开始找a<->b),改指针而暂时不删边节点
        q = arrayVex[a].firstArc;
        if (q == NULL)
        {
            cout << "要删除的边不存在" << endl;
            return;
        }
        if (q->adjVex1 == a && q->adjVex2 == b)//如果第一个边节点就是
        {
            arrayVex[a].firstArc = q->nextArc1;
            find = 1;
        }
        else//如果不是第一个边节点的话
        {
            //先初始化,p在q前
            p = arrayVex[a].firstArc;
            if (p->adjVex1 == a)
            {
                q = p->nextArc1;
                next = 0;//表示q是p的next1
            }
            else
            {
                q = p->nextArc2;
                next = 1;//表示q是p的next2
            }
            //然后进行循环
            while (q != NULL)
            {
                if (q->adjVex1 == a && q->adjVex2 != b)//即如果是a->非b
                {
                    q = q->nextArc1;//q向下走
                    //p紧随其后,但是p向下还是向右才能找到q要看next的记录了
                    if (next == 0)
                        p = p->nextArc1;
                    else
                        p = p->nextArc2;
                    next = 0;//下一次,p要向下走才能找到q
                }
                else if (q->adjVex2 == a)//即如果是非b->a(因为b比a大所以adjVex2==a时adjVex1一定不是b)
                {
                    q = q->nextArc2;//q向右走
                    //p紧随其后,但是p向下还是向右才能找到q要看next的记录了
                    if (next == 0)
                        p = p->nextArc1;
                    else
                        p = p->nextArc2;
                    next = 1;//下一次,p要向右走才能找到q
                }
                else//能运行到这时一定找到了a->b
                {
                    if (next == 0)//p要向下走才能找到q
                        p->nextArc1 = q->nextArc1;
                    else//p要向右走才能找到q
                        p->nextArc2 = q->nextArc1;
                    find = 1;//找到了a->b
                    break;//做完,跳出循环
                }
            }
        }
        
        if (find == 0)//如果从a找不到a<->b,那说明这条边并不存在
        {
            cout << "要删除的边不存在" << endl;
            return;
        }
     
        //再考虑b->a(从b开始找a<->b),改指针并且删边节点q==r
        if (arrayVex[b].firstArc->adjVex1 == a && arrayVex[b].firstArc->adjVex1 == b)//如果第一个边节点就是
        {
            arrayVex[b].firstArc = arrayVex[b].firstArc->nextArc2;
        }
        else//如果不是第一个边节点的话
        {
            p = arrayVex[b].firstArc;
            if (p->adjVex1 == b)
            {
                r = p->nextArc1;
                next = 0;
            }
            else
            {
                r = p->nextArc2;
                next = 1;
            }
            while (r != NULL)
            {
                if (r->adjVex1 == b)//即如果是b->?(?显然不是a)
                {
                    r = r->nextArc1;//r向下走
                    if (next == 0)
                        p = p->nextArc1;
                    else
                        p = p->nextArc2;
                    next = 0;//下次p要向下走才能找到r
                }
                else if (r->adjVex1 != a && r->adjVex2==b)//即如果是非a->b
                {
                    r = r->nextArc2;//r向右走
                    if (next == 0)
                        p = p->nextArc1;
                    else
                        p = p->nextArc2;
                    next = 1;//下次p要向右走才能找到r
                }
                else//r找到了那条边,即r==q
                {
                    if (next == 0)//p要向下走才能找到r
                        p->nextArc1 = r->nextArc2;
                    else//p要向右走才能找到r
                        p->nextArc2 = r->nextArc2;
                    delete q;//也就是delete r
                    break;//做完,跳出循环
                }
            }
        }
    }
     
     
    //插入边a<->b
    void NetWork::InsertEdge(int a, int b,int numK)
    {
        if (a == b || a < 0 || b < 0 || a >= size || b >= size)
        {
            cout << "输入不合法!" << endl;
            return;
        }
     
        int c;
        Arc *p,*q;
        if (a > b)//交换使得a<b
        {
            c = b;
            b = a;
            a = c;
        }
     
        //先检查是否存在a<->b,只要检查从a是否能找到a<->b
        p = arrayVex[a].firstArc;
        while (p != NULL)
        {
            if (p->adjVex1 == a && p->adjVex2 != b)//即a<->非b
                p = p->nextArc1;//向下走
            else if (p->adjVex2 == a)//即非b<->a
                p = p->nextArc2;//向右走
            else//找到了a<->b
                break;
        }
     
        if (p != NULL)//如果找到了
        {
            cout << "要插入的边已经存在" << endl;
            return;
        }
        else//如果没找到,做插入
        {
            q = new Arc(numK, a, b);//建立这个边
            q->nextArc1 = arrayVex[a].firstArc;//i的first边一定具有i,可以作为新边的next1
            q->nextArc2 = arrayVex[b].firstArc;//j的first边一定具有j,可以作为新边的next2
            arrayVex[a].firstArc = q;//头插这条边
            arrayVex[b].firstArc = q;//头插这条边
        }
    }
     
     
    //修改a<->b这条边的权值
    void NetWork::ChangeEdge(int a, int b, int numK)
    {
        if (a == b || a < 0 || b < 0 || a >= size || b >= size)
        {
            cout << "输入不合法!" << endl;
            return;
        }
     
        int c;
        Arc *p;
        if (a > b)//交换使得a<b
        {
            c = b;
            b = a;
            a = c;
        }
     
        //先检查是否存在a<->b,只要检查从a是否能找到a<->b
        p = arrayVex[a].firstArc;
        while (p != NULL)
        {
            if (p->adjVex1 == a && p->adjVex2 != b)//即a<->非b
                p = p->nextArc1;//向下走
            else if (p->adjVex2 == a)//即非b<->a
                p = p->nextArc2;//向右走
            else//找到了a<->b
                break;
        }
     
        if (p != NULL)//如果找到了
        {
            p->weight = numK;
        }
        else//如果没找到
        {
            cout << "要修改的边不存在" << endl;
        }
    }
     
    //显示
    void NetWork::Show()
    {
        Arc* p;
        cout << "无向图有" << size << "个点,分别为:";
        for (int i = 0; i < size; i++)
            cout << arrayVex[i].data << " ";
        cout << endl;
        for (int i = 0; i < size; i++)
        {
            cout<<"和" << arrayVex[i].data << "有关的边:";
            p = arrayVex[i].firstArc;
            while (p != NULL)
            {
                cout << arrayVex[p->adjVex1].data << "<--"<<p->weight<<"-->" << arrayVex[p->adjVex2].data << ",";
                if (p->adjVex1 == i)//判断向下还是向右走
                    p = p->nextArc1;
                else
                    p = p->nextArc2;
            }
            cout << endl;
        }
    }
     
    #endif

主程序lzh2.cpp

    // lzh2.cpp : 定义控制台应用程序的入口点。
    //
     
    #include "stdafx.h"
    #include "NetWork.h"
     
    int _tmain(int argc, _TCHAR* argv[])
    {
        char a[5] = { 'A', 'B', 'C', 'D', 'E' };
        int b[5][5] = {
            { 0, 1, 3, 0, 0 },
            { 1, 0, 0, 0, 1 },
            { 3, 0, 0, 2, 0 },
            { 0, 0, 2, 0, 9 },
            { 0, 1, 0, 9, 0 } };
        NetWork *k = new NetWork(5, a, (int**)b);
        k->Show();
     
        cout<<endl << "尝试删除2<->4即C<->E" << endl;
        k->DeleteEdge(2, 4);
        k->Show();
     
        cout <<endl<< "尝试删除0<->2即A<->C" << endl;
        k->DeleteEdge(2, 0);
        k->Show();
     
        cout << endl << "尝试插入2<->4即C<->E" << endl;
        k->InsertEdge(2, 4, 30);
        k->Show();
     
        cout <<endl<< "尝试删除1<->1即A<->A" << endl;
        k->DeleteEdge(1, 1);
        k->Show();
     
        cout <<endl<< "尝试删除2<->3即C<->D" << endl;
        k->DeleteEdge(3, 2);
        k->Show();
     
        cout << endl << "尝试插入2<->4即C<->E" << endl;
        k->InsertEdge(4, 2, 10);
        k->Show();
     
        cout << endl << "尝试修改3<->4即D<->E" << endl;
        k->ChangeEdge(3, 4, 20);
        k->Show();
     
        system("pause");
        return 0;
    }

运行结果:


最小生成树我还没写,明天想去动物园也不知道能不能去了
---------------------
版权声明:本文为CSDN博主「刘知昊」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/SHU15121856/article/details/71036309

posted @ 2019-08-09 20:50  天涯海角路  阅读(481)  评论(0)    收藏  举报