データ構造-----バイナリソートツリー

目次

序文

1.バイナリソートツリーとは何ですか?

2. バイナリソートツリーの構築方法

3. 二分ソート木の操作

3.1 ノードの保存方法を定義する

3.2 ノードの挿入操作

3.2 バイナリソートツリーの作成

3.4 トラバーサル出力(インオーダートラバーサル)

3.5 データ検索操作

3.6 最大値と最小値を取得する

3.7 ノードの削除操作

3.8 バイナリソートツリーを破棄する

4. 完全なコード


序文

        今日も、バイナリ ツリーのソートという新しい知識ポイントを学び続けます。その前に、関連するソート アルゴリズムを学びました。配列を与えてから、その配列をソートします。次に、同様にバイナリソートツリーを構築し、ツリーの作成過程でソートすることもでき、ソート効果も得られます。

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


以上がバイナリソートツリーについての説明です。皆さん、建国記念日おめでとうございます!

 壁紙を共有する:

おすすめ

転載: blog.csdn.net/m0_73633088/article/details/133443742
おすすめ