目次
序文
今日も、バイナリ ツリーのソートという新しい知識ポイントを学び続けます。その前に、関連するソート アルゴリズムを学びました。配列を与えてから、その配列をソートします。次に、同様にバイナリソートツリーを構築し、ツリーの作成過程でソートすることもでき、ソート効果も得られます。
1.バイナリソートツリーとは何ですか?
バイナリ ソート ツリー。バイナリ検索ツリーとも呼ばれます。バイナリ検索ツリー とも呼ばれます。データ構造の一種です。一般に、リンク リスト構造よりもクエリ効率が高くなります 。
バイナリ ツリーが与えられた場合、次の条件が満たされる場合、それはバイナリ ソート ツリーです。
- 左側のサブツリーが空でない場合、左側のサブツリー上のすべてのノードの値は、そのルート ノードの値より小さくなります。
- 右のサブツリーが空でない場合、右のサブツリー上のすべてのノードの値はそのルート ノードの値より大きくなります。
- その左側と右側のサブツリーは両方ともバイナリ ソート ツリーです。
バイナリソートツリーの最大の利点は検索効率の高さであり、リンクリストを一つずつ検索するのに比べて、データのソート規則に従って検索することができます。
バイナリソートツリー図:
2. バイナリソートツリーの構築方法
たとえば、配列[62,88,58,47,35,73,51,99,37,93] が与えられた場合、まず最初の数値を取得し、この数値をルート ノード (標準) として使用して、それを構築します。次の図に示すように、数値がこれより大きい場合は右側のサブツリーに配置され、これより小さい場合は左側のサブツリーに配置されます。
ここでは、これらのノードが 1 つずつ挿入されていることがわかります。その後、再帰的挿入によってノードを作成し、順番に下にたどって、適切な位置を見つけて、挿入操作を実行できます。
3. 二分ソート木の操作
3.1 ノードの保存方法を定義する
#include<stdio.h>
#include<stdlib.h>
//二叉排序树节点存储方式
typedef int DataType;
typedef struct binarytreenode {
DataType data; //数据域
struct binarytreenode* left; //左指针
struct binarytreenode* right; //右指针
}BTnode;
3.2 ノードの挿入操作
ノードを挿入するには、まずノードを挿入する位置を見つける必要があります。次のノードから開始して、次のノードより小さい場合は左に移動し、大きい場合は右に移動して、葉ノードの位置が挿入されます。
コード:
//插入数据
void Insert_node(BTnode** root, DataType data) {
if (*root == NULL) {
*root = (BTnode*)malloc(sizeof(BTnode));
if (!*root) {
printf("ERROR\n");
exit(-1);
}
(*root)->data = data;
(*root)->left = NULL;
(*root)->right = NULL;
}
else if ((*root)->data <= data)
Insert_node(&(*root)->right, data);
else if ((*root)->data > data)
Insert_node(&(*root)->left, data);
}
3.2 バイナリソートツリーの作成
バイナリソートツリーを作成するには、ノードを 1 つずつ挿入し、最後にルートノードを返すだけです。コードは以下のように表示されます。
//创建排序二叉树
BTnode* Create_sortBtree(DataType* arr, int size) {
if (!arr)
return NULL;
else {
BTnode* T = NULL;
for (int i = 0; i < size; i++) {
Insert_node(&T, arr[i]);
}
return T;
}
}
3.4 トラバーサル出力(インオーダートラバーサル)
//中序遍历排序二叉树
void mid_travel(BTnode* T)
{
if (!T)
return;
mid_travel(T->left);
printf("%d ", T->data);
mid_travel(T->right);
}
3.5 データ検索操作
バイナリソートツリー内で特定の値ノードを検索し、このノードを返す操作。これは、再帰的と非再帰的という 2 つの方法で実現できます。コードは次のとおりです。
再帰的な実装:
BTnode* Btree_search(BTnode* root, DataType target) {
if (!root)
return NULL;
if (target == root->data) {
return root;
}
return target > root->data ? Btree_search(root->right, target) : Btree_search(root->left, target);
}
非再帰的実装 (反復的実装):
//非递归查找
BTnode* Btree_search_fa(BTnode* T, DataType target) {
BTnode* p = T;
while (p) {
if (p->data == target)
{
return p;
}
p = target > p->data ? p->right : p->left;
}
return NULL;
}
3.6 最大値と最小値を取得する
ソートされた二分木の最大値または最小値を取得するには、端的に言えば、右端と左端のノードを見つけるだけです。ソートされた二分木の 2 つの最大値は、両端にあります。コードは以下のように表示されます。
最大値を取得する
//获取最大值
int Btree_max(BTnode* T) {
BTnode* cur = T;
while (cur->right) {
cur = cur->right;
}
return cur->data;
}
最小値を取得する
//获取最小值
int Btree_min(BTnode* T) {
BTnode* cur = T;
while (cur->left) {
cur = cur->left;
}
return cur->data;
}
3.7 ノードの削除操作
ノードを削除すると、ソートされたバイナリ ツリーの構造が損傷する可能性があるため、いくつかのケースに応じて処理する必要があります。1. リーフ ノードを削除する場合、リーフ ノードの左右のノードは空であるため、バイナリ ソート ツリーの構造に影響を与えないため、直接削除できます。 1 つの左側のサブツリー、または右側のサブツリーがある場合は、ノードの左側のノードまたは右側のノードを見つけて、削除するノードを置き換えるだけで済みます。 3. 削除するノードに左側と右側の両方のサブツリーがある場合、このノードを置き換えるには、このノードよりも 1 ビット大きいか 1 ビット小さいノードを見つけるためにトラバースする必要があります。以下に示すように:
1. リーフノードの削除
2.左 (右) サブツリーが 1 つだけあるノードを削除します。
3. 左右のサブツリーを持つノードを削除します
コード:
//删除节点
void Btree_del(BTnode* T, DataType l) {
if (!T) {
printf("fuck no\n");
return;
}
//找到这个要删除节点的父节点
BTnode* p = T, * f = NULL;
while (p) {
if (p->data == l)
{
break;
}
f = p;
p = l > p->data ? p->right : p->left;
}
if (!p)
{
printf("没有这个节点\n");
return;
}
BTnode* target = p;//此时的要删除目标节点
BTnode* par = f; //此时要删除节点的父节点
//第一种情况 此节点只有一个子树的时候
if (!target->left && target->right != NULL)
{
if (target->data > par->data) {
par->right = target->right;
}
else {
par->left = target->right;
}
free(target);//释放空间
target = NULL;
}
else if (target->left != NULL && !target->right) {
if (target->data > par->data) {
par->right = target->left;
}
else {
par->left = target->left;
}
free(target);
target = NULL;
}
//第二种情况,如果删除的是叶节点,直接删除即可
else if (!target->left && !target->right) {
if (target->data > par->data) {
par->right = NULL;
}
else {
par->left = NULL;
}
free(target);
target = NULL;
}
//第三种情况,如果左右子树都存在的话
//可以用右子树的最小元素
//或者左子树的最大元素来替代被删除的节点
//我这里就直接去用左树的最大代替这个节点
else
{
BTnode* Lchild = target->left;
while (Lchild->right != NULL) {
Lchild = Lchild->right;
}
if (target->data > par->data) {
par->right = Lchild;
}
else {
par->left = Lchild;
}
free(target);
target = NULL;
}
printf("Deleting successfully\n");
}
3.8 バイナリソートツリーを破棄する
//销毁
void Destory_btree(BTnode* T) {
if (!T)
return;
BTnode* cur = T;
if (cur->left)
Destory_btree(cur->left);
if (cur->right)
Destory_btree(cur->right);
free(T);
}
4. 完全なコード
#include<stdio.h>
#include<stdlib.h>
//二叉排序树节点存储方式
typedef int DataType;
typedef struct binarytreenode {
DataType data; //数据域
struct binarytreenode* left; //左指针
struct binarytreenode* right; //右指针
}BTnode;
//插入数据
void Insert_node(BTnode** root, DataType data) {
if (*root == NULL) {
*root = (BTnode*)malloc(sizeof(BTnode));
if (!*root) {
printf("ERROR\n");
exit(-1);
}
(*root)->data = data;
(*root)->left = NULL;
(*root)->right = NULL;
}
else if ((*root)->data <= data)
Insert_node(&(*root)->right, data);
else if ((*root)->data > data)
Insert_node(&(*root)->left, data);
}
//创建排序二叉树
BTnode* Create_sortBtree(DataType* arr, int size) {
if (!arr)
return NULL;
else {
BTnode* T = NULL;
for (int i = 0; i < size; i++) {
Insert_node(&T, arr[i]);
}
return T;
}
}
//中序遍历排序二叉树
void mid_travel(BTnode* T)
{
if (!T)
return;
mid_travel(T->left);
printf("%d ", T->data);
mid_travel(T->right);
}
//递归查找数据
BTnode* Btree_search(BTnode* root, DataType target) {
if (!root)
return NULL;
if (target == root->data) {
return root;
}
return target > root->data ? Btree_search(root->right, target) : Btree_search(root->left, target);
}
//非递归查找
BTnode* Btree_search_fa(BTnode* T, DataType target) {
BTnode* p = T, * f = NULL;
while (p) {
if (p->data == target)
{
return f;
}
f = p;
p = target > p->data ? p->right : p->left;
}
return NULL;
}
//获取最大值
int Btree_max(BTnode* T) {
BTnode* cur = T;
while (cur->right) {
cur = cur->right;
}
return cur->data;
}
//获取最小值
int Btree_min(BTnode* T) {
BTnode* cur = T;
while (cur->left) {
cur = cur->left;
}
return cur->data;
}
//删除节点
void Btree_del(BTnode* T, DataType l) {
if (!T) {
printf("fuck no\n");
return;
}
//找到这个要删除节点的父节点
BTnode* p = T, * f = NULL;
while (p) {
if (p->data == l)
{
break;
}
f = p;
p = l > p->data ? p->right : p->left;
}
if (!p)
{
printf("没有这个节点\n");
return;
}
BTnode* target = p;//此时的要删除目标节点
BTnode* par = f; //此时要删除节点的父节点
//第一种情况 此节点只有一个子树的时候
if (!target->left && target->right != NULL)
{
if (target->data > par->data) {
par->right = target->right;
}
else {
par->left = target->right;
}
free(target);//释放空间
target = NULL;
}
else if (target->left != NULL && !target->right) {
if (target->data > par->data) {
par->right = target->left;
}
else {
par->left = target->left;
}
free(target);
target = NULL;
}
//第二种情况,如果删除的是叶节点,直接删除即可
else if (!target->left && !target->right) {
if (target->data > par->data) {
par->right = NULL;
}
else {
par->left = NULL;
}
free(target);
target = NULL;
}
//第三种情况,如果左右子树都存在的话
//可以用右子树的最小元素
//或者左子树的最大元素来替代被删除的节点
//我这里就直接去用左树的最大代替这个节点
else
{
BTnode* Lchild = target->left;
while (Lchild->right != NULL) {
Lchild = Lchild->right;
}
if (target->data > par->data) {
par->right = Lchild;
}
else {
par->left = Lchild;
}
free(target);
target = NULL;
}
printf("Deleting successfully\n");
}
//销毁
void Destory_btree(BTnode* T) {
if (!T)
return;
BTnode* cur = T;
if (cur->left)
Destory_btree(cur->left);
if (cur->right)
Destory_btree(cur->right);
free(T);
}
int main()
{
int a[] = { 53,17,78,9,45,65,87,23 };
//创建二叉排序树
BTnode* T = Create_sortBtree(a, sizeof(a) / sizeof(int));
mid_travel(T);//遍历输出
puts("");
//删除最大最小值
printf("max:%d min:%d\n", Btree_max(T), Btree_min(T));
//查找
BTnode* find = Btree_search(T, 23);
printf("查找结果%d\n", find->data);
//删除节点
Btree_del(T, 45);
mid_travel(T);
puts("");
//销毁操作
Destory_btree(T);
}
//输出结果:
//9 17 23 45 53 65 78 87
//max:87 min : 9
//查找结果23
//Deleting successfully
//9 17 23 53 65 78 87
以上がバイナリソートツリーについての説明です。皆さん、建国記念日おめでとうございます!
壁紙を共有する: