数据结构习题解析与实验指导第六章(图)课后算法设计题

1.分别以邻接矩阵和邻接表作为存储结构,实现以下图的基本操作:

(1)增加一个新顶点 v v v, InsertVex(G, v);

(2)删除顶点 v v v及其相关的边,DeleteVex(G, v);

(3)增加一条边<v, w>,InsertArc(G, v, w);

(4)删除一条边<v, w>, DeleteArc(G, v, w)。

  • 邻接矩阵(有向图)
#include <iostream>
using namespace std;

struct Graph {
    static const int MAX_V = 100;
    int weight[MAX_V][MAX_V];
    int vertex[MAX_V];
    int size = 0;
    Graph() {
        
    }
};

int locate(Graph& graph, int v) { //查找顶点位置
    for (int i = 0; i < graph.size; i++) {
        if (graph.vertex[i] == v) {
            return i;
        }
    }
    return -1;
}


void insertVetex(Graph& graph, int v) { 
    if (graph.size + 1 > graph.MAX_V ) {    ///如果顶点个数已满
        return;
    }

    if (locate(graph, v) != -1) {  //如果已经存在相同的顶点
        return;
    }

    graph.vertex[graph.size] = v;
    for (int i = 0; i <= graph.size; i++) {
        graph.weight[i][graph.size] = graph.weight[graph.size][i] = 0;
    }
    graph.size++;
}

void insertEdge(Graph& graph, int v, int w) {
    int i = locate(graph, v);
    int j = locate(graph, w);
    if (i != -1 && j != -1) {
        graph.weight[i][j] = 1;
    }
}

void deleteEdge(Graph& graph, int v, int w) {

    int i = locate(graph, v);
    int j = locate(graph, w);
    if (i != -1 && j != -1) {
        graph.weight[i][j] = 0;
    }
}

void deleteVetex(Graph& graph, int v) {
    int pos = locate(graph, v);
    int lst = graph.size - 1;
    if (pos != -1) {
         //与最后一个顶点交换
        int temp = graph.vertex[pos];
        graph.vertex[pos] = graph.vertex[lst];
        graph.vertex[lst] = temp;
        for (int i = 0; i < graph.size; i++) {
            int t = graph.weight[pos][i];
            graph.weight[pos][i] = graph.weight[lst][i];
            graph.weight[lst][i] = t;
        }
        for (int i = 0; i < graph.size; i++) {
            int t = graph.weight[i][pos];
            graph.weight[i][pos] = graph.weight[i][lst];
            graph.weight[i][lst] = t;
        }
        //删除最后一个顶点
        graph.size--;
    }
}


void display(Graph& graph){
    cout << "vetices: ";
    for (int i = 0; i < graph.size; i++) {
        cout << graph.vertex[i] << " ";
    }
    cout << endl;
    cout << "edges: " << endl;
    for (int i = 0; i < graph.size; i++) {
        for (int j = 0; j < graph.size; j++) {
            cout << graph.weight[i][j] << " ";
        }
        cout << endl;
    }
}

int main() {
    Graph graph;
    insertVetex(graph, 4);
    insertVetex(graph, 5);
    insertEdge(graph, 5, 4);
    insertVetex(graph, 5);
    insertVetex(graph, 6);
    insertVetex(graph, 7);
    insertVetex(graph, 8);
    insertEdge(graph, 4, 6);
    insertEdge(graph, 3, 6);
    insertEdge(graph, 7, 7);
    insertEdge(graph, 7, 8);
    insertEdge(graph, 8, 7);
    display(graph);
    deleteEdge(graph, 4, 6);
    display(graph);
    deleteVetex(graph, 5);
    display(graph);
    return 0;
}

在这里插入图片描述

  • 邻接表(有向图)
#include <iostream>
using namespace std;

struct Node {
    int name;            //结点的id, 其实可以用string替代
    int weight;          //边或结点的权重,在此例用没有用到
    Node* next_e;        //下一条边
    Node* next_v;        //下一个顶点
    Node(int name = 0, int weight = 0, Node* next_e = 0, Node* next_v = 0) :
        name(name),
        weight(weight),
        next_e(next_e),
        next_v(next_v)
    {
        
    }
};

Node* locate(Node& graph, int v) {   //根据id查找顶点
    Node* pos = graph.next_v;
    while (pos != 0)
    {
        if (pos->name == v) {
            return pos;
        }
        pos = pos->next_v;
    }
    return 0;
}

void insertVertex(Node& graph, int v) {
    if (locate(graph, v) == 0) {
        Node* node = &graph;
        while (node->next_v != 0)         //这里使用后插法
        {
            node = node->next_v;
        }
        node->next_v = new Node(v);
    }
}

void deleteVertex(Node& graph, int v) {
    Node* node = &graph;
    while (node->next_v != 0)
    {
        if (node->next_v->name == v) {
            Node* n = node->next_v;
            while (n->next_e != 0)
            {
                Node* t = n->next_e;
                n->next_e = n->next_e->next_e;
                delete t;
            }
            Node* temp = node->next_v;;
            node->next_v = node->next_v->next_v;
            delete temp;
            return;
        }
        node = node->next_v;
    }
}

void insertEdge(Node& graph, int v, int w) {
    Node* node_v = locate(graph, v);
    Node* node_w = locate(graph, w);
    if (node_v != 0 && node_w != 0) {
        Node* node = node_v;
        while (node->next_e != 0) {
            if (node->next_e->next_v->name == w) {
                return;
            }
            node = node->next_e;
        }
        node->next_e = new Node(0,0,0, node_w);
    }
}

void deleteEdge(Node& graph, int v, int w) {
    Node* node_v = locate(graph, v);
    Node* node_w = locate(graph, w);
    if (node_v != 0 && node_w != 0) {
        Node* node = node_v;
        while (node->next_e != 0)
        {
            if (node->next_e->next_v == node_w) {
                Node* temp = node->next_e;
                node->next_e = node->next_e->next_e;
                delete temp;
            }
            node = node->next_e;
        }
    }
}

void release(Node& graph) {
    Node* node = &graph;
    while (node->next_v != 0)
    {
        Node* n = node->next_v;
        while (n->next_e != 0)
        {
            Node* t = n->next_e;
            n->next_e = n->next_e->next_e;
            delete t;
        }
        Node* temp = node->next_v;;
        node->next_v = node->next_v->next_v;
        delete temp;
    }
    graph.next_v = 0;
}


void display(Node& graph) {
    Node* node = graph.next_v;
    while (node != 0)
    {
        cout << node->name << ": ";
        Node* n = node->next_e;
        while (n != 0)
        {
            cout << n->next_v->name << " ";
            n = n->next_e;
        }
        cout << endl;
        node = node->next_v;
    }
}

/*int size(Node& graph) {
    Node* node = graph.next_v;
    int count = 0;
    while (node != 0)
    {
        count++;
        node = node->next_v;
    }
    return count;
}
*/
/*int getEdgeWeight(Node& graph, int v, int w) {
    Node* node_v = locate(graph, v);
    Node* node_w = locate(graph, w);
    if (node_v != 0 && node_w != 0) {
        Node* node = node_v->next_e;
        while (node != 0) {
            if (node->next_v == node_w) {
                return node->weight;
            }
            node = node->next_e;
        }
    }
    return 0;
}*/

int main() {
    Node graph;
    insertVertex(graph, 5);
    insertVertex(graph, 4);
    insertVertex(graph, 3);
    insertVertex(graph, 2);
    insertVertex(graph, 1);
    insertEdge(graph, 1, 2);
    insertEdge(graph, 1, 3);
    insertEdge(graph, 4, 5);
    insertEdge(graph, 4, 1);
    insertEdge(graph, 4, 3);
    display(graph);
    deleteEdge(graph, 4, 1);
    deleteEdge(graph, 4, 1);
    cout << "-----------" << endl;
    display(graph);
    deleteVertex(graph, 4);
    cout << "-----------" << endl;
    display(graph);
    release(graph);
    return 0;
}

在这里插入图片描述

2.一个连通图采用邻接表作为存储结构,设计一个算法,实现从顶点 v v v出发的深度优先遍历的非递归过程。

为了方便,这里使用邻接矩阵

#include <iostream>
#include <stack>
#include <set>
#include "graph.hpp"
using namespace std;

void DFS(Graph& graph, int v) {
	int pos = locate(graph, v);
	if (pos != -1) {
		stack<int> opened;
		set<int> closed;
		opened.push(pos);
		while (!opened.empty())
		{
			int index = opened.top(); opened.pop();
			if (closed.find(index) == closed.end()) {  //!注意判断的位置
				cout << graph.vertex[index] << " ";
				//添加子结点
				for (int i = 0; i < graph.size; i++) {
					if (graph.weight[index][i] != 0) {
						opened.push(i);
					}
				}
				closed.insert(index);
			}
		}
	}
}


int main() {
	Graph graph;
	insertVetex(graph, 0);
	insertVetex(graph, 1);
	insertVetex(graph, 2);
	insertVetex(graph, 3);
	insertVetex(graph, 4);
	insertEdge(graph, 0, 1);
	insertEdge(graph, 0, 2);
	insertEdge(graph, 1, 0);
	insertEdge(graph, 1, 3);
	insertEdge(graph, 1, 4);
	insertEdge(graph, 2, 0);
	insertEdge(graph, 2, 3);
	insertEdge(graph, 3, 1);
	insertEdge(graph, 3, 2);
	insertEdge(graph, 3, 4);
	insertEdge(graph, 4, 1);
	insertEdge(graph, 4, 3);
	display(graph);
	cout << "search result: ";
	DFS(graph, 1);
	return 0;
}

在这里插入图片描述

在这里插入图片描述

3.设计一个算法,求图 G G G中距离顶点 v v v的最短路径长度最大的一个顶点,设 v v v可达其余各个顶点。

#include <iostream>
#include "graph.hpp"
#include <queue>
#include <set>
using namespace std;
const int MAX_V = 100;

/*
	Dijkstra本质是广度优先搜索。
*/
int whichNodeCanLeadToMaxMinPath(Node& graph, int v) {
	if (locate(graph, v) == 0)  return 0;
	int node_nums = size(graph);
	int min_length[MAX_V];
	int pre_nodes[MAX_V];
	//初始化(...)
	min_length[0] = 0;
	for (int i = 1; i <= node_nums; i++) {
		int length = getEdgeWeight(graph, v, i);  
		min_length[i] = length == 0 ? INT32_MAX : length;
		pre_nodes[i] = v;
	}
	min_length[v] = 0;

	//算法开始
	queue<int> q;
	set<int> closed;
	q.push(v);
	while (!q.empty())
	{
		int index = q.front(); q.pop(); closed.insert(index);
		Node* node = locate(graph, index)->next_e;
		while (node != 0) {
			int node_name = node->next_v->name;
			//这一步可以覆盖到所有的edge
			int fresh_length = min_length[index] + getEdgeWeight(graph, index, node_name);
			if (min_length[node_name] > fresh_length) {
				pre_nodes[node_name] = index;
				min_length[node_name] = fresh_length;
				if (closed.find(node_name) != closed.end()) {
					closed.erase(node_name);
				}
			}
			if (closed.find(node_name) == closed.end()) {
				q.push(node_name);
			}
			node = node->next_e;
		}
	}

	//输出最大值
	int max_path = 0;
	int max_vertext = 0;
	for (int i = 1; i <= node_nums; i++) {
		if (min_length[i] > max_path) {
			max_path = min_length[i];
			max_vertext = i;
		}
	}
	return max_vertext;
}


int main() {

	Node graph;
	insertVertex(graph, 1);
	insertVertex(graph, 2);
	insertVertex(graph, 3);
	insertVertex(graph, 4);
	insertVertex(graph, 5);
	insertVertex(graph, 6);
	insertEdge(graph, 1, 2, 15);   // 节点1->2的权重是2,下同
	insertEdge(graph, 1, 3, 2);
	insertEdge(graph, 2, 4, 10);
	insertEdge(graph, 2, 5, 19);
	insertEdge(graph, 3, 2, 4);
	insertEdge(graph, 3, 5, 11);
	insertEdge(graph, 4, 6, 6);
	insertEdge(graph, 5, 6, 5);
	insertEdge(graph, 2, 1, 15);   // 节点2->1的权重是2,下同
	insertEdge(graph, 3, 1, 2);
	insertEdge(graph, 4, 2, 10);
	insertEdge(graph, 5, 2, 19);
	insertEdge(graph, 2, 3, 4);
	insertEdge(graph, 5, 3, 11);
	insertEdge(graph, 6, 4, 6);
	insertEdge(graph, 6, 5, 5);
	cout << whichNodeCanLeadToMaxMinPath(graph, 1) << endl;
	release(graph);
	return 0;
}

在这里插入图片描述
在这里插入图片描述

4.试基于图的深度优先搜索策略写一算法,判别以邻接表方式存储的的有向图中是否存在由顶点 v i v_i vi v j v_j vj的路径 ( v i ≠ v j ) (v_i\neq v_j) (vi=vj)

提示:深度优先搜索有递归形式,也有非递归形式。这里采用非递归形式。

#include <iostream>
#include <stack>
#include <set>
#include "graph.hpp"
using namespace std;

bool doesHasAPath(Node& graph, int v, int w) {
	Node* node_v = locate(graph, v);
	Node* node_w = locate(graph, w);
	if (node_v != 0 && node_w != 0) {
		stack<Node*> s;
		set<Node*> closed;
		s.push(node_v);
		while (!s.empty()) {
			Node* node = s.top(); s.pop();
			if (closed.find(node) == closed.end()) {
				closed.insert(node);
				Node* n = node->next_e;
				while (n != 0)
				{
					if (n->next_v == node_w) {
						return true;
					}

					s.push(n->next_v);
					n = n->next_e;
				}
			}
		}
	}
	return false;
}

int main() {
	Node graph;
	insertVertex(graph, 1);
	insertVertex(graph, 2);
	insertVertex(graph, 3);
	insertVertex(graph, 4);
	insertVertex(graph, 5);
	insertVertex(graph, 6);
	insertVertex(graph, 7);
	insertEdge(graph, 1, 2);
	insertEdge(graph, 1, 3);
	insertEdge(graph, 2, 4);
	insertEdge(graph, 2, 5);
	insertEdge(graph, 3, 2);
	insertEdge(graph, 3, 5);
	insertEdge(graph, 4, 6);
	insertEdge(graph, 5, 6);
	cout << "result(2, 7): " << doesHasAPath(graph, 2, 6) << endl;
	cout << "result(1, 7): " <<  doesHasAPath(graph, 1, 7) << endl;
	release(graph);
	return 0;
}

同第三题图。
在这里插入图片描述
5.采用邻接表存储结构,编写一个算法,判别无向图中任意给定的两个顶点(假定为 A 和 B A和B AB)之间是否存在一条长度为 k k k的简章路径。

提示:如果是邻接矩阵,则可以使用矩阵幂的方法,但是这里是邻接表
提示:可以将此问题分解为 “是否存在长度为k-1的从顶点 a a a到顶点 B B B路径”的子问题
其中 a a a是结点 A A A可以一步到达的结点。

#include <iostream>
#include "graph.hpp"
using namespace std;

bool doesHasAPath(Node& graph, int v, int w, int k) {
	if (v == w && k == 0) {
		return true;
	}
	Node* node_v = locate(graph, v);   //顶点A
	Node* node_w = locate(graph, w);   //顶点B
	if (node_v != 0 && node_w != 0) {
		Node* n = node_v->next_e;
		while (n != 0)
		{
			if (doesHasAPath(graph, n->next_v->name, w, k - 1)) {
				return true;
			}
			n = n->next_e;
		}

	}
	return false;
}

int main() {
	Node graph;
	insertVertex(graph, 1);
	insertVertex(graph, 2);
	insertVertex(graph, 3);
	insertVertex(graph, 4);
	insertVertex(graph, 5);
	insertVertex(graph, 6);
	insertVertex(graph, 7);
	insertEdge(graph, 1, 2);
	insertEdge(graph, 1, 3);
	insertEdge(graph, 2, 4);
	insertEdge(graph, 2, 5);
	insertEdge(graph, 3, 2);
	insertEdge(graph, 3, 5);
	insertEdge(graph, 4, 6);
	insertEdge(graph, 5, 6);
	cout << "result: " << doesHasAPath(graph, 3, 5, 1) << endl;
	cout << "result: " << doesHasAPath(graph, 3, 5, 2) << endl;
	cout << "result: " << doesHasAPath(graph, 3, 5, 3) << endl;
	release(graph);
	return 0;
}

同第三题图。
在这里插入图片描述

  • 19
    点赞
  • 128
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值