グラフアルゴリズムシリーズ: 無向グラフのデータ構造

グラフアルゴリズムシリーズ: 無向グラフのデータ構造

[[393944]]

この記事はWeChatの公開アカウント「Beta Learns JAVA」から転載したもので、著者はSilently9527です。この記事を転載する場合は、Beta Learning JAVA パブリック アカウントにお問い合わせください。

序文

この記事から、グラフ関連のアルゴリズムを一緒に学習します。グラフ コンピューティングには、ガベージ コレクターのマーク アンド スイープ アルゴリズム、マップ上のパスの最短距離、トポロジカル ソートなど、非常に実用的なアルゴリズムが多数あります。これらのアルゴリズムを学習する前に、まずグラフの基本的な定義と、グラフを表すために使用されるデータ構造を理解する必要があります。この記事では、無向グラフから始めます。

グラフの定義

グラフ: 頂点の集合と、2 つの順序を接続できる順序の集合で構成されます。 2 つの頂点を結ぶ辺には方向がなく、このようなグラフは無向グラフと呼ばれます。

グラフ用語

同じ辺で接続された 2 つの頂点は隣接していると呼ばれます。

頂点の次数とは、この頂点を結ぶ辺の総数です。上図に示すように、頂点1の次数は3です。

頂点をそれ自身に接続する辺は自己ループと呼ばれます。

同じ頂点のペアを結ぶ辺は平行辺と呼ばれる。

他にもたくさんの用語があります。今のところ、この記事で使用する必要のある用語のみをリストします。他の用語については後で説明します。用語が多すぎると覚えるのは簡単ではありません。

グラフの表現方法

グラフを表現するために使用されるデータ構造は、主に次の 2 つの要件を指します。

  1. グラフ関連のアルゴリズムを開発する場合、グラフ表現のデータ構造が基礎となるため、このデータ構造が効率的です。
  2. 実際のプロセスでは、グラフのサイズは不確実であり、非常に大きくなる可能性があるため、十分なスペースを確保する必要があります。

これら 2 つの要件を考慮した後、専門家は次の 3 つの選択方法を提案しました。

  • 隣接行列は、v 個の頂点を持つグラフに入力されます。v に v を掛けた行列を使用して表すことができます。頂点 v が w に接続されている場合は、v 行と w 列を true に設定します。これにより、2 つの頂点が接続されていることが示されます。ただし、この方法には問題があります。グラフが非常に大きい場合、スペースが無駄になります。 2番目のポイントは満たされていません。第二に、この方法では平行なエッジを表現することができない。
  • エッジの配列は、頂点を表す 2 つの int 属性を含むエッジ オブジェクトを定義できます。ただし、頂点の接続された頂点を見つける必要がある場合は、すべてのエッジをトラバースする必要があります。このデータ構造は効率が悪い
  • 隣接リスト配列は、頂点の数と同じサイズの配列を定義します。データの添え字は頂点を表します。配列内の各要素はリンクリストオブジェクト (LinkedListQueue) であり、リンクリストに格納されている値は、頂点に接続されている頂点です。 (LinkedListQueueは以前の記事で実装されています。記事「https://juejin.cn/post/6926685994347397127」を参照してください)

無向グラフのAPI定義

  1. パブリッククラスGraph {
  2. public Graph( int V); // v 個の頂点と辺のないグラフを作成する
  3.      
  4. 公共  int V(); //頂点の数を返す
  5.      
  6. 公共  int E(); //グラフ内のエッジの総数を返す
  7.      
  8. public void addEdge( int v, int w); //グラフにエッジvWを追加する
  9.          
  10. public Iterable< Integer > adj( int v); // v に隣接するすべての頂点を返す
  11.      
  12. public String toString(); //文字列を使用してグラフの関係を出力します
  13. }

無向グラフAPIの実装

上記で定義した API を実装するには、3 つのメンバー変数が必要です。v はグラフ内の頂点の数を表し、e はグラフの合計エッジ データを表し、LinkedListQueue 配列は頂点 v の隣接ノードを格納するために使用されます。

コンストラクタは空の隣接リスト配列を初期化する

これは無向グラフなので、addEdge メソッドはグラフに v->w エッジと w->v エッジの両方を追加する必要があります。

  1. パブリッククラスGraph {
  2. プライベート最終int v;
  3. プライベートint e;
  4. プライベート LinkedListQueue< Integer >[] adj;
  5.  
  6. パブリックグラフ( int v) {
  7. this.v = v;
  8. this.adj = (LinkedListQueue< Integer >[]) 新しいLinkedListQueue[v];
  9. ( int i = 0; i < v; i++)の場合{
  10. this.adj[i] = 新しいLinkedListQueue<>();
  11. }
  12. }
  13.  
  14. 公共 整数V(){
  15. vを返します
  16. }
  17.  
  18. 公共 整数E() {
  19. eを返します
  20. }
  21.  
  22. パブリックvoid addEdge( int v, int w) {
  23. this.adj[v].enqueue(w);
  24. this.adj[w].enqueue(v);
  25. this.e++;
  26. }
  27.  
  28. パブリックイテラブル<整数> adj( int v) {
  29. this.adj[v]を返します
  30. }
  31.  
  32. @オーバーライド
  33. パブリック文字列toString() {
  34. StringBuilder sb = 新しい StringBuilder();
  35. sb.append(v).append( " 頂点、 " ).append(e).append( " 辺\n" );
  36. ( int i = 0; i < v; i++)の場合{
  37. sb.append(i).append( ": " );
  38. ( int j : this.adj[i])の場合{
  39. sb.append(j).append( " " );
  40. }
  41. sb.append( "\n" );
  42. }
  43. sb.toString()を返します
  44. }
  45. }

グラフの一般的なツールと方法

グラフデータ構造の実装に基づいて、いくつかのツールと方法を提供することができます。

頂点 v の次数を計算します。頂点の次数は、その頂点に接続されている頂点の数に等しくなります。

  1. 公共 静的  int degree(グラフグラフ、 int v) {
  2. 度数= 0;
  3. ( int w : graph.adj(v))の場合{
  4. 学位++;
  5. }
  6. 戻り度合い;
  7. }

すべての頂点の最大次数を計算する

  1. 公共 静的  int maxDegree(グラフグラフ) {
  2. 最大度数= 0;
  3. ( int v = 0; v < graph.V(); v++)の場合{
  4. int度 = 度(グラフ、v);
  5. (最大度数<度数)の場合{
  6. 最大度数 = 度数;
  7. }
  8. }
  9. maxDegreeを返します
  10. }

すべての頂点の平均次数を計算します。各辺には 2 つの頂点があるため、グラフ内のすべての頂点の合計次数は辺の 2 倍になります。

  1. 公共 静的  double avgDegree(グラフグラフ) {
  2. 2.0 * graph.E() / graph.V()を返します
  3. }

グラフ内の自己ループの数を計算します。頂点 v について、v が v の隣接リストにも表示される場合、v には自己ループがあります。無向グラフであるため、各エッジは 2 回記録されます (理解しにくい場合は、グラフの toString を出力して理解することができます)

  1. 公共 静的  int numberOfSelfLoops(グラフグラフ) {
  2. 整数 カウント= 0;
  3. ( int v = 0; v < graph.V(); v++)の場合{
  4. ( int w : graph.adj(v))の場合{
  5. (v == w) の場合 {
  6. カウント++;
  7. }
  8. }
  9. }
  10. 戻る カウント/ 2;
  11. }

要約する

この記事では、主にグラフを表現するために使用するデータ構造について学習し、このデータ構造に基づいていくつかの簡単なツールとメソッドを実装します。次の記事では、グラフの最初の検索アルゴリズムである深さ優先検索について学習します。

この記事のすべてのソースコードは、github リポジトリに保存されています: https://github.com/silently9527/JavaCore

<<:  Nvidia の新しいブラック テクノロジーが「Minecraft」のモザイクをリアルな大ヒット作に変える

>>:  ElasticSearch はどのようにして TDigest アルゴリズムを使用して数十億のデータのパーセンタイルを計算するのでしょうか?

ブログ    

推薦する

...

...

清華大学などは、シンボリックメモリと組み合わせて、大規模モデルの複雑な推論能力を向上させるChatDBを提案した。

ChatGPT、GPT-4、PaLM、LLaMAなどの大規模言語モデルの普及に伴い、大規模言語モデ...

...

ついに誰かが畳み込みニューラルネットワーク(CNN)を明確にした。

[[406748]]従来のニューラル ネットワーク レイヤーは完全に接続されています。サンプリング...

EasyDL モデルのトレーニングから EdgeBoard 推論までのステップバイステップ ガイド

まとめ: EdgeBoard は Baidu が開発した FPGA ベースの組み込み AI ソリュー...

求職者の履歴書はどうすればAIやロボットによる審査に合格できるのでしょうか?

[[271396]]今日では、求人ウェブサイトに提出された多くの求職者の履歴書は、新しい仕事の面接...

SQL SERVER データマイニング: クラスタリングアルゴリズムとシーケンシャルクラスタリングアルゴリズムの理解

前回の「SQL SERVER データ マイニングと列の使用方法の理解」に続き、今回はSQL SERV...

ネイチャー誌の表紙:AIの翼に乗って、データが計算社会科学を「担う」

シュメール王国の時代から、この賢明な王国の人々はデータを記録し、国勢調査を実施し、食糧を配給し始めま...

マイクロソフトは、AIチップが十分に入手できない場合、データセンターのサービスが中断される可能性があると警告している

CNBCによると、7月29日、マイクロソフトは最近発表した財務報告書の中で、データセンターのサービス...

RPA の収益は 2021 年に 18 億 9,000 万米ドルに達する見込みです。AI は RPA をどのように再定義するのでしょうか?

市場調査会社ガートナーは、ロボティック・プロセス・オートメーション(RPA)を世界のエンタープライズ...

...

2020年第1四半期の人工知能の最新進歩

かつてはSFの世界であり、コンピューティングの世界の非現実的な夢であった人工知能が、今や現実のものと...

貨物ドローンは宅配業界に革命を起こす:より重い荷物を運び、より遠くまで飛ぶ

貨物ドローンは、高効率、環境保護、低コストなど、多くの利点を備え、宅配業界に革命をもたらそうとしてい...