ツリー:
:バイナリ検索ツリー
の空ツリーまたは次のプロパティを持つバイナリツリーのどちらかである:(バイナリ検索ツリー、バイナリ・ソートツリーも):それは左だ場合は、バイナリ検索ツリー(バイナリ検索ツリー)、サブツリーは、次に、全てのノードが少ないルートノードの値より左の部分木の値であり、空でない;それは空の右サブツリーのルートノットより全て大きいノードの右サブツリーでない場合点の値は、その左右のサブツリーは、バイナリソートツリーです。
原理:
検出プロセスバイナリソートの木と次善のバイナリツリーは通常、バイナリ・ソートツリーを格納するためのリンクリスト構造としたバイナリに似ています。キーの順序付けられたシーケンスを得るために、バイナリソートツリートラバーサル順、ランダムシーケンスは、ツリー構造は、ランダムシーケンスを順序付けする過程で、バイナリソートツリー構造によってシーケンスに順序付けされてもよいですプロセス。新しいノードが挿入されるたびには、バイナリソートツリーの新しいリーフノードであり、挿入操作は、他のノードを移動させることなく行われる、すなわち、非空の空から唯一つのノードポインタ変更ことができます。検索、挿入、ツリーの高い複雑さに等しい削除、O(ログ(N)) 。
:アルゴリズム検索
バイナリ検索ツリーが空の場合は1を、操作戻り動作時、そうでなければ、空、
まずテイクルート、Xは、ルートノード、リターンに等しい場合、
前記ノードが少ないルートノード以外である場合、再帰;左のサブツリーを探す
ノードがルートノードよりも大きい場合は4、再帰的に右のサブツリーを見つけます。
Node p = tree;
while (p != null) {
if (data < p.data) p = p.left;
else if (data > p.data) p = p.right;
else return p;
挿入アルゴリズム:
ツリーが空である1場合は、新しいノードが挿入され、直接に、そうでない場合は、次の手順を実行します。
2.ルートよりも大きいデータを挿入するデータ、右の部分木が空の場合、新しいデータを挿入する右サブツリーは、新しいデータが子ノードの右の位置に直接挿入され、空でない、右を通過続けますサブツリー、挿入位置を見つけます。
左の子を横断続行し、空でない;ルートノードデータより小さいデータを挿入し、左の部分木が空である場合、左サブツリーは、データに挿入され、次いで、新しいデータが左の子ノードの位置に直接挿入される3ツリーは、挿入位置を見つけます。
if (tree == null) {
tree = new Node(data);
return;
}
Node p = tree;
while (p != null) {
if (data > p.data) {
if (p.right == null) {
p.right = new Node(data);
return;
}
p = p.right;
} else { //data < p.data
if (p.left == null) {
p.left = new Node(data);
return;
}
p = p.left;
}
}
削除アルゴリズム:
ノードを削除したい場合1.最初のケースでは、あなたがnullにポインターを削除するノードに直接何の子ノード、親ノードのポイントを持っていません。たとえば、55削除する方法をノード。
2. 2番目の場合、唯一の左の子か右の子は、親ノードのポイントが削除されたノードの子にノードポインタを削除するには、あなたが一つのノードのみを削除したい場合はノードは、することができます。たとえば、あなたがノード削除する方法
あなたはノードが2人の子供を持って削除したい場合は3に第三のケースは、あなたがすること、それを置き換えるためにツリーまたは左の部分木の最大ノードに最小ノードの右の子ノードを見つける必要があります上のノードを削除します。次に、右側のサブツリーノードを削除するか、またはあなたが使用できるように、最小のサブツリーノードの最大を残しました
Node p = tree; //p 指向要删除的结点,初始化指向根节点
Node pp = null; //pp 记录的是 p 的父节点
while (p != null && p.data != data) {
pp = p;
if (data > p.data) p = p.right;
else p = p.left;
}
if (p == null) return; //没有找到
//要删除的节点有两个子节点
if (p.left != null && p.right != null) {//查找右子树中最小的节点
Node minP = p.right;
Node minPP = p; //minPP 表示 minP 的父节点
while (minP.left != null) {
minPP = minP;
minP = p.left;
}
p.data = minP.data; //将 minP 的数据替换到 p 中
p = minP; //下面就变成了删除 minP 了,要结合整个删除函数来看
pp = minPP;
}
//删除的是叶子节点或者仅有一个子节点
Node child; //p 的子节点
if (p.left != null) child = p.left;
else if (p.right != null) child = p.right;
else child = null;
if (pp == null) tree = child; // 删除的是根节点
else if (pp.left == p) pp.left = child;
else pp.right = child;
平衡二分木:
プロパティ:
それは星や空の木だったりバイナリツリーには、次の特性を有します:
その左サブツリー及び右サブツリーは、バイナリツリー、および左サブツリーの深さとしない1以下の右サブツリーの差の絶対値がバランスしています。
バランス係数BFマイナスノードの左の部分木の深さのために、その右部分木で定義されたノードのバイナリツリーの深さは、すべてのノードのバイナリツリーのバランスバランス要因とすることができる場合にのみ-1、0、。
限りバイナリツリーとしてノードは、平衡二分木風雲がバランスを失った、1よりも絶対値が大きいのバランス係数を有します。
コードは他の誰かのブログを参照してくださいので、それは、ないので。
#include <stdio.h>
#include <stdlib.h>
//分别定义平衡因子数
#define LH +1
#define EH 0
#define RH -1
typedef int ElemType;
typedef enum {false,true} bool;
//定义二叉排序树
typedef struct BSTNode{
ElemType data;
int bf;//balance flag
struct BSTNode *lchild,*rchild;
}*BSTree,BSTNode;
//对以 p 为根结点的二叉树做右旋处理,令 p 指针指向新的树根结点
void R_Rotate(BSTree* p)
{
//借助文章中的图 5 所示加以理解,其中结点 A 为 p 指针指向的根结点
BSTree lc = (*p)->lchild;
(*p)->lchild = lc->rchild;
lc->rchild = *p;
*p = lc;
}
////对以 p 为根结点的二叉树做左旋处理,令 p 指针指向新的树根结点
void L_Rotate(BSTree* p)
{
//借助文章中的图 6 所示加以理解,其中结点 A 为 p 指针指向的根结点
BSTree rc = (*p)->rchild;
(*p)->rchild = rc->lchild;
rc->lchild = *p;
*p = rc;
}
//对以指针 T 所指向结点为根结点的二叉树作左子树的平衡处理,令指针 T 指向新的根结点
void LeftBalance(BSTree* T)
{
BSTree lc,rd;
lc = (*T)->lchild;
//查看以 T 的左子树为根结点的子树,失去平衡的原因,如果 bf 值为 1 ,则说明添加在左子树为根结点的左子树中,需要对其进行右旋处理;反之,如果 bf 值为 -1,说明添加在以左子树为根结点的右子树中,需要进行双向先左旋后右旋的处理
switch (lc->bf)
{
case LH:
(*T)->bf = lc->bf = EH;
R_Rotate(T);
break;
case RH:
rd = lc->rchild;
switch(rd->bf)
{
case LH:
(*T)->bf = RH;
lc->bf = EH;
break;
case EH:
(*T)->bf = lc->bf = EH;
break;
case RH:
(*T)->bf = EH;
lc->bf = LH;
break;
}
rd->bf = EH;
L_Rotate(&(*T)->lchild);
R_Rotate(T);
break;
}
}
//右子树的平衡处理同左子树的平衡处理完全类似
void RightBalance(BSTree* T)
{
BSTree lc,rd;
lc= (*T)->rchild;
switch (lc->bf)
{
case RH:
(*T)->bf = lc->bf = EH;
L_Rotate(T);
break;
case LH:
rd = lc->lchild;
switch(rd->bf)
{
case LH:
(*T)->bf = EH;
lc->bf = RH;
break;
case EH:
(*T)->bf = lc->bf = EH;
break;
case RH:
(*T)->bf = EH;
lc->bf = LH;
break;
}
rd->bf = EH;
R_Rotate(&(*T)->rchild);
L_Rotate(T);
break;
}
}
int InsertAVL(BSTree* T,ElemType e,bool* taller)
{
//如果本身为空树,则直接添加 e 为根结点
if ((*T)==NULL)
{
(*T)=(BSTree)malloc(sizeof(BSTNode));
(*T)->bf = EH;
(*T)->data = e;
(*T)->lchild = NULL;
(*T)->rchild = NULL;
*taller=true;
}
//如果二叉排序树中已经存在 e ,则不做任何处理
else if (e == (*T)->data)
{
*taller = false;
return 0;
}
//如果 e 小于结点 T 的数据域,则插入到 T 的左子树中
else if (e < (*T)->data)
{
//如果插入过程,不会影响树本身的平衡,则直接结束
if(!InsertAVL(&(*T)->lchild,e,taller))
return 0;
//判断插入过程是否会导致整棵树的深度 +1
if(*taller)
{
//判断根结点 T 的平衡因子是多少,由于是在其左子树添加新结点的过程中导致失去平衡,所以当 T 结点的平衡因子本身为 1 时,需要进行左子树的平衡处理,否则更新树中各结点的平衡因子数
switch ((*T)->bf)
{
case LH:
LeftBalance(T);
*taller = false;
break;
case EH:
(*T)->bf = LH;
*taller = true;
break;
case RH:
(*T)->bf = EH;
*taller = false;
break;
}
}
}
//同样,当 e>T->data 时,需要插入到以 T 为根结点的树的右子树中,同样需要做和以上同样的操作
else
{
if(!InsertAVL(&(*T)->rchild,e,taller))
return 0;
if (*taller)
{
switch ((*T)->bf)
{
case LH:
(*T)->bf = EH;
*taller = false;
break;
case EH:
(*T)->bf = RH;
*taller = true;
break;
case RH:
RightBalance(T);
*taller = false;
break;
}
}
}
return 1;
}
//判断现有平衡二叉树中是否已经具有数据域为 e 的结点
bool FindNode(BSTree root,ElemType e,BSTree* pos)
{
BSTree pt = root;
(*pos) = NULL;
while(pt)
{
if (pt->data == e)
{
//找到节点,pos指向该节点并返回true
(*pos) = pt;
return true;
}
else if (pt->data>e)
{
pt = pt->lchild;
}
else
pt = pt->rchild;
}
return false;
}
//中序遍历平衡二叉树
void InorderTra(BSTree root)
{
if(root->lchild)
InorderTra(root->lchild);
printf("%d ",root->data);
if(root->rchild)
InorderTra(root->rchild);
}
int main()
{
int i,nArr[] = {1,23,45,34,98,9,4,35,23};
BSTree root=NULL,pos;
bool taller;
//用 nArr查找表构建平衡二叉树(不断插入数据的过程)
for (i=0;i<9;i++)
{
InsertAVL(&root,nArr[i],&taller);
}
//中序遍历输出
InorderTra(root);
//判断平衡二叉树中是否含有数据域为 103 的数据
if(FindNode(root,103,&pos))
printf("\n%d\n",pos->data);
else
printf("\nNot find this Node\n");
return 0;
}