java 数据结构 图中使用的一些常用算法 图的存储结构 邻接矩阵:图的邻接矩阵存储方式是用两个数组来标示图。一个一位数组存储图顶点的信息,一个二维数组(称为邻接矩阵)存储图中边或者弧的信息。 设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为: 实例如下,左图是一个无向图。右图是邻接矩阵表示:

以下内容主要来自大话数据结构之中,部分内容参考互联网中其他前辈的博客。

  图的定义

图是由顶点的有穷非空集合和顶点之间边的集合组成,通过表示为G(V,E),其中,G标示一个图,V是图G中顶点的集合,E是图G中边的集合。

无边图:若顶点Vi到Vj之间的边没有方向,则称这条边为无项边(Edge),用序偶对(Vi,Vj)标示。

对于下图无向图G1来说,G1=(V1, {E1}),其中顶点集合V1={A,B,C,D};边集合E1={(A,B),(B,C),(C,D),(D,A),(A,C)}:

有向图:若从顶点Vi到Vj的边是有方向的,则成这条边为有向边,也称为弧(Arc)。用有序对(Vi,Vj)标示,Vi称为弧尾,Vj称为弧头。如果任意两条边之间都是有向的,则称该图为有向图。

有向图G2中,G2=(V2,{E2}),顶点集合(A,B,C,D),弧集合E2={<A,D>,{B,A},<C,A>,<B,C>}.

权(Weight):有些图的边和弧有相关的数,这个数叫做权(Weight)。这些带权的图通常称为网(Network)。

    

  图的存储结构

  图的存储结构一般分为邻接矩阵和十字链表

  邻接矩阵:图的邻接矩阵存储方式是用两个数组来标示图。一个一位数组存储图顶点的信息,一个二维数组(称为邻接矩阵)存储图中边或者弧的信息。

  设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为:

  

  十字链表:

  顶点表结点结构:

  

  firstin:表示入边表头指针,指向该顶点的入边表中第一个结点。

  firstout:表示出边表头指针,指向该顶点的出边表中的第一个结点。

  边表结点结构:

  

  tailvex:指弧起点在顶点表的下标。

  headvex:指弧终点在顶点表中的下标。

  headlink:指入边表指针域。

  taillink:指边表指针域。

  如果是网,还可以再增加一个weight域来存储权值。

  

  蓝线表示出度,红线表示入度

  十字链表的优点

  十字链表是把邻接表和逆邻接表整合在一起,这样既容易找到以Vi为尾的弧,也容易找到以Vi为头的弧,

  因而容易求的顶点的出度和入度。

  

  图的搜索:

  深度优先遍历:也有称为深度优先搜索,简称DFS。其实,就像是一棵树的前序遍历。它从图中某个结点v出发,访问此顶点,然后从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有      路径相通的顶点都被访问到。若图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中的所有顶点都被访问到为止。

  基本实现思想:

  (1)访问顶点v;

  (2)从v的未被访问的邻接点中选取一个顶点w,从w出发进行深度优先遍历;

  (3)重复上述两步,直至图中所有和v有路径相通的顶点都被访问到。

  

  广度优先遍历:也称广度优先搜索,简称BFS。BFS算法是一个分层搜索的过程,和树的层序遍历算法类同,它也需要一个队列以保持遍历过的顶点顺序,以便按出队的顺序再去访问这些顶点的邻接顶点。

  基本实现思想:

  (1)顶点v入队列。

  (2)当队列非空时则继续执行,否则算法结束。

  (3)出队列取得队头顶点v;访问顶点v并标记顶点v已被访问。

  (4)查找顶点v的第一个邻接顶点col。

  (5)若v的邻接顶点col未被访问过的,则col入队列。

  (6)继续查找顶点v的另一个新的邻接顶点col,转到步骤(5)。

直到顶点v的所有未被访问过的邻接点处理完。转到步骤(2)。

  广度优先遍历图是以顶点v为起始点,由近至远,依次访问和v有路径相通而且路径长度为1,2,……的顶点。为了使“先被访问顶点的邻接点”先于“后被访问顶点的邻接点”被访问,需设置队列存储访问的顶点。

  最小生成树

    我们把构造连通网的最小代价生成的树称为最小生成树,即权值最小的生成树。

  实现方式:

  1、普利姆算法(Prim)

    基本思想:假设G=(V,E)是连通的,TE是G上最小生成树中边的集合。算法从U={u0}(u0∈V)、TE={}开始。重复执行下列操作:

    在所有u∈U,v∈V-U的边(u,v)∈E中找一条权值最小的边(u0,v0)并入集合TE中,同时v0并入U,直到V=U为止。

   此时,TE中必有n-1条边,T=(V,TE)为G的最小生成树。

    Prim算法的核心:始终保持TE中的边集构成一棵生成树。

   注意:prim算法适合稠密图,其时间复杂度为O(n^2),其时间复杂度与边得数目无关,而kruskal算法的时间复杂度为O(eloge)跟边的数目有关,适合稀疏图。

    示例:

    

  (1)图中有6个顶点v1-v6,每条边的边权值都在图上;在进行prim算法时,我先随意选择一个顶点作为起始点,当然我们一般选择v1作为起始点,好,现在我们设U集合为当前所找到最小生成树里面的   顶点,TE集合为所找到的边,现在状态如下:

      U={v1}; TE={};

  (2)现在查找一个顶点在U集合中,另一个顶点在V-U集合中的最小权值,如下图,在红线相交的线上找最小值。

  

  通过图中我们可以看到边v1-v3的权值最小为1,那么将v3加入到U集合,(v1,v3)加入到TE,状态如下:

U={v1,v3}; TE={(v1,v3)};

(3)继续寻找,现在状态为U={v1,v3}; TE={(v1,v3)};在与红线相交的边上查找最小值。

  

  我们可以找到最小的权值为(v3,v6)=4,那么我们将v6加入到U集合,并将最小边加入到TE集合,那么加入后状态如下:

  U={v1,v3,v6}; TE={(v1,v3),(v3,v6)}; 如此循环一下直到找到所有顶点为止。

  (4)下图像我们展示了全部的查找过程:

  

    

  2、

时间: 2024-10-03 13:39:53

java 数据结构 图中使用的一些常用算法 图的存储结构 邻接矩阵:图的邻接矩阵存储方式是用两个数组来标示图。一个一位数组存储图顶点的信息,一个二维数组(称为邻接矩阵)存储图中边或者弧的信息。 设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为: 实例如下,左图是一个无向图。右图是邻接矩阵表示:的相关文章

[java学习笔记]java语言基础概述之数组的定义&amp;常见操作(遍历、排序、查找)&amp;二维数组

1.数组基础 1.什么是数组:           同一类型数据的集合,就是一个容器. 2.数组的好处:           可以自动为数组中的元素从零开始编号,方便操作这些数据. 3.格式:  (一旦创建,必须明确长度)          格式1:              元素类型   [ ]  数组名  =  new  元素类型  [元素个数即数组的长度]:              示例:int[] array = new int[5];          格式2:           

java基础:java中的二维数组

二维数组的概念: 一个元素为一维数组的数组. 格式1: 数据类型[][] 数组名 = new 数据类型[m][n]; m:表示这个二维数组有多少个一维数组. n:表示每一个一维数组的元素有多少个. 注意: A:以下格式也可以表示二维数组 a:数据类型 数组名[][] = new 数据类型[m][n]; b:数据类型[] 数组名[] = new 数据类型[m][n]; B:注意下面定义的区别 int x; int y; int x,y; int[] x; int[] y[]; int[] x,y[

【Java学习笔记之八】java二维数组及其多维数组的内存应用拓展延伸

多维数组声明 数据类型[][] 数组名称; 数据类型[] 数组名称[]; 数据类型数组名称[][]; 以上三种语法在声明二维数组时的功能是等价的.同理,声明三维数组时需要三对中括号,中括号的位置可以在数据类型的后面,也可以在数组名称的后面,其它的依次类推. 例如: int[][] map; char c[][]; 和一维数组一样,数组声明以后在内存中没有分配具体的存储空间,也没有设定数组的长度.  -------------------------------------------------

直观理解C语言中指向一位数组与二维数组的指针

一维数组和指针: 对于一位数组和指针是很好理解的: 一维数组名: 对于这样的一维数组:int a[5];  a作为数组名就是我们数组的首地址, a是一个地址常量 . 首先说说常量和变量的关系, 对于变量来说, 用箱子去比喻再好不过了, 声明一个变量就声明一个箱子,比如我们开辟出一个苹果类型的箱子, 给这个变量赋值就是把盛放苹果的箱子中放入一个实实在在的苹果, 这就是变量的赋值.  而对于数组来说, 就是一组类型相同的箱子中,一组苹果箱子, 可以放入不同的苹果. 一维数组空间: 变量被声明后, 我

二维数组的定义

第一种格式: 1 public class Array_TwoDimension { 2 public static void main(String[] args) { 3 int[][] arr1 = new int[3][4];//定义了arr1的二维数组,表示二维数组中有3个一维数组,每个一维数组中有四个元素 4 5 arr1[0][3] = 78;//这是给二维数组中的第一个数组中的第三个角标赋值 6 7 System.out.println(arr1);//打印的是数组的地址,会比一

数据结构之二维数组与稀疏数组的转换

1.二维数组 二维数据其实就是高数中的矩阵,在此不做过多的解释 2.稀疏数组 当一个二维数组中大多值为0,或者相同时,我们可以考虑用到稀疏数组,来减少内存 稀疏数组的处理方法: 1)一个有3列的二维数组,记录原数组有几行几列,多少个不同的值 2)不同值的元素的所在行以及列记录在稀疏数组中,从而缩小规模 3.例子如下: 4.下面是稀疏数组以及二维数组之间的转换 package com.ebiz.array; /** * @author YHj * @create 2019-07-13 16:46

Java Array二维数组使用

二维数组:元素为一维数组的数组 package myArray.arrayarray; /* *二维数组:元素为一维数组的数组 * * 定义格式: * A:数组类型[][] 数组名: (推荐用法) * B:数组类型 数组名[][]; * C:数组类型[] 数组名[]; * 初始化: * A:动态初始化 * 数据类型[][] 数组名 = new 数据类型[m][n]; * m表示二维数组中一维数组的个数 * n表示一维数组的个数 * B:静态初始化 * 数据类型[][] 数组名 = new 数据类

每日一题10:在排序的二维数组中查找

排序的二维数组是这样的:在每一行中元素是递增的,在每一列中元素也是递增的,比如: 11 34 35 47 51 13 37 40 52 61 19 42 50 79 80 给定一个值,判断其是否在这样排序的二维数组中. 首先,先来生成测试数据,思路如下:1)先选择一种将给定输入按升序排列.2)构造一个二维数组,寻找该数组中以第一个元素为起点,确定一个最大的正方形区域(其宽要么与原数组的行或与原数组的列数相同).3)按规则,在这个正方形中,每个对角线元素都不小于从数组起点到这个元素所构成的正方形区

剑指offer(3)——二维数组中的查找

题目: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数 思路: 首先选取数组中右上角的数,然后让该数(num1)和待查找的数(num2)进行比较,如果num1比num2小,那么接下来只能向下继续查找,行数加1,如果num1比num2大,那么接下来应该将列数减1,继续查找,直到整个数组遍历完成 代码: 1 public boolean findNum(int[][] arr,int

6.javaScript中的二维数组

1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Document</title> 6 <script type="text/javascript"> 7 //声明一维数组 8 var myarr = new Array(); 9 for (var i = 0; i < 3; i++) {