C++算法题:关于树的算法

20 篇文章 2 订阅

问题1:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。要求不能创建任何新的结点,只调整指针的指向。

什么是二元查找树?

比如:

转换成双向链表的顺序是:

1  3  4  6  7  8  10  13  14 

步骤一:建立二叉搜索树

struct BSTreeNode  
{  
    int value;  
    BSTreeNode *left;  
    BSTreeNode *right;  
};

BSTreeNode * Insert(BSTreeNode *p, int x)  
{  
    if(p == NULL)  
    {  
//最终新加的元素将会被赶到最下面,新建这个节点;这么做是遵循二元查找树定义的
//前面也可插入只是太麻烦
        p = new BSTreeNode;  
        p->value = x;  
        p->left = NULL;  
        p->right = NULL;  
    }  
    else  
    {  
//如果x小于头结点,加到左边
        if(p->value > x)  
            p->left = Insert(p->left, x);  
//如果x大于头结点,加到右边
        if(p->value < x)  
            p->right = Insert(p->right, x);  
    }  
    return p;  
} 

步骤二:遍历二元查找树

void Traverse(BSTreeNode *p) //中序遍历  
{  
    if(p == NULL)  
        return;  
    Traverse(p->left);      //左
    cout<<p->value<<' ';  //根
    Traverse(p->right);    //右
}  

步骤三:转换为双向链表(比我小之中取最大,比我大之中取最小,分列我两侧)

BSTreeNode * Convert(BSTreeNode *node)  
{  
    if(node == NULL)  
        return NULL;  
    BSTreeNode *leftMax,*rightMin;  
    leftMax = node->left;      
    rightMin = node->right;  
    //找到左子树的最大结点  
    while(leftMax != NULL && leftMax->right != NULL)  
        leftMax = leftMax->right;  
    //找到右子树的最小结点  
    while(rightMin != NULL && rightMin->left != NULL)  
        rightMin = rightMin->left;  
    //递归求解  在调整指针之前,先递归
    Convert(node->right);   
    Convert(node->left);  
    //将左右子树同根结点连起来,只不过是以兄弟的关系  
    if(leftMax != NULL)  
        leftMax->right = node;  
    if(rightMin != NULL)  
        rightMin->left = node;  
    node->left = leftMax;  
    node->right = rightMin;  
    return node;  
}  

问题2:输入一颗二元查找树,将该树转换为它的镜像,即在转换后的二元查找树中,左子树的结点都大于右子树的结点。用递归和循环两种方法完成树的镜像转换

struct BSTreeNode    
{    
    int value;    
    BSTreeNode *left;    
    BSTreeNode *right;    
}; 

解法一:用递归

//函数功能 : 输入一颗二元查找树,将该树转换为它的镜像  
//函数参数 : pRoot为根结点  
//返回值 :   根结点  
BSTreeNode * Mirror_Solution1(BSTreeNode * pRoot)  
{  
    if(pRoot != NULL)  
    {  
 //必须记住这个节点,不然下面的赋值将把原来的关系解除,就找不到原来的pRoot->left;了
        BSTreeNode * pRight = pRoot->right;  
        BSTreeNode * pLeft = pRoot->left; 
        pRoot->left = Mirror_Solution1(pRight);  //转化右子树  
        pRoot->right = Mirror_Solution1(pLeft);  //转化左子树  
    }  
    return pRoot;  
} 

解法二:用循环

BSTreeNode * Mirror_Solution2(BSTreeNode * pRoot)  
{  
    if(pRoot != NULL)  
    {  
        stack<BSTreeNode *> stk;   //辅助栈  
        stk.push(pRoot);           //压入根结点  
        while(stk.size())  
        {  
            BSTreeNode *pNode = stk.top();  
            BSTreeNode *pLeft = pNode->left;  
            BSTreeNode* pRight = pNode->right;  
            stk.pop();  
  
            if(pLeft != NULL)  
                stk.push(pLeft);  
            if(pRight != NULL)  
                stk.push(pRight);  
            pNode->left = pRight;  //交换左右子女  
            pNode->right = pLeft;  
        }  
    }  
    return pRoot;  
} 

问题3:输入一颗二元树,从上往下按层打印树的每个结点,同一层中按照从左往右的顺序打印。

//跟上一篇的镜像二叉树类似
//函数功能 : 按层次遍历二元树  
//函数参数 : pRoot指向根结点  
//返回值 :   无  
void LevelReverse(BSTreeNode *pRoot)  
{  
    if(pRoot == NULL)  
        return;  
  
    queue<BSTreeNode *> nodeQueue;  
    nodeQueue.push(pRoot);  
    while(nodeQueue.size())  
    {  
        BSTreeNode * pNode = nodeQueue.front(); //取队首元素  
        nodeQueue.pop(); //必须出队列  
        if(pNode->left)  //左子女  
            nodeQueue.push(pNode->left);  
        if(pNode->right) //右子女  
            nodeQueue.push(pNode->right);  
  
        cout<<pNode->value<<' ';  
    }  
} 

问题4:输入一棵二叉树的根结点,判断该树是不是平衡二叉树。如果某二叉树中任意结点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。例如下图中的二叉树就是一棵平衡二叉树

struct BinaryTreeNode  
{  
    int data;  
    BinaryTreeNode *pLeft;  
    BinaryTreeNode *pRight;  
};  
//函数功能 : 判断二叉树是不是平衡的  
//函数参数 : pRoot为根结点,pDepth为根结点的深度。  
//返回值 :   是否平衡的  
bool IsBalanced(BinaryTreeNode *pRoot, int *pDepth)  
{  
    if(pRoot == NULL)  
    {  
        *pDepth = 0;  
        return true;  
    }  
    int leftDepth, rightDepth; //左右子树的深度  
    //只有左右子树已经是平衡,才能比较当前节点是不是平衡
    if(IsBalanced(pRoot->pLeft, &leftDepth)&&  
        IsBalanced(pRoot->pRight, &rightDepth))  
    {  
        int diff = leftDepth - rightDepth;  
        if(diff == 0 || diff == 1 || diff == -1)  //相差为0或1或-1  
        {  
            *pDepth = 1 + (leftDepth > rightDepth ? leftDepth: rightDepth);   
            return true;  
        }  
        else  
     //如果返回一个false则全盘都是false
            return false;  
    }  
    return false;  
}  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值