二叉树相关
统计二叉树中结点的个数
int Node_Count(BiTree T)
{
if (T = NULL)
return 0;
else
return Node_Count(T->lchild) + Node_Count(T->rchild) + 1;
}
计算二叉树中叶子结点的个数
int Leaf_Count(BiTree T)
{
if (!T)
return 0;
if (!T->lchild && !T->rchild) // 如果二叉树左子树和右子树皆为空,说明该二叉树根节点为叶子结点,加1
return 1;
else
return Leaf_Count(T->lchild) + Leaf_Count(T->rchild);
}
计算二叉树中非叶子结点的个数
int Count(BiTree T)
{
if (!T)
return 0;
if (T->lchild || T->rchild)
return Count(T->lchild) + Count(T->rchild) + 1;
}
统计二叉树的度为1的结点个数
int Count(BiTree T)
{
if (!T)
return 0;
if (T->lchild && T->rchild)
return Count(T->lchild) + Count(T->rchild);
else
return 1;
}
计算二叉树中度为2的结点
int Count(BiTree T)
{
if (!T)
return 0;
else
{
if (T->lchild && T->rchild)
return Count(T->lchild) + Count(T->rchild) + 1;
else
return Count(T->lchild) + Count(T->rchild);
}
}
计算二叉树的宽度
思想:开辟一个数组count[树高],遍历每一个结点。在某层i中,每遍历到一个结点,就执行一次count[i]++。当遍历完所有的结点后,取count数组中的最大值就是树最宽的那一层的结点个数,即书的宽度。
int MAX = -1000;
int w[100];
int getWidth(BiTree T, int h)
{
if (T == NULL)
return *max_element(w + 1, w + h + 1); // 返回count数组中的最大值,即树的宽度
w[h]++; // 某层中每遍历到一个结点,该层的宽度就加1
if (MAX < w[h])
MAX = w[h]; // 发现了更宽的层
getWidth(T->lchild, h + 1); // 继续下一层
getWidth(T->rchild, h + 1);
}
调用方法:cout << getWidth(T, 1) << endl;
用非递归算法计算二叉树的高度
思想:使用层次遍历,利用队列指针,设置一个专门的指针last专门指向一层元素的最后一个元素。将一层中最后一个元素之前的元素依次出队,并将每个元素的孩子结点入队,那么当一层之中最后一个结点出队之时,这一层所有的孩子结点已经全部入队,即此时的尾指针只想了下一层最后一个结点之后,我们将last指向尾指针,以代表本层遍历结束 。
int Btdepth(BiTree &T)
{
int last, level = 0;
SqQueue Q;
InitQueue(Q);
BiTree p = T;
EnQueue(Q, T);
last = Q.rear;
while (!IsEmpty(Q))
{
DeQueue(Q, p);
if (p->lchild)
EnQueue(Q, p->lchild);
if (p->rchild)
EnQueue(Q, p->rchild);
if (Q.front == last)
{
level++;
last = Q.rear;
}
}
return level;
}
判断二叉树是否为平衡二叉树
思想:采用后序遍历的递归算法,判断以每一个结点为根的子树是否都满足平衡条件。
void Is_AVL(BiTree T, int balance, int h) // balance为二叉树的平衡标记,h为二叉树的高
{
int tl = 0, tr = 0, hl = 0, hr = 0; //左、右子树的平衡标记和高度
if (T == NULL) //空树,高度为0
{
h = 0;
balance = 1;
}
else if (T->lchild == NULL && T->rchild == NULL) //仅有根结点。高度为1
{
h = 1;
balance = 1;
}
else
{
Is_AVL(T->lchild, bl, hl); //递归判断左子树
Is_AVL(T->rchild, br, hr); //递归判断右子树
h = (hl > hr ? hl : hr) + 1;
if (abs(hl - hr) < 2) //若子树高度差的绝对值小于2,则看左右子树是否都平衡
balance = bl && br; //逻辑与,即左右子树都平衡时,二叉树平衡,balance=1
else
balance = 0;
}
}
判断二叉树是否为完全二叉树
思想:采用层次遍历算法。将所有结点加入队列,当遇到空结点时,查看后面是否还有非空结点。若有,则不是完全二叉树。
bool IsComplete(Bitree T)
{
InitQueue(Q);
if (!T)
return 1;
EnQueue(Q, T);
while (!IsEmpty(Q))
{
DeQueue(Q, p);
if (p)
{
EnQueue(p->lchild);
EnQueue(p->rchild);
}
else
{
while (!IsEmpty(Q))
{
DeQueue(Q, p);
if (p)
return 0;
}
}
}
return 1;
}
判断给定的二叉树是否为二叉排序树
思路:对二叉排序树来说,其中序遍历序列是一个递增有序序列。因此,对给定的二叉树进行中序遍历,若始终能保持前一个值比后一个值小,则说明该二叉树是一棵二叉排序树。
keyType predt = -32767; // predt为全局变量,保存当前结点中序前驱的值,初值为 负无穷
int JudgeBST(BiTree T)
{
int b1, b2;
if (T == NULL) // 空树
return 1;
else
{
b1 = JudgeBST(T->lchild); // 判断左子树是否为二叉排序树
if (b1 == 0 || predt >= T->data) // 若左子树返回0或前驱大于等于当前结点
return 0; // 则说明不是二叉排序树
predt = T->data; // 保存当前结果的关键字
b2 = JudgeBST(T->rchild); // 判断右子树是否为二叉排序树
return b2; // 返回右子树的判断结果
}
}
判断两棵二叉树是否相似,两棵都是空树,或只有一个结点为相似的,或者两棵树的左子树左子树是相似的,右子树右子树相似
bool similar(BiTree T1, BiTree T2)
{
if (T1 == NULL && T2 == NULL)
return true;
else if (T1 == NULL || T2 == NULL)
return false;
else
{
bool l = similar(T1->lchild, T2->lchild);
bool r = similar(T1->rchild, T2->rchild);
return l && r;
}
}
求两结点的最近公共结点
BiTree Fun(BiTree T, BiTree a, BiTree b)
{
if (T == null || T == a || T == b)
return T;
BiTree left = Fun(T->lchild, a, b);
BiTree right = Fun(T->rchild, a, b);
//左和右都不为null。 说明在左子树中发现过a或b,在右子树上也发现过a或b,并且a和b在当前节点首次相遇
if (left != null && right != null)
return T;
//左和右中一个不为null,另一个为null,说明不为null的节点是a或b中的一个,或者是a和b的最近祖先;直接返回;
if (left != null)
return left;
if (right != null)
return right;
return null; //左和右均为null,没有发现a和b;
}
求编号为i和j两个结点的最近公共祖先节点
int Comm_Ancestor(SqTree T, int i, int j)
{
if (T[i] != '#' && T[j] != '#')
{
while (i != j)
{
if (i > j)
i = i / 2; //向上找i的祖先
else
j = j / 2; //向上找j的祖先
}
return T[i];
}
}
从大到小输出二叉排序树中所有值不小于k的关键字
思想:因为二叉排序树的性质是【左子树 < 根 < 右子树】。所以为了从大到小输出,要先遍历右子树。再遍历根结点,最后遍历左子树。
void print(BiTree T, int k)
{
if (T == NULL)
return;
if (T->rchild != NULL)
print(T->rchild, k); //递归输出右子树结点
if (T->data >= k)
cout << T->data; //只输出大于等于k的结点值
if (T->lchild != NULL)
print(T->lchild, k); //递归输出左子树结点
}
先序遍历的第k个数
int t = 0;
void PreOrder(BiTree T)
{
if (T)
{
t++;
if (t == k)
cout << T->data;
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
在排序二叉树中寻找x所需的比较次数(求值为x的结点在二叉树中的层次)
int Search(BiTree T, char x)
{
BiTree p = T;
if (!p || p->data == x)
return 1; //树为空或者树根即为x的情况
int i = 1;
while (p && p->data != x)
{
if (p->data > x)
p = p->lchild;
else
p = p->rchild;
i++;
}
if (!p)
return 0; //没有找到的情况
return i; //成功找到
}
递归计算值为x的结点在二叉树中的层次
void getLevel(BiTree T, char x, int floor)
{
if (T)
{
if (T->data == x)
int result = floor;
getLevel(T->lchild, x, floor + 1);
getLevel(T->rchild, x, floor + 1);
}
}
从右向左删除或输出二叉树中的叶子结点(将叶子结点连成单链表)
void Delete(BiTree T)
{
BiTree p = T;
if (!p)
return;
else if (!p->lchild && !p->rchild)
cout << p->data; // free(p); 删除叶子结点
else
{
Delete(p->rchild); //如果要求从左到右,就颠倒一下这两句
Delete(p->lchild);
}
}
删除或输出二叉树中大于x的结点
void Delete(BiTree T, int x)
{
BiTree p = T;
if (!p)
return;
else if (p->data > x)
cout << p->data << " "; // delete(p);
Delete(p->lchild, x);
Delete(p->rchild, x);
}
删除二叉树中结点值小于(大于、等于)x的结点(包括其子树)
void Release(BiTree &T)
{
if (!T)
return;
Release(T->lchild);
Release(T->rchild);
free(T);
}
void Delete_X(BiTree &T, char x)
{
if (T == NULL)
return;
if (T->data >= x)
{ //自定义条件
Release(T);
T = NULL; //因为free只是告诉系统这块内存我们不用了而不是物
//理上面的释放所以我们要手动赋值NULL;
}
if (T != NULL)
{ //这里再次进行一次判断当T不为空时继续向下执行
Delete_X(T->lchild, x);
Delete_X(T->rchild, x);
}
}
删除二叉树中,所有结点值为x的结点,删去以他为根的子树。
思想:要删除次结点,必须先删除他的左右子树,故应该使用后序遍历,根据层次遍历,找到本结点的左孩子和右孩子判断左孩子右孩子的值,若相等则删除左子树,右子树和它自己。
void del_x(BiTree &T)
{
if (T != NULL)
{
del_x(T->lchild);
del_x(T->rchild);
free(T);
}
}
void Search(BiTree &T, int x)
{
SqQueue Q;
InitQueue(Q);
BiTree p = T;
if (p)
{
if (p->data == x)
{
del_x(p);
exit(0);
}
EnQueue(Q, T);
while (!IsEmpty(Q))
{
DeQueue(Q, p);
if (p->lchild)
if (p->lchild->data == x)
{
del_x(p->lchild);
p->lchild = NULL;
}
else
EnQueue(Q, p->lchild);
if (p->rchild)
if (p->rchild->data == x)
{
del_x(p->rchild);
p->rchild = NULL;
}
else
EnQueue(Q, p->rchild);
}
}
}
求出给定二叉排序树的最大和最小值
思想:二叉排序树中最坐下结点即为最小值;最右下结点即为最大值。无需关键字比较。
int Max(BiTree T)
{
while (T->lchild != NULL)
T = T->lchild;
return T->data;
}
int Min(T)
{
while (T->rchild != NULL)
T = T->rchild;
return T->data;
}
二叉树中从每个叶子结点到根结点的路径
void Print_All_Path(Bitree T, char path[], int pathlen)
{
int i;
if (T != NULL)
{
path[pathlen] = T->data;
// 如果改成【if(T->data==x)】,功能是【输出值为x的结点的祖先】
// 如果改成【if(T==x)】,功能是【输出结点x的祖先】
if (T->lchild == NULL &&T->rchild = NULL)
{
for (i = pathlen; i >= 0; i--)
cout << path[i] << " ";
cout << endl;
}
else
{
Print_All_Path(T->lchild, path, pathlen + 1);
rint_All_Path(T->rchild, path, pathlen + 1);
}
}
}
使用递归算法进行左右结点转换
void ExChangeTree(BiTree T)
{
BiTree temp;
if (T != NULL)
{
temp = T->lchild;
T->lchild = T->rchild; //直接交换节点地址
T->rchild = temp;
ExChangeTree(T->lchild);
ExChangeTree(T->rchild);
}
}