C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++でグラフ構造化スタック(Graph Structured Stack)を実装する方法

この記事では、C++を用いてグラフ構造化スタック(Graph Structured Stack)を実装する方法を解説します。グラフ構造化スタックは、複数のスタックの状態を有向グラフとして管理できるデータ構造であり、GLR構文解析などのパースアルゴリズムで利用されることで知られています。本プログラムでは、隣接行列で表現されたグラフ上を探索し、始点ノードからボトムノードに至る経路を複数のスタックとして検出・出力します。

アルゴリズムの手順

開始
    関数 graphStructuredStack(int **adjMat, int s, int bNode):
    隣接行列 adjMat、始点 s、ボトムノード bNode を受け取る
    stackFound = false で初期化する
    sVertex = 1 から noOfNodes まで繰り返す
        dVertex = 1 から noOfNodes まで繰り返す
            this->adjMat[sVertex][dVertex] = adjMat[sVertex][dVertex]
        繰り返し終了
    繰り返し終了
    始点 s を mystack にプッシュする
    while (!mystack.empty())
        element = mystack.top()
        d = 1 で初期化する
        while (d <= noOfNodes)
            if (this->adjMat[element][d] == 1)
                行き先 d を mystack にプッシュする
                par[d] = element(親ノードを記録)
                this->adjMat[element][d] = 0(辺を使用済みにする)
                if (d == bNode)
                    stackFound = true を設定して break
                終了
                element = d
                d = 1
                continue
            終了
            d をインクリメント
        繰り返し終了
        if (stackFound)
            node = bNode から node != s の間
                node を istack にプッシュ
            s を istack にプッシュ
            stackList.push_back(istack)
            stackFound = false に戻す
        終了
        mystack から要素をポップ
    繰り返し終了
    iterator = stackList.begin()
    while (iterator != stackList.end())
        イテレータを進める
        while (!stack.empty())
            スタックの先頭要素を出力
            スタックから要素をポップ
        繰り返し終了
    繰り返し終了
終了。

サンプルコード

#include <iostream>
#include <stack>
#include <list>
using namespace std;
class GraphStructuredStack {
   private:
   list< stack<int> > stackList;
   stack<int> mystack;
   int noOfNodes;
   int **adjMat;
   int *par;
   public:
   GraphStructuredStack(int noOfNodes) {
      this->noOfNodes = noOfNodes;
      adjMat = new int* [noOfNodes + 1];
      this->par = new int [noOfNodes + 1];
      for (int i = 0; i < noOfNodes + 1; i++)
         adjMat[i] = new int [noOfNodes + 1];
   }
   void graphStructuredStack(int **adjMat, int s, int bNode) {
      bool stackFound = false;
      for (int sVertex = 1; sVertex <= noOfNodes; sVertex++) {
         for (int dVertex = 1; dVertex <= noOfNodes; dVertex++) {
            this->adjMat[sVertex][dVertex] = adjMat[sVertex][dVertex];
         }
      }
      mystack.push(s);
      int element, d;
      while (!mystack.empty()) {
         element = mystack.top();
         d = 1;
         while (d <= noOfNodes) {
            if (this->adjMat[element][d] == 1) {
               mystack.push(d);
               par[d] = element;
               this->adjMat[element][d] = 0;
               if (d == bNode) {
                  stackFound = true;
                  break;
               }
               element = d;
               d = 1;
               continue;
            }
            d++;
         }
         if (stackFound) {
            stack<int> istack;
            for (int node = bNode; node != s; node = par[node]) {
               istack.push(node);
            }
            istack.push(s);
            stackList.push_back(istack);
            stackFound = false;
         }
         mystack.pop();
      }
      list<stack<int> >::iterator iterator;
      iterator = stackList.begin();
      while (iterator != stackList.end()) {
         stack <int> stack = *iterator;
         iterator++;
         while (!stack.empty()) {
            cout<<stack.top()<<"\t";
            stack.pop();
         }
         cout<<endl;
      }
   }
};
int main() {
   int noofnodes;
   cout<<"Enter number of nodes: ";
   cin>>noofnodes;
   GraphStructuredStack gss(noofnodes);
   int source, bottom;
   int **adjMatrix;
   adjMatrix = new int* [noofnodes + 1];
   for (int i = 0; i < noofnodes + 1; i++)
      adjMatrix[i] = new int [noofnodes + 1];
   cout<<"Enter the graph matrix: "<<endl;
   for (int sVertex = 1; sVertex <= noofnodes; sVertex++) {
      for (int dVertex = 1; dVertex <= noofnodes; dVertex++) {
         cin>>adjMatrix[sVertex][dVertex];
      }
   }
   cout<<"Enter the source node: ";
   cin>>source;
   cout<<"Enter the bottom node: ";
   cin>>bottom;
   cout<<"The stacks are: "<<endl;
   gss.graphStructuredStack(adjMatrix, source, bottom);
   return 0;
}

実行結果

このプログラムを実行すると、まずノード数とグラフの隣接行列を入力します。次に始点ノードとボトムノードを指定すると、始点からボトムノードへ至るすべての経路がスタックとして検出され、画面に出力されます。以下は実行例です。

Enter number of nodes: 4
Enter the graph matrix:
1 1 1 0
0 1 1 0
1 0 0 0
1 1 1 1
Enter the source node: 3
Enter the bottom node: 1
The stacks are:
31

このように、ノード3を始点としノード1をボトムノードとした場合、「3 → 1」という経路がスタックとして検出されています。グラフの形状によっては、複数の異なる経路(複数のスタック)が一度に出力されることもあります。

  1. C++で基数ソート(ラディックスソート)を実装するプログラム

    基数ソート(ラディックスソート)は、非比較型のソートアルゴリズムの一つです。要素同士を直接比較するのではなく、整数キーを構成する各桁に注目し、同じ桁位置・同じ値を持つ数字どうしをグループ化しながら並べ替えを行います。 「基数」とは記数法における底のことです。私たちが普段使う10進法では基数は10であるため、10進数を基数ソートで並べ替える際には、数値を一時的に格納するための10個のバケット(ポケット)が必要になります。 基数ソートの計算量 時間計算量: O(nk) ※nは要素数、kは最大桁数 空間計算量: O(n+k) 入力 − ソート前のデータ: 802 630 20 745 52 3

  2. 配列を使ってC++でスタックを実装する方法【サンプルコード付きで解説】

    スタック(Stack)は、要素の集合を管理するための抽象データ構造の一つです。最大の特徴はLIFO(Last In, First Out:後入れ先出し)方式を採用している点で、最後に追加された要素ほど最初に取り出されます。本記事では、C++の配列を使ってスタックを実装する方法を、完全なサンプルコードとともにわかりやすく解説します。スタックの主な操作スタックに対して行える基本的な操作には、次の3つがあります。Push(プッシュ) … スタックの頂上(トップ)に新しいデータを追加するPop(ポップ) … スタックのトップからデータを取り除くPeek(ピーク) … スタックのトップにあるデータを参照