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

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

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

ブログ    
ブログ    

推薦する

米国のテクノロジー業界が冬を乗り切る中、プログラマーたちは仕事を維持するために率先して給与を削減している。 35歳の会社員:給料をもう少し下げてもいい

テクノロジー業界は歴史的に平均給与が最も高い業界の一つであり、リストのトップにランクされることも少な...

ローコードがAIの参入障壁を下げる

[[341638]] [51CTO.com クイック翻訳] 機械学習を迅速に実装したい組織は、新興の...

人工知能2.0の時代、機械にスマートな脳を搭載する方法

[[419760]] 「クラブアップルの木は、その赤みがかった色にもかかわらず、霧雨の中にひとりぼっ...

人工知能と機械学習は、組織がデジタルシステムを運用する上でますます重要になる

[[280794]]いくつかの困難や障害にもかかわらず、多くの企業がデジタル変革プロジェクトで大きな...

...

インテリジェントロボットはCOVID-19の流行とどのように戦うのでしょうか?

【51CTO.comオリジナル記事】 COVID -19の流行がもたらした厳しい課題に直面して、科...

GPU ベースの AI を使用して、わずか 36 分で実際の宇宙をシミュレートする

科学者たちはすでに宇宙論の分野で大量のデータを処理するためにスーパーコンピュータを使用することに慣れ...

ElevenLabs、元の話し手の声と感情を維持するAI翻訳吹き替え機能を発表

AIテキスト読み上げ会社ElevenLabsは10月11日、火曜日にAI Dubbingを発表した。...

一枚の写真で「踊り続ける」ことができ、SHERFは人間の神経放射場を駆動できる新しい方法を一般化することができます

人体神経放射線分野の目標は、2D 人体画像から高品質の 3D デジタル人間を復元して駆動し、それによ...

転移学習に関する最先端の研究:低リソース、ドメイン一般化、安全な転移

この記事はLeiphone.comから転載したものです。転載する場合は、Leiphone.com公式...

プログラマーが知っておくべき 20 世紀の 10 大アルゴリズム

トップ10のアルゴリズムを発明したアルゴリズムの巨匠たち1. 1946年のモンテカルロ法[1946年...

2020年に人工知能はどのように発展するでしょうか?知っておくべき6つのトレンド

過去1年を振り返ると、人工知能の発展は繁栄し、多彩なものであったと言えます。人工知能が3回連続で政府...

2017年世界ロボット会議エクスプレス:無人スーパーマーケットロボットがデビュー

[51CTO.com 北京レポート] 2017年8月23日から27日まで、2017年世界ロボット大会...

AI陣営を理解するためのチャート: AIを学んで間違った側に立つと自滅につながる可能性がある

AIにはさまざまな手法があります。私たちがよく知っている「5大流派」に加え、この記事の著者はAIのさ...