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

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

[[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 アルゴリズムを使用して数十億のデータのパーセンタイルを計算するのでしょうか?

ブログ    
ブログ    
ブログ    

推薦する

アリババが雲奇会議でデジタル経済について語らなかったこと

2009 年以来、雲奇会議は、最も初期のローカル ウェブサイト サミットから、アリババの年次戦略およ...

...

李菲菲の「具現化された知能」はどこまで進歩したのか?

2009年、当時プリンストン大学に勤務していたコンピューター科学者のフェイフェイ・リー氏が、人工知...

ImageNetは人間の顔をぼかすことにしたが、ハスキー犬の顔の写真の認識率は急上昇した

この記事はAI新メディアQuantum Bit(公開アカウントID:QbitAI)より許可を得て転載...

MITとIBMが共同で「コンピュータービジョンの黄金時代に備える」ための新しいデータセットを発表

人工知能の分野における画像分類問題に関して言えば、トレーニングとテストに最もよく使用されるデータセッ...

...

Java プログラミング スキル - データ構造とアルゴリズム「ソート アルゴリズムの分類と紹介」

導入ソートとは、データのセットを指定された順序で並べるプロセスです。分類カテゴリ内部ソート: ソート...

OpenAIの「コピー&ペースト」の背後にあるのは、盗作者が全てを無料で手に入れたいということ

今日では、盗作された記事や作品が出版され、盗作者がそれを無料で使用したり、利益を得たりすることは珍し...

エッジにAIを導入する3つのメリット

AIワークロードをエッジで実行することで、経済性の向上、意思決定の迅速化、自動化が可能になります。誇...

2021 年に注目すべき 4 つの自動化問題

[[377158]]研究によれば、コロナウイルスのパンデミック中に組織が確立したビジネス規範は、パン...

ソフトウェアと自動化機器が持続可能性と回復力を向上させる方法

近年、需要の増加、エネルギーコストの高騰、持続可能性の問題が続く中、データセンターが注目を集めていま...

海外の専門家による人工知能の発展見通しに関する衝撃的な4つの予測

人工知能技術が成熟するにつれ、この技術のより広範な社会的、倫理的影響に十分な注意が払われていないので...

Java プログラミング スキル - データ構造とアルゴリズム「再帰」

[[392763]]コンセプト簡単に言うと、再帰とは、毎回異なる変数を渡しながら、自身を呼び出すメ...

人工知能に関する6つの誤解を解く

「人工知能はすべての仕事を自動化し、人間を失業させるだろう。」 「人工知能は単なる架空の技術だ。」 ...

ResearchAndMarkets: 世界の AI ソリューション市場は 2027 年に 2,820 億ドルに達する見込み

ResearchAndMarkets が発表した最新のレポートによると、2027 年までに世界の人...