[]データ構造 - エンドでの図は何ですか?

あなたは、私は私がしたいと思います考えてはいけない、私はそれはものではありません図と述べました。 - 明はそれを明らかにしました。

なぜチャート

多くの関係を表すために使用されます。

直接的な関係に直線状の即時の前任者と後継者に限定

木は、唯一の親が直接の前駆体であることができます

基本コンセプト

サイド:2つの接続ノード

頂点(頂点):データ要素は、頂点は、ゼロまたはそれ以上の隣接する要素を有していてもよいです。

パスは:例えば、のD-> Cからの経路が存在します

1)D-> B-> C

2)D-> A-> B-> C

分類

無向グラフ:上記のように、頂点間の無指向性接続。例えばAB、すなわちA-> Bであってもよいが> A.をB-できます

有向グラフ:接続された頂点間の方向、例えばAB、

のみA-> BがB-> Aありません

重み付きグラフ:重みを持つこのグラフ、また、ネットワークエッジとして知られています

表現

あるいはまた、ストレージ構造

2つの方法の図表現を2次元配列表現(隣接行列)は、リスト(隣接リスト)を表します。

隣接行列

私たちは、マップを表現するために2つの配列を使用します。

描画を格納するために使用される一次元アレイ頂点情報を

二次元配列は、寄託格納するサイド情報

全て求めて隣接頂点VIは、行i及び再び走査における行列要素であるarr[i][j]隣接点1と同様。

隣接行列は、n図の頂点の隣接頂点のパターンとの関係を示す行列である。行列は、行とCOLある。1 .... N点を表します。

以下が観察され、無向グラフの例です。

隣接行列は対称行列であります

主対角線は0であり、エッジ自体への頂点は存在しません。

隣接リスト

エッジの存在を懸念のみ。

隣接行列は、n個の頂点の各側面のためのスペースを割り当てる必要があるため、多くの側面は、存在しない空間の一部の損失を引き起こすであろうがあります。

唯一の懸念は、側面に存在する隣接リストを達成するために、我々は存在しない側を気にしないでください。したがってそこには無駄なスペースがなく、隣接する表の配列組成を示しています。

チャートを作成します。

図のコードは、以下の構造を実装します

    A   B   C   D   E
A   0   1   1   0   0
B   1   0   1   1   1
C   1   1   0   0   0
D   0   1   0   0   0 
E   0   1   0   0   0
//说明
//(1) 1 表示能够直接连接
//(2) 0 表示不能直接连接

アイデアの分析:

我々は2つの配列を必要とします

文字列型は、頂点のArrayListを格納するために使用されます

情報側を格納するための二次元アレイ

一般的な方法:

  1. 頂点を挿入します
  2. エッジを挿入
  3. ノードの数を返します。
  4. 累積的に、各挿入端で得られたエッジの数
  5. 図2に対応するマトリクスディスプレイ。
  6. 先頭ノードI(添字)データに対応した0 - > "" 1 - > "B" 2 - > "C"
  7. V1とV2の重みを返す、アレイのどの重み存在。

コードの実装

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;

/**
 * @ClassName: Demo20_Graph
 * @author: benjamin
 * @version: 1.0
 * @description: TODO
 * @createTime: 2019/08/26/11:20
 */

public class Demo20_Graph {

  // 用于存储顶点的集合
  private ArrayList<String> vertexList;
  // 存储边的信息的二维数组
  private int[][] edges;
  // 记录边的数目
  private int numOfEdges;
  // 定义数组boolean[],记录某个结点是否被访问

  public static void main(String[] args) {
    Demo20_Graph graph = new Demo20_Graph(5);

    // 插入顶点
    String vertexs[] = {"A","B","C","D","E","F"};
    for(String vertex:vertexs){
        graph.insertVertex(vertex);
    }
    // 添加边
    // A-B A-C B-C B-D B-E
    graph.insertEdge(0,1,1);
    graph.insertEdge(0,2,1);
    graph.insertEdge(1,2,1);
    graph.insertEdge(1,3,1);
    graph.insertEdge(1,4,1);
    // 显示一把邻结矩阵
    graph.showGraph();
  }

  // 构造器,初始化矩阵和顶点集合
  Demo20_Graph(int n) {
    // 集合长度为n
    vertexList = new ArrayList<String>(n);
    // 邻接矩阵为n*n
    edges = new int[n][n];
    numOfEdges = 0;
  }

  //常用的方法
  //返回结点的个数
  public int getNumOfVertex() {
    return vertexList.size();
  }

  //显示图对应的矩阵
  public void showGraph() {
    for(int[] vertex:edges){
      System.out.println(Arrays.toString(vertex));
    }
  }

  //得到边的数目
  public int getNumOfEdges() {
    return numOfEdges;
  }

  //返回结点i(下标)对应的数据 0->"A" 1->"B" 2->"C"
  public String getValueByIndex(int i) {
    return vertexList.get(i);
  }

  //返回v1和v2的权值
  public int getWeight(int v1, int v2) {
    return edges[v1][v2];
  }

  //插入结点
  public void insertVertex(String vertex) {
    vertexList.add(vertex);
  }

  /**
   * 添加边
   *
   * @param v1 表示点的下标即使第几个顶点  "A"-"B" "A"->0 "B"->1
   * @param v2 第二个顶点对应的下标
   * @param weight 表示权,1或者0
   */
  public void insertEdge(int v1, int v2, int weight) {
    edges[v1][v2] = weight;
    edges[v2][v1] = weight;
    numOfEdges++;
  }

}

出力:

[0、1、1、0、0]
[1、0、1、1、1]
[1、1、0、0、0]
[0、1、0、0、0]
[0、1、0 、0、0]

トラバースグラフ

すなわち、ノードのアクセスポイント。ので、複数のノードがあるグラフは、これらのノードをトラバースする方法を、具体的な戦略を必要とする2つのアクセスポリシーがあります。

  • 深さ優先探索
  • 幅優先トラバーサル

フィールドで行われる研究に戻っ芸術に精通元、およびを選択した後、

後者は、起業家精神のように、既知から始め、すでに関心の緩やかな再発掘部分から何かを知っています。

深さ優先探索(DFS)

基本的な考え方

深さ優先探索マップ(深さ優先探索)

初期アクセスノードから、初期のアクセス・ノードは、複数の隣接ノードを有していてもよく、深さ優先トラバーサル戦略は、まず、第1の隣接ノードを訪問することであり、次いで、隣接ノードへの最初のノードへのアクセスとしてアクセスされますその最初の隣接ノードは、理解することができる:最初に、毎回、現在のアクセスノードの完了後、現在のノードの最初の隣接ノードにアクセスします。

私たちは、深さ優先探索は再帰的プロセスであり、この戦略は垂直掘削深さ優先のアクセスであることがわかります

DFSは、上の図を達成するためにどのようにステップ?

初期としてノードは、Aから出発し、訪れた最初の標識

最初の隣接ノードBは、Bが存在すると、初期ノードBとして今、訪問されていません

Bから出発して、標識BがCの存在により、第1隣接ノードBへのアクセスを有し、Cは、アクセスされないが、今、初期ノードCとして

D Cの次のノードのノードは、バックBの次の隣接ノードE Bの端部に存在しません

アルゴリズムのステップ

  1. 訪問したように、初期アクセスノードv、およびノー​​ドvがマーク。
  2. 第1隣接ノードWにおけるノードvを探します。
  3. 存在するW場合、存在しないW場合、プロセスは継続する次のノードから1、Vに戻り、4に進みます。
  4. アクセスは、再帰深さ優先トラバーサルのW、Wない場合(すなわち、W Vとして他方は、次いでステップ123)。
  5. ステップ3に進み、次の隣接ノードノードwの隣接ノードvの検索。

コードの実装

  /**
   * 得到第一个邻接结点的下标 w
   *
   * @return 如果存在就返回对应的下标,否则返回-1
   */
  public int getFirstNeighbor(int index) {
    for (int j = 0; j < vertexList.size(); j++) {
      if (edges[index][j] > 0) {
        return j;
      }
    }
    return -1;
  }

  /**
   * @Description: 根据前一个邻接结点的下标来获取下一个邻接结点
   * @Param: [v1, v2]
   * @return: int
   * @Author: benjamin
   * @Date: 2019/8/26
   */
  public int getNextNeighbor(int v1, int v2) {
    for (int j = v2 + 1; j < vertexList.size(); j++) {
      if (edges[v1][j] > 0) {
        return j;
      }
    }
    return -1;
  }

  //深度优先遍历算法
  //i 第一次就是 0
  private void dfs(boolean[] isVisited, int i) {
    // 首先输出访问的结点
    System.out.print(getValueByIndex(i) + "->");
    // 将结点设置为已经访问
    isVisited[i] = true;
    // 查找结点i的第一个邻接结点w
    int w = getFirstNeighbor(i);
    // 只要w不为1,说明有
    while (w != -1){
      if(!isVisited[w]){
        dfs(isVisited,w);
      }
      // 如果该结点已经被访问过,则访问i的下下一个邻接结点
      w = getNextNeighbor(i,w);
    }
  }

  //对dfs 进行一个重载, 遍历我们所有的结点,并进行 dfs
  public void dfs() {
    isVisited = new boolean[vertexList.size()];
    //遍历所有的结点,长度为集合的长度,进行dfs[回溯]
    for(int i = 0; i < getNumOfVertex(); i++) {
      if(!isVisited[i]) {
        dfs(isVisited, i);
      }
    }

  }

幅優先トラバーサル(BFS)

基本的な考え方

幅優先探索グラフ(広いまず検索)。

幅優先トラバーサルを使用して階層的検索と同様の処理が、順序キューを維持する必要があるこれらのノードにアクセスするので、この順に隣接するノードに、ノードを訪問

アルゴリズムのステップ

  1. 訪問したように、初期のアクセス・ノードは、ノードvとVをラベル。
  2. ノード・キューV
  3. キューが空でない場合は、そうでない場合、アルゴリズムは終了し、継続します。
  4. キューは、HOLノードuを得ることができます。
  5. 第1隣接ノードWのノードUを見つけます。
  6. 隣接ノードwをノードuが存在しない場合、ステップ3に進み、そうでなければ、サイクルは3つのステップを以下
    1. まだワットノードがアクセスされた場合は訪問したとして、アクセスノードは、Wとマーク。
    2. ノード・キューのw
    3. 隣接ノードを、以下のワットノードUへワット次の隣接ノードを検索し、手順6に進みます。

コードの実装

/**
* 得到第一个邻接结点的下标 w
*
* @return 如果存在就返回对应的下标,否则返回-1
*/
public int getFirstNeighbor(int index) {
for (int j = 0; j < vertexList.size(); j++) {
  if (edges[index][j] > 0) {
    return j;
  }
}
return -1;
}

/**
* @Description: 根据前一个邻接结点的下标来获取下一个邻接结点
* @Param: [v1, v2]
* @return: int
* @Author: benjamin
* @Date: 2019/8/26
*/
public int getNextNeighbor(int v1, int v2) {
for (int j = v2 + 1; j < vertexList.size(); j++) {
  if (edges[v1][j] > 0) {
    return j;
  }
}
return -1;
}
//对一个结点进行广度优先遍历的方法
private void bfs(boolean[] isVisited, int i) {
int u ; // 表示队列的头结点对应下标
int w ; // 邻接结点w
//队列,记录结点访问的顺序
LinkedList queue = new LinkedList();
//访问结点,输出结点信息
System.out.print(getValueByIndex(i) + "=>");
//标记为已访问
isVisited[i] = true;
//将结点加入队列
queue.addLast(i);

while( !queue.isEmpty()) {
//取出队列的头结点下标
u = (Integer)queue.removeFirst();
//得到第一个邻接结点的下标 w
w = getFirstNeighbor(u);
while(w != -1) {//找到
//是否访问过
if(!isVisited[w]) {
  System.out.print(getValueByIndex(w) + "=>");
  //标记已经访问
  isVisited[w] = true;
  //入队
  queue.addLast(w);
}
//以u为前驱点,找w后面的下一个邻结点
w = getNextNeighbor(u, w); //体现出我们的广度优先
}
}
}

//遍历所有的结点,都进行广度优先搜索
public void bfs() {
isVisited = new boolean[vertexList.size()];// 清空标志位
for (int j = 0; j < vertexList.size(); j++) {
if (!isVisited[j]) {
bfs(isVisited, j);
}
}
}

おすすめ

転載: www.cnblogs.com/benjieqiang/p/11414409.html