バイナリソートツリーの定義
バイナリ ソート ツリー (バイナリ検索ツリーとも呼ばれます) は、並べ替えと検索の両方に役立つ特別なバイナリ ツリーです。
定義:
バイナリ ソート ツリーは、空のバイナリ ツリー、または次のプロパティを持つバイナリ ツリーのいずれかです。
- 左側のサブツリー上のすべてのノードのキーは、ルート ノードのキーよりも小さくなります。
- 右側のサブツリー上のすべてのノードのキーは、ルート ノードのキーよりも大きくなります。
- 左側のサブツリーと右側のサブツリーはそれぞれ二分木です。
//二叉排序树结点
typedef int KeyType;
typedef struct {
KeyType key;
char info[];
}ElemType;
typedef struct BSTNode{
ElemType data;
struct BSTNode * lchild;
struct BSTNode * rchild;
}BSTNode,*BSTree;
左サブツリー ノード値 < ルート ノード値 < 右サブツリー ノード値 "
> \quad\qquad\qquad\qquad \Downarrow">
順序トラバーサルを実行して、増加する順序シーケンスを取得します。
検索操作
バイナリ ソート ツリーは順序付きリストとみなすことができるため、バイナリ ソート ツリーでの検索は二分探索に似ており、徐々に検索範囲を狭めるプロセスでもあります。
アルゴリズムの説明:
① バイナリソートツリーが空の場合、検索は失敗し、null ポインタが返されます。
② バイナリソートツリーが空でない場合は、指定されたキーをルートノードのキーと比較します。
- それらが等しい場合、検索は成功し、ルート ノード ポインタが返されます。
- ルート ノードより小さい場合は、左側のサブツリーを再帰的に検索します。
- ルート ノードより大きい場合は、右側のサブツリーを再帰的に検索します。
アルゴリズムの説明:
BSTree SearchBST(BSTree T,KeyType key){
if((!T)||key==T->data.key)
return T;
else if(key<T->data.key)
return SearchBST(T->lchild,key);
else
return SearchBST(T->rchild,key);
}
挿入操作
バイナリソートツリーの挿入操作は検索に基づいています。バイナリソートツリーに key のキー値を持つノード * S を挿入するには、ルートノードから下方向に検索し、ツリーの途中に key と等しいキーを持つノードがある場合にのみ挿入する必要があります。新しく挿入されたノードは、新しく追加されたリーフ ノードである必要があり、検索部分が成功したときに検索パス上で最後に訪問したノードの左または右の子ノードである必要があります。
アルゴリズムの説明
① 2分ソートツリーが空の場合、挿入対象のノード *S をルートノードとして空のツリーに挿入します。
② バイナリ ソート ツリーが空でない場合は、指定されたキーとルート ノードのキー (T->data.key) を比較します。
- key< T->data.key の場合、*S を左側のサブツリーに挿入します。
- key>T->data.key の場合、*S を右側のサブツリーに挿入します。
int InsertBST(BSTree &T, ElemType e) {
if (!T) {
T = (BSTree) malloc(sizeof(BSTNode));
T->data = e;
T->lchild = T->rchild = NULL;
return 1;
} else if (e.key == T->data.key)
return 0;
else if (e.key < T->data.key)
return InsertBST(T->lchild, e);
else if (e.key > T->data.key)
return InsertBST(T->rchild, e);
}
削除操作
削除されるノードは、バイナリ ソート ツリー内の任意のノードであり、ノードの削除後、バイナリ ソート ツリーの特性を維持するために、その位置に応じて親ノードとその関連ノードのポインタを変更する必要があります。
削除されたノード z がリーフ ノードの場合は、直接削除され、バイナリ ソート ツリーのように動作しません。
ノード z に左側のサブツリーしかない場合、z のサブツリーを z の親ノードのサブツリーにして、z の位置を置き換えます。
ノード z に右のサブツリーしかない場合、z のサブツリーを z の親ノードのサブツリーにして、z の位置を置き換えます。
ノード z の左右のサブツリーが空でない場合は、z を z の直接の先行者に置き換えてから、バイナリ ソート ツリーから直接の先行者を削除して、状況①または②に変換します。
ノード z の左右のサブツリーが空でない場合は、z を z の直接後続ノードに置き換え、次にこの直接後続ノードをバイナリ ソート ツリーから削除し、状況①または②に変換します。
アルゴリズムの説明:
- まず、キーワード key を使用して削除するノードを検索します。
① 削除されたノード z が葉ノードの場合は、直接削除され、バイナリ ソート ツリーの特性はありません。
② ノード z が左サブツリーのみ、または右サブツリーのみを持つ場合、z のサブツリーを z の位置を置き換えて z の親ノードのサブツリーにします。
③ ノード z の左右のサブツリーが空でない場合は、z を z の直接の後続者 (または直接の先行者) に置き換えてから、バイナリ ソート ツリーから直接の後続者 (または直接の先行者) を削除して、① または②の状況。
void DeleteBST(BSTree &T, KeyType key) {
BSTNode *z = T; //待删除的结点
BSTNode *f = NULL; //待删除结点 *z 的双亲结点
/**----------------------- while循环从根开始查找关键字等于key的结点*z -----------------------*/
while (z) {
if (z->data.key == key)
break; //找到关键字等于key的结点 *z
f = z; //*f 为 *p的双亲结点
if (z->data.key > key)
z = z->lchild; //在*z 的左子树中继续查找
else
z = z->rchild; //在 *p的右子树中继续查找
}
if (!z)return; //找不到待删除的结点;
/**------------ 考虑3中情况实现p所指子树内部的处理:*p左右子树不为空、无左子树、无右子树 ------------*/
BSTNode *q = z;
if (z->lchild && z->rchild) {
//待删除结点*z 左右子树均不为空
BSTNode *s = z->lchild;
while (s->rchild) {
//在*p的左子树中继续查找其前驱结点,即最右下结点
q = s;
s = s->rchild; //向右到尽头
}
z->data = s->data; //s指向待删除结点的前驱
if (q != z)
q->rchild = s->lchild; //重接*q的右子树
else
q->lchild = s->lchild; //重接*q的左子树
delete s;
return;
} else if (!z->rchild) {
//待删除结点*p无右子树结点,只需重接其左子树
z = z->lchild;
} else if (!z->lchild) {
//待删除结点*z 无左子树结点,只需重接其右子树
z = z->rchild;
}
/**------------------------- 将p所指的子树挂接到其双亲结点*f相应的位置 -------------------------*/
if (!f) //被删除结点为根结点
T = z;
else if (q == f->lchild)
f->lchild = z; //挂接到*f的左子树位置
else
f->rchild = z; //挂接到*f的右子树位置
delete q;
}
作成オペレーション
バイナリ ソート ツリーの作成操作は、空のバイナリ ソート ツリーから開始され、ノードは入力されません。検索操作の後、新しいノードが現在のバイナリ ソート ツリーの適切な位置に挿入されます。
アルゴリズムの説明:
① 二分ソート木 T を空の木に初期化する。
②キーワードがkeyのノードを読み込みます。
③ 読み取ったキーワードキーが入力終了マークでない場合、以下の処理をループで実行します。
- これらの点をバイナリソートツリー T に挿入します。
- キーワードが key のノードを読み込みます。
void CreatBST(BSTree &T) {
T = NULL;
ElemType e;
cin >> e;
while (e.key != '\0') {
InsertBST(T, e);
cin >> e;
}
}