ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

数据结构2021温习篇——图(7b)_邻接表

2021-09-21 17:30:54  阅读:172  来源: 互联网

标签:7b int dest link 2021 NodeTable 温习 adj numVertices


前言

上节我们接触了邻接矩阵存储图的结点之间的关系,但是当图的边特别稀疏时,邻接矩阵就有很多 0 元素,造成空间极大的浪费。本节接触的邻接表可以解决这个问题。



解析



完整代码

//
// Created by Dell on 2019/12/15.
//

#include<iostream>
#include<queue>
#include <iomanip>

using namespace std;

const int maxWeight = 9999;
const int DefaultSize = 30;

template<class T, class E>
struct Edge {
    int dest;    //边的另一个顶点位置
    E cost;            //边上的权值
    Edge<T, E> *link;

    Edge() {}

    Edge(int num, E weight) : dest(num), cost(weight), link(0) {}

    bool operator!=(Edge<T, E> &R) const {
        return (dest != R.dest) ? true : false;
    }
};

template<class T, class E>
struct Vertex {
    T data;
    Edge<T, E> *adj;
};

template<class T, class E>
class Graphlnk {
public:
    Graphlnk(int sz = DefaultSize);

    ~Graphlnk();

    T getValue(int i) {
        return (i >= 0 && i < numVertices) ? NodeTable[i].data : 0;
    }

    E getWeight(int v1, int v2);

    bool insertVertex(const T &vertex);

    bool removeVertex(int v);

    bool insertEdge(int v1, int v2, E weight);

    bool removeEdge(int v1, int v2);

    int getFirstNeighbor(int v);

    int getNextNeighbor(int v, int w);

    void CreateNodeTable();

    void PrintDest(); //把邻接表的样子输出来
    void PrintMatrix(); //把邻接矩阵的样子输出来

    //遍历
    void DFS();

    void BFS();


private:
    int numVertices;
    int maxVertices;
    int numEdges;
    bool *visited; //用于dfs和bfs
    //结点表
    Vertex<T, E> *NodeTable;


    int getVertexPos(const T vertex) {
        for (int i = 0; i < numVertices; i++) {
            if (NodeTable[i].data == vertex)
                return i;
        }
        return -1;
    }

    void DFS(int v);
};


template<class T, class E>
Graphlnk<T, E>::Graphlnk(int sz) {
    maxVertices = sz;
    numVertices = 0;
    numEdges = 0;
    visited = nullptr;

    NodeTable = new Vertex<T, E>[maxVertices];
    if (NodeTable == nullptr) {
        cerr << "分存分配错误" << endl;
        exit(1);
    }
    for (int i = 0; i < maxVertices; i++) {
        NodeTable[i].adj = nullptr;
    }
}


template<class T, class E>
Graphlnk<T, E>::~Graphlnk() {
    for (int i = 0; i < numVertices; i++) {
        Edge<T, E> *p = NodeTable[i].adj;
        while (p != nullptr) {
            NodeTable[i].adj = p->link;
            delete p;
            p = NodeTable[i].adj;
        }
    }
    delete[]NodeTable;
}


template<class T, class E>
E Graphlnk<T, E>::getWeight(int v1, int v2) {
    if (v1 >= 0 && v1 < numVertices && v2 >= 0 && v2 < numVertices) {
        Edge<T, E> *p = NodeTable[v1].adj;
        while (p != 0 && p->dest != v2) {
            p = p->link;
        }
        if (p != 0)
            return p->cost;  //找到此边,返回权值
    }
    return 0;
}


template<class T, class E>
bool Graphlnk<T, E>::insertVertex(const T &vertex) {
    if (numVertices == maxVertices)
        return false;
    NodeTable[numVertices].data = vertex;
    numVertices++;
    return true;
}


template<class T, class E>
bool Graphlnk<T, E>::removeVertex(int v) {
    if (numVertices == 1 || v < 0 || v >= numVertices)
        return false;
    Edge<T, E> *p, *s, *t;
    int i, k;
    while (NodeTable[v].adj != 0) {
        p = NodeTable[v].adj;
        k = p->dest;
        s = NodeTable[k].adj;  //找对称存放的边结点
        t = nullptr;                 //t 是 s的前一个指针,跟着s走,方便后续删除结点
        while (s != 0 && s->dest != v) {
            t = s;
            s = s->link;
        }
        if (s != nullptr) {
            if (t == nullptr)
                NodeTable[k].adj = s->link;
            else
                t->link = s->link;
            delete s;
        }

        NodeTable[v].adj = p->link;
        delete p;
        numEdges--;
    }

    numVertices--;   //图的顶点数减1
    NodeTable[v].data = NodeTable[numVertices].data;  //用最后一个结点来填补
    p = NodeTable[v].adj = NodeTable[numVertices].adj;
    while (p != 0) {
        s = NodeTable[p->dest].adj;
        while (s != nullptr) {
            if (s->dest == numVertices) {
                s->dest = v;
                break;
            } else
                s = s->link;
        }
        ///
        //书中没有这句代码
        p = p->link;
        //
    }

    //问题:把最后一个结点拿来填补,那么其他顶点有连接到numVertices的怎么办
    return true;
}


template<class T, class E>
bool Graphlnk<T, E>::insertEdge(int v1, int v2, E weight) {
    if (v1 >= 0 && v1 < numVertices && v2 >= 0 && v2 < numVertices) {
        Edge<T, E> *q, *p = NodeTable[v1].adj;
        while (p != nullptr && p->dest != v2)
            p = p->link;
        if (p != nullptr)
            return false; //已有此边,否则p此时必为0
        p = new Edge<T, E>;
        q = new Edge<T, E>;

        p->dest = v2;
        p->cost = weight;
        q->dest = v1;
        q->cost = weight;

        //头插入v1的边链表
        p->link = NodeTable[v1].adj;
        NodeTable[v1].adj = p;

        //头插入v2的边链表
        q->link = NodeTable[v2].adj;
        NodeTable[v2].adj = q;


        numEdges++;
        return true;
    }
    return false;
}


template<class T, class E>
bool Graphlnk<T, E>::removeEdge(int v1, int v2) {
    if (v1 >= 0 && v1 < numVertices && v2 >= 0 && v2 < numVertices) {
        Edge<T, E> *p = NodeTable[v1].adj;
        Edge<T, E> *q = nullptr, *s = p; //q是p上一个指针,方便删除操作

        while (p != nullptr && p->dest != v2) {
            q = p;
            p = p->link;
        }
        if (p != nullptr) {
            if (p == s)    //要删的结点被头指针指着
                NodeTable[v1].adj = p->link;
            else  //此时不是头指针指着的结点q必然不空
                q->link = p->link;
            delete p;
        } else
            return false; // p == 0,没找到这条边

        p = NodeTable[v2].adj;  //v2对应边链表中删除
        q = nullptr;
        s = p;
        while (p->dest != v1) {
            q = p;
            p = p->link;
        }
        if (p == s)   //要删的结点被头指针指着
            NodeTable[v2].adj = p->link;
        else
            q->link = p->link;
        delete p;
        return true;
    }
    return false;
}


template<class T, class E>
int Graphlnk<T, E>::getFirstNeighbor(int v) {
    if (v >= 0 && v < numVertices) {
        Edge<T, E> *p = NodeTable[v].adj;
        if (p != 0)
            return p->dest;//存在,返回第一个临界点
    }
    return -1;
}


template<class T, class E>
int Graphlnk<T, E>::getNextNeighbor(int v, int w) {
    if (v >= 0 && v < numVertices) {
        Edge<T, E> *p = NodeTable[v].adj;
        while (p != 0 && p->dest != w)
            p = p->link;
        if (p != 0 && p->link != 0)
            return p->link->dest;
    }
    return -1;  //-1代表不存在
}


//建立邻接表结构
template<class T, class E>
void Graphlnk<T, E>::CreateNodeTable() {
    int n, i, j, m;
    Edge<T, E> *p;

    cout << "请输入要创建的结点个数" << endl;
    cin >> n; //结点个数
    if (n > maxVertices) {
        cout << "超过最大结点数" << endl;
        return;
    }
    numVertices = n;
    for (i = 0; i < n; i++) {
        NodeTable[i].adj = 0;  //预设为空链
        cout << "请输入编号为 " << i << "的结点的值: ";
        cin >> NodeTable[i].data;

        cout << "请输入" << NodeTable[i].data << "的邻接点个数:";
        cin >> m;
        cout << "请输入它的 " << m << "个邻接点(相邻顶点编号 权重)" << endl;
        for (j = 0; j < m; j++) {
            p = new Edge<T, E>;
            cin >> p->dest;
            cin >> p->cost;
            //头插入建链
            p->link = NodeTable[i].adj;
            NodeTable[i].adj = p;
        }
    }
}


template<class T, class E>
void Graphlnk<T, E>::DFS(int v) {
    visited[v] = true;
    cout << NodeTable[v].data << " ";
    Edge<T, E> *p = NodeTable[v].adj;
    while (p != 0) {
        if (!visited[p->dest])
            DFS(p->dest);
        p = p->link;
    }
}


template<class T, class E>
void Graphlnk<T, E>::DFS() {
    visited = new bool[numVertices];
    for (int i = 0; i < numVertices; i++)
        visited[i] = false;
    int v0;
    cout << "请输入深度优先遍历的出发点编号:0至 " << numVertices - 1 << endl;
    cin >> v0;
    DFS(v0);
    cout << endl << endl;
}


template<class T, class E>
void Graphlnk<T, E>::BFS() {
    visited = new bool[numVertices];
    for (int i = 0; i < numVertices; i++)
        visited[i] = false;
    int v;
    Edge<T, E> *p;
    queue<int> Q;
    cout << "请输入广度优先遍历的出发点编号:0至 " << numVertices - 1 << endl;
    cin >> v;
    Q.push(v);

    while (!Q.empty()) {
        v = Q.front();
        Q.pop();
        if (!visited[v]) {
            visited[v] = true;
            cout << NodeTable[v].data << " ";
            p = NodeTable[v].adj;
            while (p != 0) {
                if (!visited[p->dest])
                    Q.push(p->dest);
                p = p->link;
            }
        }
    }
    cout << endl << endl;
}


template<class T, class E>
void Graphlnk<T, E>::PrintDest() {
    Edge<T, E> *p;
    for (int i = 0; i < numVertices; i++) {
        cout << "-----与" << "编号为 " << i << " ,值为 ";
        cout << NodeTable[i].data << " 相连的点 : 顶点值(编号,权值)" << endl;
        p = NodeTable[i].adj;
        while (p != 0) {
            cout << NodeTable[p->dest].data;
            cout << "( " << p->dest << ", " << p->cost << ")" << " ";
            p = p->link;
        }
        cout << endl << endl;
    }
    cout << endl << endl;
}

template<class T, class E>
void Graphlnk<T, E>::PrintMatrix() {
    int i, j;
    E matrix[numVertices][numVertices];

    for (i = 0; i < numVertices; i++)
        for (j = 0; j < numVertices; j++)
            matrix[i][j] = (i == j) ? 0 : maxWeight;


    Edge<T, E> *p;
    for (i = 0; i < numVertices; i++) {
        p = NodeTable[i].adj;
        while (p != nullptr) {
            matrix[i][p->dest] = p->cost;
            p = p->link;
        }
    }

    cout << "图的邻接表用“邻接矩阵”形式表示: " << endl;
    cout << setw(8) << " ";
    for (i = 0; i < numVertices; i++)
        cout << setw(8) << NodeTable[i].data;
    cout << endl;
    for (i = 0; i < numVertices; i++) {
        cout << setw(8) << NodeTable[i].data;
        for (j = 0; j < numVertices; j++) {
            cout << setw(8) << matrix[i][j];
        }
        cout << endl;
    }
    cout << endl << endl;
}


int main() {
    Graphlnk<char, double> a;
    //a.CreateNodeTable();

    //把图先建立起来

    //先插入顶点
    a.insertVertex('a');
    a.insertVertex('b');
    a.insertVertex('c');
    a.insertVertex('d');
    a.insertVertex('e');
    a.insertVertex('f');
    a.insertVertex('g');


    //插入他们之间的边
    a.insertEdge(0, 1, 3.1);
    a.insertEdge(0, 2, 2.6);
    a.insertEdge(0, 4, 2.7);

    a.insertEdge(1, 3, 5.4);
    a.insertEdge(1, 5, 4.5);

    a.insertEdge(4, 5, 3.8);
    a.insertEdge(5, 6, 4.2);

    a.PrintDest();

//    a.PrintMatrix();



    cout << "删除带点e之后" << endl;

    a.removeVertex(4);
    a.PrintDest();

    cout << endl << "删除边bf后..." << endl;
    a.removeEdge(1, 5);
    a.PrintDest();


    a.BFS();
    a.DFS();
/*
	cout << endl << endl;
	cout << "a广度优先遍历" << endl;
	a.BFS();
	cout << endl << endl;
	cout << "a深度优先遍历" << endl;
	a.DFS();
*/
    cout << endl;
}

标签:7b,int,dest,link,2021,NodeTable,温习,adj,numVertices
来源: https://blog.csdn.net/weixin_43850253/article/details/120403541

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有