C++ でバイナリ ツリー レベルごとにデータを出力する

Syed Hassan Sabeeh Kazmi 2023年10月12日
  1. C++ でバイナリ ツリーのデータをレベルごとに出力するためのキューを使用したアルゴリズムの記述
  2. リンク リスト ノードを使用して、バイナリ ツリーのデータを C++ のレベルごとに出力する
  3. ハッシュ手法を使用して、C++ でレベルごとにバイナリ ツリーのデータを出力する
C++ でバイナリ ツリー レベルごとにデータを出力する

二分木のレベルごとのトラバーサルは、幅優先トラバーサルとして知られています。 このチュートリアルでは、C++ でバイナリ ツリーのデータをレベルごとに出力する方法を説明し、このタスクを実行するためのさまざまな方法について説明します。

スタックは 深さ優先 トラバーサル用であるため、キューを使用することは、バイナリ ツリーのデータをレベルごとに出力する適切な方法です。 ただし、この目標を達成するには 3つの方法があります。キュー (またはリンク リスト ノード) を使用して独自のアルゴリズムを作成するか、ハッシング手法を使用します。

C++ でバイナリ ツリーのデータをレベルごとに出力するためのキューを使用したアルゴリズムの記述

C++ では、#include<queue> を含めることでキューの機能を使用して、バイナリ ツリーのデータをレベルごとにソート順に出力するアルゴリズムを記述できます。 キューは FIFO (先入れ先出しの原則) に従うため、キューを初期化し、ルートをキューにプッシュする必要があります。

論理アルゴリズムを作成し、それを入力バイナリ ツリーに適用すると、null ノードを使用できます (ノードを 改行 で区切るため)。 null ノードとのやり取りは、未訪問のノードが現在のレベルに残っていないことを意味し、newline を出力できることを思い出してください。

各バイナリ ツリー レベルの最後には、その終了を表す null ノードが必要です。 タイプ ノードのデータを格納するキューを初期化し、root をそこにプッシュし、最後に null ノードをキューにプッシュすると、null ノードをレベルに挿入できます。

#include <iostream>
#include <queue>

using namespace std;

class binT_node {
 public:
  int nodeData;

  // declare left and right nodes of the binary tree
  binT_node* left;
  binT_node* right;

  binT_node(int data, binT_node* lef, binT_node* rig) {
    nodeData = data;
    left = lef;
    right = rig;
  }
};

void print_dataT(binT_node* root) {
  queue<binT_node*> que;
  que.push(root);

  while (true) {
    int orderLength = que.size();

    if (orderLength == 0) {
      break;
    }

    int i = 0;

    while (i < orderLength) {
      binT_node* nod = que.front();
      cout << (nod->nodeData) << " ";

      if (nod->left != NULL) {
        que.push(nod->left);
      }

      if (nod->right != NULL) {
        que.push(nod->right);
      }

      que.pop();
      i++;
    }

    cout << endl;
  }
}

int main() {
  binT_node* rootNode;
  rootNode = new binT_node(1, NULL, NULL);
  rootNode->left = new binT_node(2, NULL, NULL);
  rootNode->right = new binT_node(3, NULL, NULL);
  rootNode->left->left = new binT_node(4, NULL, NULL);
  rootNode->left->right = new binT_node(5, NULL, NULL);
  rootNode->right->left = new binT_node(6, NULL, NULL);
  rootNode->right->right = new binT_node(7, NULL, NULL);
  print_dataT(rootNode);

  return 0;
}

出力:

1
2 3
4 5 6 7

各反復で 1つのノードを出力する代わりに、1 回の反復で同じレベルのノードを出力することができます。これは、C++ で同様のアルゴリズムを作成する別のよく知られたアプローチです。

このアプローチは、キューを初期化し、それに root ノードと null ノードをプッシュすることを含め、最初のアプローチと少し似ています。

さらに、tempnull でない場合、ノード temp の値を出力し、null でない場合は temp.left をキューにプッシュし、null でない場合は temp.right をキューにプッシュし、繰り返します。 キューが空になるまでの手順。

リンク リスト ノードを使用して、バイナリ ツリーのデータを C++ のレベルごとに出力する

ノードにアクセスしてその子ノードを FIFO キューに入れることは、キューをリンク リストとして実装することもできるため、標準的な方法です。 ただし、C++ の関数を使用して、バイナリ ツリーの現在のレベルを出力することは可能です。

最初に、リンク リスト ノードの ArrayList を作成することにより、バイナリ ツリーのレベル順トラバーサルに queue(BFS) を使用します。 変数はキューのサイズを格納でき、各バイナリ ツリー レベルですべてのノードを取得および操作するのに役立ちます。

ここで、キュー サイズを格納する変数が 0 より大きい間、変数にアクセスし、子をキューに追加してすべてのノードを取得、出力、または操作します。

この再帰的なソリューションは完全に機能しますが、キューやハッシング手法ほど効果的ではありません。

#include <iostream>

using namespace std;

class listNode {
 public:
  int data;
  listNode *left, *right;
};

void print_data(listNode* root_node, int level_order);
int lev_height(listNode* node);
listNode* updatedNode(int data);

void printData_LevelOrder(listNode* root_node) {
  int heig = lev_height(root_node);
  int init;
  for (init = 1; init <= heig; init++) print_data(root_node, init);
}

void print_data(listNode* root_node, int level_order) {
  // in case of a `null` or empty root
  if (root_node == NULL) return;

  // in case if root represents `1`
  if (level_order == 1) cout << root_node->data << " ";

  // in case the root is greater than `1`
  else if (level_order > 1) {
    print_data(root_node->left, level_order - 1);
    print_data(root_node->right, level_order - 1);
  }
}

int lev_height(listNode* node_linkedlist) {
  // in case of empty or `NULL`
  if (node_linkedlist == NULL)
    return 0;
  else {
    int level_leftHeight = lev_height(node_linkedlist->left);
    int level_rightHeight = lev_height(node_linkedlist->right);

    // in case the left node is greater than the right node
    if (level_leftHeight > level_rightHeight) {
      return (level_leftHeight + 1);
    }

    // in case the right node is greater than the left node
    else {
      return (level_rightHeight + 1);
    }
  }
}

listNode* updatedNode(int _listdata) {
  listNode* list_node = new listNode();
  list_node->data = _listdata;
  list_node->left = NULL;
  list_node->right = NULL;

  return (list_node);
}

int main() {
  listNode* linkedlistNode = updatedNode(1);
  linkedlistNode->left = updatedNode(2);
  linkedlistNode->right = updatedNode(3);
  linkedlistNode->left->left = updatedNode(4);
  linkedlistNode->left->right = updatedNode(5);

  cout << "Level by Level Data Insertion to a Binary Tree is Complete! \n";
  printData_LevelOrder(linkedlistNode);

  return 0;
}

出力:

Level by Level Data Insertion to a Binary Tree is Complete!
1 2 3 4 5

printLevelOrderprintCurrentLevel は、このアプローチ (リンクされたリストを使用してバイナリ ツリーのデータを出力する) のサブ関数であり、それぞれ、特定のレベルですべてのノードを出力するか、バイナリ ツリーのレベル順トラバーサルを出力します。 .

さらに、printLevelOrder サブ関数は、printCurrentLevel 関数を利用して、バイナリ ツリーのすべてのレベルのルートからノードを 1つずつ出力できます。

Breath-First Search (BFS) の時間計算量は O(n^2) です。ここで、n はバイナリ ツリー ノードの最大数を表し、O(h) は、 h がバイナリ ツリーの完全な高さを表す C++ プログラム。

このチュートリアルで見つける各アルゴリズムは、以下を含むすべてのタイプのバイナリ ツリーを処理できます。 完全な、完全な、完全な、退化した、または病的な、歪んだ、バランスのとれた二分木。

ハッシュ手法を使用して、C++ でレベルごとにバイナリ ツリーのデータを出力する

ハッシュ テクニックの一部として、ハッシュ テーブルを使用すると、バイナリ ツリーのデータをレベルごとに出力できます。また、ハッシュ テーブルのルックアップ時間が平均で O(1) かかる非常に有用なデータ構造であることが証明されています。

アルゴリズムとバイナリデータ構造に関連するいくつかの問題を非常に効率的に解決して、時間の複雑さを軽減できます。

ハッシングには multimap が含まれています。これにより、1つのキーを複数の値にマッピングし、それを使用してバイナリ ツリー ノードとそのレベルを格納できます。

ハッシュ手法は、バイナリ ツリー レベル番号 (変数に格納されている) をキーとして使用し、親ノードまたはバイナリ ツリーの最初のレベルから開始して、各レベルに対応するすべてのノードを出力します。

#include <iostream>

// associative container that contains key-value pairs
// search, insert and remove elements in average constant-time complexity
#include <unordered_map>
#include <vector>  // initialize the vector contents

using namespace std;

// data structure creation | fulfill the purpose of storing data in a binary
// table
struct _hashnode {
  int key;
  _hashnode *left, *right;

  // `key` -> `_nodekey` will contain all the binary tree info to arrange the
  // nodes
  _hashnode(int _nodekey) {
    this->key = _nodekey;
    this->left = this->right = nullptr;
  }
};

// enable nodes storage in a map (to traverse the tree in a pre_order fashion)
// corresponding to the node's level
void hash_preorder(_hashnode* hash_root, int level, auto& map) {
  // initially: empty binary table
  if (hash_root == nullptr) {
    return;
  }

  // current node and its level insertion into the map
  map[level].push_back(hash_root->key);

  hash_preorder(hash_root->left, level + 1, map);
  hash_preorder(hash_root->right, level + 1, map);
}

// recursive function | fulfill the purpose of printing binary tree's level
// order traversal
void traversal_throughHash(_hashnode* hash_root) {
  // creation of a `null` or an empty map | to store nodes between the given
  // levels of a binary tree
  unordered_map<int, vector<int>> map;

  /* level-wise insertion of nodes to the map after the tree traversal */
  hash_preorder(hash_root, 1, map);

  for (int init = 1; map[init].size() > 0; init++) {
    cout << "[Binary Tree] Level " << init << ":- ";
    for (int juan : map[init]) {
      cout << juan << " ";
    }
    cout << endl;
  }
}

int main() {
  _hashnode* hash_Root = new _hashnode(15);
  hash_Root->left = new _hashnode(10);
  hash_Root->right = new _hashnode(20);
  hash_Root->left->left = new _hashnode(8);
  hash_Root->left->right = new _hashnode(12);
  hash_Root->right->left = new _hashnode(16);
  hash_Root->right->right = new _hashnode(25);
  hash_Root->right->right->right = new _hashnode(30);

  traversal_throughHash(hash_Root);

  return 0;
}

出力:

[Binary Tree] Level 1:- 15
[Binary Tree] Level 2:- 10 20
[Binary Tree] Level 3:- 8 12 16 25
[Binary Tree] Level 4:- 30

一般に、バイナリ ツリーは、最上位ノードが parent または root ノードであり、各 parent ノードが子ノードのペアを表すデータ構造として機能します。

二分木探索には 4つの一般的な方法があり、レベルごとの順序探索は最も効率的な方法の 1つです。

比較による並べ替え に基づくアルゴリズムで、n log n のパフォーマンスより優れているものはないというのは事実です。 バイナリ ティーの各ノードは、その子ノード (ai ≤ aj) 間の比較を表し、それらは n! の 1つを表します。

二分木には、n = (2^h) - 1 ノードが含まれます。ここで、h は二分木の高さを表し、葉以外のすべてのノードには、右と左の両方の子ノードがあります。

n! を持つツリーに対して h = [log(n!)] を計算することにより、バイナリ ツリーの高さを決定できます。 葉ノードと h = log(n + 1) 高さ。

Syed Hassan Sabeeh Kazmi avatar Syed Hassan Sabeeh Kazmi avatar

Hassan is a Software Engineer with a well-developed set of programming skills. He uses his knowledge and writing capabilities to produce interesting-to-read technical articles.

GitHub

関連記事 - C++ Tree