20162321-王彪-实验四总结

2024-02-03 15:40
文章标签 总结 实验 20162321 王彪

本文主要是介绍20162321-王彪-实验四总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

写在前面:程序设计与数据结构到目前为止的大题成绩出来了,悄悄咪咪地看了一下,发现实验得分和实验博客得分都不高,说实话有点尴尬。可能是在提交实验作业时过于简单,提交不完全,而实验博客也不是太详细,导致分数不高。所以这最后一次实验博客,一定要仔细并且详尽讲述本次实验的理解和思路历程。

实验四-图的实现与应用-1

用邻接矩阵实现无向图(边和顶点都要保存),实现在包含添加和删除结点的方法,添加和删除边的方法,size(),isEmpty(),广度优先迭代器,深度优先迭代器,给出伪代码,产品代码,测试代码(不少于5条测试),上方提交代码链接,附件提交测试截图

邻接矩阵
  • 用二维数组来实现矩阵,邻接矩阵的长度等于顶点个数,邻接矩阵(A,B),其中A,B表示的是顶点在顶点集合中的位置。而邻接矩阵(二维数组)的每个位置则表示图的边(带权图:每个位置存入数字代表权值,没有边则用-1或0;非带权图:每个位置存入布尔值来表示两个顶点是否连接)
  • 无向图和有向图的邻接矩阵:
    无向图和有向图的邻接矩阵有着些许差别(我们以顶点:A,B,C,D,E为例)
    1065456-20171125162906953-1349059063.png

我们可以看到无向图的邻接矩阵是对称,这是因为在无向图中(A,B)所代表的边的含义与(B,A)所代表的边的含义完全一样,而有向图则不同。
1065456-20171125164626531-862710103.png

UML类图

1065456-20171125171715421-323214952.png

伪代码
    属性{链表(保存顶点)二维数组(邻接矩阵)边的数量
} 构造函数(int n){根据n来初始化链表和二维数组
}插入顶点(T item){链表中加入item
}插入边(int x,int y,int weight){二维数组[x][y] = weight;边的数量增加
}删除边(intx ,int y){二维数组[x][y] = 0 or -1边的数量减少
}删除顶点(T item){调用帮助删除边函数顶点链表移除item
}帮助删除边(T item){得到item在顶点链表中位置新建二维数组,n1 = 原二维数组长度-1for(int i=0;i<原二维数组长度;i++){如果 i = item的位置,则继续循环如果 i < item的位置,则建立循环(int j=0;j<n;j++){如果j=item的位置,则继续循环;如果j<item的位置,则新数组(i,j)位置上的值=原数组(i,j)位置上的值;如果j>item的位置,则新数组(i,j-1)位置上的值 = 原数组(i,j)位置上的值;}如果i > item的位置,则建立循环(int j=0;j<n;j++){如果j=item的位置,则继续循环如果j<item的位置,则新数组(i-1,j)位置上的值=原数组(i,j)位置上的值;如果j>item的位置,则新数组(i-1,j-1)位置上的值=原数组(i,j)位置上的值;}将新数组指向原数组}    是否为空{如果顶点表的长度为0,则返回正确;}
}
  • 关于深度优先和广度优先遍历的实现

    书上给了两个方法,但由于只是片面的给了单独的方法,所以以下是我对书中的代码的注释和改动。

    public Iterator<T> iteratorBFS(int startIndex){//用来保存从队列中出队的数,此数是要加入迭代器中的顶点在顶点集中的下标int currentVertex;//该队列用来存储顶点在顶点集中的位置LinkedQueue<Integer> traversalQueue = new LinkedQueue<>();//该迭代器保存的是顶点元素ArrayIterator<T> iter = new ArrayIterator<>();/* insexIsValid(int n)** 书中并没有给出indexIsValid的具体实现方式** 根据命名推断:index是否有效,所以该方法的目的是判断参数startIndex是否是有效值**public  boolean insexIsValid(int index){**        if (0<index&&index<myList.size()){**                return true;**        }**        else return false;**    }  */           if (!indexIsValid(startIndex))return iter;//visited数组帮助判断顶点是否被访问boolean[] visited = new boolean[myList.size()];//利用循环现将visited全部标记为未访问for (int vertexIndex=0;vertexIndex<myList.size();vertexIndex++){visited[vertexIndex]= false;}//初始化操作:将参数startIndex入队,并标记为已访问traversalQueue.enqueue(startIndex);visited[startIndex] =  true;//while循环,只要队列不为空就继续循环while (!traversalQueue.isEmpty()){//将队列中第一个元素出队,赋值给currentVertexcurrentVertex = traversalQueue.dequeue();//迭代器加入顶点集中currentVertex位置的元素iter.add(myList.get(currentVertex));//利用循环遍历与currentVertex位置的顶点相连的所以顶点for (int vertexIndex=0;vertexIndex<myList.size();vertexIndex++){if (edges[currentVertex][vertexIndex]>0&&!visited[vertexIndex]){traversalQueue.enqueue(vertexIndex);visited[vertexIndex] = true;}}}return iter;}

实验一:代码

实验四-图的实现与应用-2

用十字链表实现无向图(边和顶点都要保存),实现在包含添加和删除结点的方法,添加和删除边的方法,size(),isEmpty(),广度优先迭代器,深度优先迭代器,给出伪代码,产品代码,测试代码(不少于5条测试),上方提交代码链接,附件提交测试截图

十字链表
  • 实验二是比较难的,原因就在于上课时老师对十字链表的讲述也不是很详细,自身对十字链表的理解也不够。导致在上手时完全不知道该怎么做,网上查找了很多资料,一开始也是有点云里雾里的。
  • 十字链表比较难理解的地方是在于十字这一概念:十字链表是为了便于求得图中顶点的度(出度和入度)而提出来的。它是综合邻接表和逆邻接表形式的一种链式存储结构。
  • 既然是链表那么就得构建结点类,十字链表中有有两种结点结构:边结点结构,顶点结构
  • 顶点结构
    1065456-20171126112146656-1618349742.png
  • 弧结构
    1065456-20171126133507875-1615268708.png
  • 接下来,就要弄清楚十字链表的具体实现,以下是我用ProcessOn画的理解图,本博客中所有图就出自于我的ProcessOn
    1065456-20171126145129984-928848720.png

  • 我个人理解为:每个顶点结点都有两个链表,正如上图的蓝色和绿色标记的,以结点B为例:蓝色的链表表示以B为弧尾的边的集合即进入B的边的集合;绿色的链表表示以B为弧头的边的集合(从B出去的边)

    UML类图

    1065456-20171126153313578-561273845.png

    代码解析
  • 插入边:insertEdge(int tail,int head),结合前面的图我们知道,如果要插入一条边,那么这条边对应的头结点的FirstIn表就得加入此条边,同时这条边对应的尾节点的FirstOut表就得也得加入此条边。
    1065456-20171126160302593-621534488.png

public void insertEdge(int tail,int head){EdgeNode<T> myEdge = new EdgeNode(tail,head,null,null);VertexNode<T> tailNode = NodeList.get(tail);VertexNode<T> headNode = NodeList.get(head);if (tailNode.firstOut==null){tailNode.firstOut = myEdge;}else {tailNode.firstOut.insertTail(myEdge);}if (headNode.firstIn==null){headNode.firstIn = myEdge;}else {headNode.firstIn.insertHead(myEdge);}}
  • 删除边
public void removeEdge(int tail,int head){EdgeNode myEdge = NodeList.get(tail).firstOut;if (myEdge.tailVex==tail&&myEdge.headVex==head){if (!(myEdge.tailLink==null&&myEdge.headLink==null)){NodeList.get(tail).firstOut = myEdge.tailLink;}else NodeList.get(tail).firstOut=null;}else {myEdge = findBeforeEdge(tail,head);myEdge.tailLink = null;}}
public EdgeNode findBeforeEdge(int tail,int head){EdgeNode myEdge = null;if (NodeList.get(tail).firstOut!=null){myEdge = NodeList.get(tail).firstOut;}else return null;while (myEdge.tailLink!=null){if (!(myEdge.tailLink.tailVex==tail&&myEdge.tailLink.headVex==head)) {myEdge = myEdge.tailLink;}elsebreak;}return myEdge;}

实验二:代码

实验四-图的实现与应用-3

实现PP19.9,给出伪代码,产品代码,测试代码(不少于5条测试),上方提交代码链接,附件提交测试截图

PP19.9

创建计算机网络路由系统,输入网络中点到点的线路,以及每条线路使用的费用,系统输出网络中各点之间最便宜的路径,指出不相通的所有位置

  • 主要实现原理就是查找两个顶点之间的最短路径;其余实现则没有区别,具体是带权的无向图
关键代码
public void vertexShortestDist(){for (int i=0;i<myList.size();i++){helpShortestDist(i);}}public void helpShortestDist(int index){for (int i=0;i<myList.size();i++){for (int j=0;j<myList.size();j++){if (edges[i][index]!=0&&edges[index][j]!=0){if (edges[i][j]==0){edges[i][j]=edges[i][index]+edges[index][j];}else if (edges[i][j]>edges[i][index]+edges[index][j])edges[i][j]=edges[i][index]+edges[index][j];}}}}
  • 这里一次以每个顶点为中间点对整个二维数组进行加工,但关键是每次添加一条边时都调用此方法。
  • 该代码的伪代码来自于蓝墨云班课上的PPT163:各顶点对间最短路径算法,略有不同的是:初始化矩阵的方式不同,PPT中直接出示话了矩阵,而我的做法则是在添加边时调用函数,致使每次添加边后,矩阵都会变化,使其始终保持储存最小路径
public void inserEdge(int a,int b,int weigth){if (!insexIsValid(a)||!insexIsValid(b)){throw new NumberFormatException("Wrong number");}edges[a][b] = weigth;vertexShortestDist();NumEdges++;}
  • 实现原理很简单:例如以A为中间点,判断BC之间的路径时,比较Node[B][C]?Node[B][A]+Node[A][C]的大小关系,若<和=则Node[B][C]的值不做更改,反之Node[B][C]=Node[B][A]+Node[A][C]

    实验三:代码

转载于:https://www.cnblogs.com/wbiao21/p/7892713.html

这篇关于20162321-王彪-实验四总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/674626

相关文章

java常见报错及解决方案总结

《java常见报错及解决方案总结》:本文主要介绍Java编程中常见错误类型及示例,包括语法错误、空指针异常、数组下标越界、类型转换异常、文件未找到异常、除以零异常、非法线程操作异常、方法未定义异常... 目录1. 语法错误 (Syntax Errors)示例 1:解决方案:2. 空指针异常 (NullPoi

Java反转字符串的五种方法总结

《Java反转字符串的五种方法总结》:本文主要介绍五种在Java中反转字符串的方法,包括使用StringBuilder的reverse()方法、字符数组、自定义StringBuilder方法、直接... 目录前言方法一:使用StringBuilder的reverse()方法方法二:使用字符数组方法三:使用自

Python依赖库的几种离线安装方法总结

《Python依赖库的几种离线安装方法总结》:本文主要介绍如何在Python中使用pip工具进行依赖库的安装和管理,包括如何导出和导入依赖包列表、如何下载和安装单个或多个库包及其依赖,以及如何指定... 目录前言一、如何copy一个python环境二、如何下载一个包及其依赖并安装三、如何导出requirem

Rust格式化输出方式总结

《Rust格式化输出方式总结》Rust提供了强大的格式化输出功能,通过std::fmt模块和相关的宏来实现,主要的输出宏包括println!和format!,它们支持多种格式化占位符,如{}、{:?}... 目录Rust格式化输出方式基本的格式化输出格式化占位符Format 特性总结Rust格式化输出方式

Python中连接不同数据库的方法总结

《Python中连接不同数据库的方法总结》在数据驱动的现代应用开发中,Python凭借其丰富的库和强大的生态系统,成为连接各种数据库的理想编程语言,下面我们就来看看如何使用Python实现连接常用的几... 目录一、连接mysql数据库二、连接PostgreSQL数据库三、连接SQLite数据库四、连接Mo

Git提交代码详细流程及问题总结

《Git提交代码详细流程及问题总结》:本文主要介绍Git的三大分区,分别是工作区、暂存区和版本库,并详细描述了提交、推送、拉取代码和合并分支的流程,文中通过代码介绍的非常详解,需要的朋友可以参考下... 目录1.git 三大分区2.Git提交、推送、拉取代码、合并分支详细流程3.问题总结4.git push

Kubernetes常用命令大全近期总结

《Kubernetes常用命令大全近期总结》Kubernetes是用于大规模部署和管理这些容器的开源软件-在希腊语中,这个词还有“舵手”或“飞行员”的意思,使用Kubernetes(有时被称为“... 目录前言Kubernetes 的工作原理为什么要使用 Kubernetes?Kubernetes常用命令总

Python中实现进度条的多种方法总结

《Python中实现进度条的多种方法总结》在Python编程中,进度条是一个非常有用的功能,它能让用户直观地了解任务的进度,提升用户体验,本文将介绍几种在Python中实现进度条的常用方法,并通过代码... 目录一、简单的打印方式二、使用tqdm库三、使用alive-progress库四、使用progres

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

Java向kettle8.0传递参数的方式总结

《Java向kettle8.0传递参数的方式总结》介绍了如何在Kettle中传递参数到转换和作业中,包括设置全局properties、使用TransMeta和JobMeta的parameterValu... 目录1.传递参数到转换中2.传递参数到作业中总结1.传递参数到转换中1.1. 通过设置Trans的