BSTに挿入する
二分探索木を構築します。
「BSTに挿入する」はCoddyKit上の無料C Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C Academyコースには全4レッスンが含まれています。
BSTの順序規則
二分探索木(BST)は、二分木にもう1つ規則を加えたものです。すべてのノードについて、左部分木の値はすべてそのノードより小さく、右部分木の値はすべて大きくなります。
この順序付けにより、木の高さに比例する時間で検索、挿入、削除を行えます。
値が属する場所
挿入では、ルートから開始して比較します。新しい値が小さければ左へ、大きければ右へ進みます。
空いている場所(NULL)に到達するまで繰り返します。そこが新しいノードの入る場所です。
/* insert 7 into:
* 10
* / \
* 5 15
* 7 < 10 -> left; 7 > 5 -> right of 5
*/create_nodeヘルパー
挿入では新しい葉ノードを作成するため、ノードを確保して初期化するコンストラクターを再利用します。
新しく挿入されたノードは常に葉なので、両方の子はNULLから始まります。
Node *create_node(int value) {
Node *n = malloc(sizeof(Node));
if (!n) return NULL;
n->value = value;
n->left = n->right = NULL;
return n;
}再帰的な挿入
最もすっきりした挿入方法は、再帰を使い、場合によっては新しくなった部分木のルートを返す方法です。
部分木が空なら新しいノードを返します。それ以外の場合は左または右へ再帰し、その結果を再接続してから、変更されていないルートを返します。
Node *insert(Node *root, int value) {
if (root == NULL)
return create_node(value);
if (value < root->value)
root->left = insert(root->left, value);
else if (value > root->value)
root->right = insert(root->right, value);
return root; /* equal: ignore duplicate */
}ルートを返す理由
部分木のルートを返すと、親側でリンクを1行で再接続できます。root->left = insert(root->left, v)のように記述します。
部分木が空だった場合は、返された新しいノードが子になります。空でなかった場合は同じルートが返され、リンクは変わりません。
/* The assignment does double duty:
* - empty case: stores the new node
* - non-empty: stores the same pointer back (no-op)
*/
root->left = insert(root->left, value);重複値の扱い
実際のBSTでは、同じ値をどう扱うかを決める必要があります。よくある選択肢は重複を無視することで、ここでのinsertも等しい場合の分岐を持たないことでそのように動作します。
ほかの方法として、ノードごとに個数を保持したり、重複値を常に片側へ送ったりすることもできます。
if (value < root->value)
root->left = insert(root->left, value);
else if (value > root->value)
root->right = insert(root->right, value);
/* value == root->value -> do nothing */BSTを構築する
値の列を挿入すると、挿入順序に応じた形状の木ができます。
ここでは複数の数値を挿入し、順序規則が保たれていることを確認するため、ルートの直接の子を表示します。
#include <stdio.h>
#include <stdlib.h>
typedef struct Node { int value; struct Node *left, *right; } Node;
Node *create_node(int v){ Node *n=malloc(sizeof(Node)); n->value=v; n->left=n->right=NULL; return n; }
Node *insert(Node *r,int v){
if(!r) return create_node(v);
if(v<r->value) r->left=insert(r->left,v);
else if(v>r->value) r->right=insert(r->right,v);
return r;
}
int main(void){
Node *root = NULL;
int data[] = {10,5,15,3,7};
for(int i=0;i<5;i++) root=insert(root,data[i]);
printf("root=%d left=%d right=%d\n", root->value, root->left->value, root->right->value);
return 0;
}反復的な挿入
再帰を使わずに挿入することもできます。ポインターで下へ進み、親を記録しながら空いている場所を探します。
その後、新しいノードを親の正しい側に接続します。
void insert_iter(Node **rootp, int value) {
Node *cur = *rootp, *parent = NULL;
while (cur) {
parent = cur;
cur = (value < cur->value) ? cur->left : cur->right;
}
Node *n = create_node(value);
if (!parent) *rootp = n;
else if (value < parent->value) parent->left = n;
else parent->right = n;
}挿入順序が木の形を決める
1、2、3、4、5をソート済みの順序で挿入すると、リンクリストのような退化した木になり、高さは要素数と等しくなります。
バランスのよい順序で挿入すると、高さをlog(n)に近く保てます。バランスは検索速度に直接影響します。
/* sorted insert 1..5 ->
* 1
* \
* 2
* \
* 3 (height = 4, like a list)
*/挿入のコスト
各挿入ではルートから葉までの1本の経路をたどるため、木の高さに比例する処理量になります。
バランスのよい木ではおよそlog(n)回の比較ですが、退化した木ではn回になる場合があります。これが自己平衡木が存在する理由です。
完全な挿入デモ
このプログラムは値を挿入した後、ノード数を数えて、重複しない5つの値が格納され、重複値が無視されたことを確認します。
重複する10を挿入しても個数が増えないのは、insertが同じ値を破棄するためです。
#include <stdio.h>
#include <stdlib.h>
typedef struct Node { int value; struct Node *left, *right; } Node;
Node *cn(int v){ Node *n=malloc(sizeof(Node)); n->value=v; n->left=n->right=NULL; return n; }
Node *insert(Node *r,int v){
if(!r) return cn(v);
if(v<r->value) r->left=insert(r->left,v);
else if(v>r->value) r->right=insert(r->right,v);
return r;
}
int count(Node *r){ return r? 1+count(r->left)+count(r->right):0; }
int main(void){
Node *root=NULL;
int d[]={10,5,15,10,20};
for(int i=0;i<5;i++) root=insert(root,d[i]);
printf("count=%d\n", count(root));
return 0;
}簡単な確認
挿入の動作について考えてみましょう。
まとめ
BSTへの挿入では、新しい値を各ノードと比較し、小さければ左へ、大きければ右へ進み、空いている位置が見つかるまで繰り返します。
再帰形式では部分木のルートを返すため、親ノードはリンクをきれいに付け直せます。挿入コストは木の高さに応じて増えるため、挿入順序が重要です。
よくある質問
「BSTに挿入する」レッスンは無料ですか?
はい。「BSTに挿入する」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C Academyコースには全4レッスンが含まれています。
「BSTに挿入する」で何を学びますか?
二分探索木を構築します。 ブラウザで直接実行するハンズオンコードでC Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「BSTに挿入する」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC Academyレッスンでコードを書いて実行できますか?
はい。すべてのC Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 木構造のノードと構造
- BSTに挿入する
- 走査
- 検索と解放