《数据结构与算法分析》学习笔记(五)——二叉树

时间:2021-12-08 03:50:30

(一)查找二叉树ADT

1、二叉查找树ADT性质:

    对于树中的每个节点X,它的左子树中所有关键字值都小于X的关键字值,而它的右子树值的关键字值都大于X的关键字值。

2、一些ADT的基本操作

结构定义

typedef int SearchTree_ElementType;

struct SearchTreeNode;            //这句话一定要加,要不下面这句不会成立。
typedef struct SearchTreeNode* SearchTree; struct SearchTreeNode
{
SearchTree_ElementType Element;
SearchTree Left;
SearchTree Right;
};

(1)建立空树:

    一般来说空树有些人习惯用保留一个空的节点,但是按照标准定义的话,树理应为NULL,采用后者。(附简单代码,复习递归思路)

//清空树
SearchTree SearchTree_MakeEmpty(SearchTree Root)
{
if (Root != NULL)
{
SearchTree_MakeEmpty(Root->Left);
SearchTree_MakeEmpty(Root->Right);
delete Root;
}
return NULL;
}

(2)Find

    使用简单递归思想写,代码简单,但是空间栈比较多,但是因为深度为logN,所以应该空间是可以接受的。

SearchTree_Position SearchTree_Find(SearchTree_ElementType X, SearchTree T)
{
if (T == NULL)
return NULL;
else if (X < T->Element)
SearchTree_Find(X, T->Left);
else if (X > T->Element)
SearchTree_Find(X, T->Right);
else
return T;
}

(3)FindMax和Min

//FindMax和FindMin
SearchTree_Position SearchTree_FindMax(SearchTree T)
{
if (T == NULL)
return NULL;
else if (T->Right == NULL)
return T;
else
SearchTree_FindMax(T->Right);
} SearchTree_Position SearchTree_FindMin(SearchTree T)
{
if (T == NULL)
return NULL;
else if (T->Left == NULL)
return T;
else
SearchTree_FindMax(T->Left);
}

(4)插入

    如果有重复单元进行插入,那可以选择加入一个count,记录加入多少次,而不用重复进行操作

//插入
SearchTree_Position SearchTree_Insert(SearchTree T,SearchTree_ElementType X)
{
if (T == NULL)
{
T = new SearchTreeNode;
if (T == NULL)
{
cout << "Out of Space" << endl;
}
else
{
T->Element = X;
T->Left = T->Right = NULL;
}
}
else if (T->Element > X)
SearchTree_Insert(T->Right, X);
else if (T->Element < X)
SearchTree_Insert(T->Left, X); return T;
}

(5)删除

    删除的情况有3种:

    a、没有儿子的,直接删除

    b、有一个儿子的,删除这个节点之后,把子节点接上去

    d、有两个儿子的,可以用右子树的最小值或者左子树的最大值代替该节点的数据并递归删除那个节点。

 

    如果删除的次数有限,那么可以使用一个tag进行记录即可,即可以使用策略称为惰性测量。

//删除
SearchTree_Position SearchTree_Delete(SearchTree T, SearchTree_ElementType X)
{
SearchTree_Position NodeTemp; if (T == NULL)
cout << "Not Found" << endl;
else if (T->Element > X)
SearchTree_Delete(T->Left, X);
else if (T->Element < X)
SearchTree_Delete(T->Right, X);
else
{
if (T->Left && T->Right) //两个儿子
{
NodeTemp = SearchTree_FindMin(T->Right);
T->Element = NodeTemp->Element;
SearchTree_Delete(T->Right, T->Element);
}
else
{
NodeTemp = T;
if (T->Left == NULL)
T = T->Right;
else if (T->Right == NULL)
T = T->Left; delete NodeTemp;
}
} return T;
}

 

 

(二)——AVL树

1、AVL树定义:

    每个节点的左子树和右子树的高度最多差1的二叉查找树(空树的高度定义为 -1)

2、旋转:

    如果删除使用惰性删除,那么可能破坏AVL树的基本操作就只能是——插入。所以采用一种操作称为旋转来对树进行简单修正。

(1)AVL不平衡情况分析

    假设必须平衡的点成为Node_A,那么有四种情况,(a d镜像   b c镜像)

a、对Node_A的左儿子的左子树进行一次插入
b、对Node_A的左儿子的右子树进行一次插入
c、对Node_A的右儿子的左子树进行一次插入
d、对Node_A的右儿子的右子树进行一次插入

     对于a,d使用单旋转进行修正,对于b,c使用双旋转进行修正。

(2)单旋转

A、图示效果

《数据结构与算法分析》学习笔记(五)——二叉树

     其中左图所示的是情况a,X和Z的高度差2,所以要进行修正,有图是通过单旋转进行的修正。

     方法:就是将K1拉起来,K2成为K1的右子树,Y成为K2的左子树。

B、参考代码

/**********************声明,类型定义**********************/
struct Avl_Node;
typedef struct AvlNode* Position;
typedef struct AvlNode* AvlTree; typedef int Avl_ElementType; /***********************函数声明**********************/ #define Max(a,b) (a>b?a:b) //单旋转
Position Avl_SingleRotateWithLeft(Position K2);
Position Avl_SingleRotateWithRight(Position K1); /***********************AVL数据结构定义**********************/
struct AvlNode
{
Avl_ElementType Element;
AvlTree Left;
AvlTree Right;
int Height;
};

    这个是ADT的数据格式声明

//单旋转
Position Avl_SingleRotateWithLeft(Position K2)
{
Position K1; K1 = K2->Left;
K2->Left = K1->Right;
K1->Right = K2; K2->Height = Max(Avl_Get_NodeHeight(K2->Left), Avl_Get_NodeHeight(K2->Right)) + 1; K1->Height = Max(Avl_Get_NodeHeight(K1->Left), K2->Height) + 1; return K1;
}
Position Avl_SingleRotateWithRight(Position K1)
{
Position K2; K2 = K1->Right;
K1->Right = K2->Left;
K2->Left = K1; K1->Height = Max(Avl_Get_NodeHeight(K1->Left), Avl_Get_NodeHeight(K1->Right))+1;
K2->Height = Max(Avl_Get_NodeHeight(K2->Right), K1->Height) + 1; return K2;
}

 

(3)双旋转

A、图示效果

《数据结构与算法分析》学习笔记(五)——二叉树

 

      其中左图就是情况b,BC和D的高度差2,所以要修正,但是通过单旋转并没有办法进行修正,所以使用双旋转进行修正

      方法:将K3成为根节点,K1,K2成为K3的子节点,B成为K1的右子树,C成为K2的左子树。

B、参考代码、

//双旋转
Position Avl_DoubleRotateWithLeft(Position K3)
{
K3->Left = Avl_SingleRotateWithRight(K3->Left); return Avl_SingleRotateWithLeft(K3);
}
Position Avl_DoubleRotateWithRight(Position K1)
{
K1->Right = Avl_SingleRotateWithLeft(K1->Right); return Avl_SingleRotateWithRight(K1);
}

3、AVL树的一些基本操作函数

#include "stdafx.h"
#include "AVL.h"
#include <iostream> using namespace std; //空树
AvlTree Avl_MakeEmpty(AvlTree T)
{
if (T != NULL)
{
Avl_MakeEmpty(T->Left);
Avl_MakeEmpty(T->Right);
free(T); }
return NULL;
} //查找
AvlTree Avl_Find(Avl_ElementType X, AvlTree T)
{
if (T == NULL)
{
return NULL;
cout << "Not Found!" << endl;
} if (X < T->Element)
{
return Avl_Find(X, T->Left);
}
else if (X > T->Element)
{
return Avl_Find(X, T->Right);
}
else
{
return T;
} } //查找极值
AvlTree Avl_FindMin(AvlTree T)
{
if (T == NULL)
{
return NULL;
}
else if (T->Right == NULL)
{
return T;
}
else
{
Avl_FindMin(T->Right);
}
} AvlTree Avl_FindMax(AvlTree T)
{
if (T == NULL)
{
return NULL;
}
else if (T->Left == NULL)
{
return T;
}
else
{
Avl_FindMin(T->Left);
}
} //获取树的高度,计算使用递归的方法
int Avl_Get_NodeHeight(Position P)
{
if (P == NULL)
return -1;
else
return P->Height;
} //单旋转
Position Avl_SingleRotateWithLeft(Position K2)
{
Position K1; K1 = K2->Left;
K2->Left = K1->Right;
K1->Right = K2; K2->Height = Max(Avl_Get_NodeHeight(K2->Left), Avl_Get_NodeHeight(K2->Right)) + 1; K1->Height = Max(Avl_Get_NodeHeight(K1->Left), K2->Height) + 1; return K1;
}
Position Avl_SingleRotateWithRight(Position K1)
{
Position K2; K2 = K1->Right;
K1->Right = K2->Left;
K2->Left = K1; K1->Height = Max(Avl_Get_NodeHeight(K1->Left), Avl_Get_NodeHeight(K1->Right))+1;
K2->Height = Max(Avl_Get_NodeHeight(K2->Right), K1->Height) + 1; return K2;
} //双旋转
Position Avl_DoubleRotateWithLeft(Position K3)
{
K3->Left = Avl_SingleRotateWithRight(K3->Left); return Avl_SingleRotateWithLeft(K3);
}
Position Avl_DoubleRotateWithRight(Position K1)
{
K1->Right = Avl_SingleRotateWithLeft(K1->Right); return Avl_SingleRotateWithRight(K1);
} //插入
AvlTree Avl_Insert(Avl_ElementType X, AvlTree T)
{ //空树
if (T == NULL)
{
T = new struct AvlNode;
if (T == NULL)
{
cout << "out of Space" << endl;
}
else
{
T->Element = X;
T->Height = 0;
T->Left = T->Right = NULL;
}
}
//在左子树
else if (X < T->Element)
{
Avl_Insert(X, T->Left);
if (Avl_Get_NodeHeight(T->Left) - Avl_Get_NodeHeight(T->Right) == 2)
{
if (X < T->Left->Element) //a情况
T = Avl_SingleRotateWithLeft(T);
else //b情况
T = Avl_DoubleRotateWithLeft(T);
}
}
else if (X>T->Element)
{
Avl_Insert(X, T->Right);
if (Avl_Get_NodeHeight(T->Right) - Avl_Get_NodeHeight(T->Left) == 2)
{
if (X < T->Right->Element) //c情况
T = Avl_DoubleRotateWithRight(T);
else //d情况
T = Avl_SingleRotateWithRight(T);
}
} T->Height = Max(Avl_Get_NodeHeight(T->Left), Avl_Get_NodeHeight(T->Right)) + 1;
return T;
}

 

(三)——树的遍历

1、三种遍历:先序、中序、后序

void PrintTree(SearchTree T)
{
if( T!= NULL)
{
PrintTree(T->Left);
PrintElement(T->Elemment);
PrintTree(T->Right);
}
}