例题:设二叉树的存储结构为二叉链表,编写有关二叉树的递归算法

例题:设二叉树的存储结构为二叉链表,编写有关二叉树的递归算法:

(1)统计二叉树中度为1的结点个数;

(2)统计二叉树中度为2的结点个数;

(3)统计二叉树中度为0的结点个数;

(4)统计二叉树的高度;

(5)统计二叉树的宽度;

(6)从二叉树中删去所有叶节点;

(7)计算指定结点*p所在的层次;

(8)计算二叉树中各节点中的最大元素的值;

(9)交换二叉树中每个结点的两个子女;

(10)以先序次序输出一颗二叉树中所有结点的数据值及结点所在层次。

(1)统计二叉树中度为1的结点个数
void CountNode1(BiTree T)
{
	static int num=0//在函数内部定义,这个变量只初始化一次
	if (T == NULL)
		return;
	if ((T->lchild && !T->rchild) || (!T->lchild && T->rchild))//左右子树只有一个非空
		num++;
	
	CountNode1(T->lchild);
	CountNode1(T->rchild);
}
(2)统计二叉树中度为2的结点个数
void CountNode2(BiTree T)
{
	static int num=0//在函数内部定义,这个变量只初始化一次
	if (T == NULL)
		return;
	if (T->lchild && T->rchild))//左右子树都非空
		num++;
	
	CountNode2(T->lchild);
	CountNode2(T->rchild);
}
(3)统计二叉树中度为0的结点个数
void CountNode0(BiTree T)
{
	static int num=0//在函数内部定义,这个变量只初始化一次
	if (T == NULL)
		return;
	if (!T->lchild && !T->rchild))//左右子树都为空
		num++;
	
	CountNode0(T->lchild);
	CountNode0(T->rchild);
(4)统计二叉树的高度
int Height(BiTree T)
{
	if (T == NULL)
		return 0;
	return Max(Height(T->lchild), Height(T->rchild)) + 1;
}

(5)统计二叉树的宽度

// 求解树的高度
int getHeight(BiTree T) {
    if (T == NULL) {
        return 0;
    }
    int leftHeight = getHeight(T->left);
    int rightHeight = getHeight(T->right);
    return 1 + max(leftHeight, rightHeight);
}

// 求解每层的节点数
int getWidthAtLevel(BiTree T, int level) {//level是树的层数,层数是由低到高增大
    if (T==NULL) {
        return 0;
    }
    if (level == 1) {//到达叶子结点
        return 1;
    } 
    else if (level > 1) {
        return getWidthAtLevel(T->left, level - 1) + getWidthAtLevel(T->right, level - 1);
    }
    return 0;
}

// 求解二叉树的宽度
int getTreeWidth(BiTree T) {
    int maxWidth = 0;
    int height = getHeight(T);

    for (int i = 1; i <= height; i++) {//最宽的那层为树的宽度
        int levelWidth = 0;
        getWidthOfLevel(T, i, &levelWidth);
        if (levelWidth > maxWidth) {
            maxWidth = levelWidth;
        }
    }

    return maxWidth;
}


(6)从二叉树中删去所有叶节点

要使用递归算法删除二叉树中的所有叶节点(叶子结点是没有子节点的节点),可以按照以下步骤进行:

1.如果二叉树为空(即根节点为NULL),则不需要执行任何操作。
2.否则,递归地调用删除叶节点的函数,首先删除左子树中的叶节点,然后删除右子树中的叶节点。
3.在递归过程中,检查当前节点是否为叶节点(即左右子节点都为空)。如果是叶节点,则释放当前节点的内存并将其设置为NULL。

// 递归函数来删除叶节点
void deleteLeaves(BiTree &T) {
    if (T == NULL) {
        return;
    }

    // 递归地删除左子树和右子树的叶节点
    deleteLeaves(root->left);
    deleteLeaves(root->right);

    // 检查当前节点是否为叶节点
    if (root->left == NULL && root->right == NULL) {
        free(T);
        T = NULL;
    }
}
(7)计算指定结点*p所在的层次

1.如果二叉树为空(即根节点为 NULL),或者 p 为NULL,则返回 0 或其他适当的值,表示未找到。
2.如果根节点为 p,则返回 1,表示根节点所在的层次为 1。
3.否则,递归地计算 p 在左子树和右子树中的层次,然后取较大的层次值,再加 1,以表示 p 在当前树中的层次。


// 递归函数来计算指定节点的层次
int findNodeLevel(BiTree T, BiNode* p, int level) {//level初始值为1
    if (T == NULL) {
        return 0; // 如果树为空或未找到节点,返回0表示未找到
    }

    if (T == p) {
        return level; // 找到了目标节点,返回当前层次
    }

    // 递归在左子树和右子树中查找
    int leftLevel = findNodeLevel(T->left, p, level + 1);
    if (leftLevel != 0) {
        return leftLevel; // 在左子树中找到了,返回结果
    }

    int rightLevel = findNodeLevel(root->right, p, level + 1);
    return rightLevel; // 返回左子树和右子树中的非零结果
}


(8)计算二叉树中各节点中的最大元素的值
int findMaxInSubtree(BiTree T) {
    if (T == NULL) {
        return INT_MIN; // 对于空节点,返回一个较小的值
    }
    
    int leftMax = findMaxInSubtree(root->left);
    int rightMax = findMaxInSubtree(root->right);

    // 返回左子树、右子树和当前节点的最大值
    return max(max(leftMax, rightMax), root->data);
}
(9)交换二叉树中每个结点的两个子女
// 递归函数来交换二叉树中每个节点的左右子树
void swapChildren(BiTree T) {
    if (T == NULL) {
        return;
    }
    
    // 递归交换左右子树
    BiNode* temp = T->left;
    T->left = T->right;
    T->right = temp;

    swapChildren(T->left);
    swapChildren(T->right);
}
(10)以先序次序输出一颗二叉树中所有结点的数据值及结点所在层次。
// 递归函数来以先序遍历方式输出二叉树节点的数据值和层次
void preOrderTraversalWithLevel(BiTree T, int level) {//level初始值为1
    if (T == NULL) {
        return;
    }

    // 输出节点数据值和层次
    cout << "Node: " << T->data << ", Level: " << level << endl;

    // 递归遍历左子树和右子树,层次加一
    preOrderTraversalWithLevel(T->left, level + 1);
    preOrderTraversalWithLevel(T->right, level + 1);
}
1本程序在vc++6.0编译通过并能正常运行。 2主界面 程序已经尽量做到操作简便了,用户只需要根据提示一步步进行操作就行了。 六思考和总结: 这个课程计的各个基本操作大部分都在我的综合性实验中实现了,所以做这个主要攻克插入和删除这两个算法!其中插入在书本上已经有了,其中的右平衡算法虽然没有给出,但通过给出的左平衡算法很容易就可以写出右平衡算法。所以最终的点就在于删除算法的实现!做的过程中对插入算法进行了非常非常多次的尝!花了非常多的时间,这其中很多时候是在对程序进行单步调,运用了VC6。0的众多良好工具,也学到了很多它的许多好的调手段。 其中删除算法中最难想到的一点是:在用叶子结点代替要删除的非叶子结点后,应该递归的运用删除算法去删除叶子结点!这就是整个算法的核心,其中很强烈得体会到的递归的强大,递归的最高境界(我暂时能看到的境界)! 其它的都没什么了。选做的那两个算法很容易实现的: 1合并两棵平衡二叉排序树:只需遍历其中的一棵,将它的每一个元素插入到另一棵即可。 2拆分两棵平衡二叉排序树:只需以根结点为中心,左子树独立为一棵,右子树独立为一棵,最后将根插入到左子树或右子树即可。 BSTreeEmpty(BSTree T) 初始条件:平衡二叉排序树存在。 操作结果:若T为空平衡二叉排序树,则返回TRUE,否则FALSE. BSTreeDepth(BSTree T) 初始条件:平衡二叉排序树存在。 操作结果:返回T的深度。 LeafNum(BSTree T) 求叶子结点数,非递归中序遍历 NodeNum(BSTree T) 求结点数,非递归中序遍历 DestoryBSTree(BSTree *T) 后序遍历销毁平衡二叉排序树T R_Rotate(BSTree *p) 对以*p为根的平衡二叉排序树作右旋处理,处理之后p指向新的树根结点 即旋转处理之前的左子树的根结点 L_Rotate(BSTree *p) 对以*p为根的平衡二叉排序树作左旋处理,处理之后p指向新的树根结点, 即旋转处理之前的右子树的根结点 LeftBalance(BSTree *T) 对以指针T所指结点为根的平衡二叉排序树作左平衡旋转处理, 本算法结束时,指针T指向新的根结点 RightBalance(BSTree *T) 对以指针T所指结点为根的平衡二叉排序树作右平衡旋转处理, 本算法结束时,指针T指向新的根结点 Insert_AVL(BSTree *T, TElemType e, int *taller) 若在平衡的二叉排序树T中不存在和e有相同的关键字的结点, 则插入一个数据元素为e的新结点,并返回OK,否则返回ERROR. 若因插入而使二叉排序树失去平衡,则作平衡旋转处理 布尔变量taller反映T长高与否 InOrderTraverse(BSTree T) 递归中序遍历输出平衡二叉排序树 SearchBST(BSTree T, TElemType e, BSTree *f, BSTree *p) 在根指针T所指的平衡二叉排序树中递归的查找其元素值等于e的数据元素, 若查找成功,则指针p指向该数据元素结点,并返回TRUE,否则指针p 指向查找路径上访问的最后一个结点并返回FALSE,指针f指向T的双亲, 其初始调用值为NULL Delete_AVL(BSTree *T, TElemType e, int *shorter) 在平衡二叉排序树中删除元素值为e的结点,成功返回OK,失败返回ERROR PrintBSTree_GList(BSTree T) 以广义表形式打印出来 PrintBSTree_AoList(BSTree T, int length) 以凹入表形式打印,length初始值为0 Combine_Two_AVL(BSTree *T1, BSTree T2) 合并两棵平衡二叉排序树 Split_AVL(BSTree T, BSTree *T1, BSTree *T2) 拆分两棵平衡二叉树 } (2)存储结构的定义: typedef struct BSTNode { TElemType data; int bf; //结点的平衡因子 struct BSTNode *lchild, *rchild;//左.右孩子指针 }BSTNode, *BSTree;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值