树的镜像

来源:互联网 发布:如何开通淘宝贷款吗 编辑:程序博客网 时间:2024/05/18 12:01

淘宝笔试的一个题目,在网上也没有找到正确的代码,自己写了一个,简单测试了下还行,但不保证完全正确。题目是这样的,一棵树,不一定是二叉树,是一棵很普通的屌丝树,把他镜像反转下。思路必须明确,首先用左孩子右兄弟的存储方法存储这棵树,然后对所有同级别的兄弟反转,也就是所有节点的右边链反转,其实也就是单链表反转的操作。代码中用到了递归,但是要注意的一点是单链表反转while中操作的次数为链表的长度减一的,这也就是说递归的时候是缺少了一次的,这就要求在while后面补上这次缺少的递归操作。树的图如下:

树的左孩子(child)右兄弟(sibling)的存储如下:

代码如下:代码中的数组为树的左孩子右兄弟存储的先序遍历顺序。

#include <iostream>#include <assert.h>using namespace std;typedef char ElemType;typedef struct CSNode{        ElemType data;        struct CSNode *firstchild, *nextsibling;}CSNode, *CSTree;const char INVALID = '^';const int MAX_NODE_COUNT = 20;void createCSTree(CSTree &tree, char *a);void preOrder(const CSTree tree);void mirrorCSTree(CSTree tree);int main(){        char a[] = {'A', 'B', 'E', 'H', '^', 'I', '^', '^', '^', 'C', '^', 'D', 'F', 'J', '^', '^', 'G', '^', '^', '^', '^', '\0'};        CSTree tree = NULL;        createCSTree(tree, a);        printf("before mirror preOrder:\n");        preOrder(tree);        mirrorCSTree(tree);        printf("after mirror preOrder:\n");        preOrder(tree);        return 0;}void createCSTree(CSTree &tree, char *a){        static int i = 0;        if(a[i] == '\0')                return;        if(a[i] == INVALID)        {                tree = NULL;                i++;                return;        }        else        {                CSNode *pCSNode = (CSNode *)malloc(sizeof(CSNode));                pCSNode->data = a[i++];                tree = pCSNode;                createCSTree(tree->firstchild, a);                createCSTree(tree->nextsibling, a);        }}void preOrder(const CSTree tree){        if(tree != NULL)        {                cout<<tree->data<<endl;                preOrder(tree->firstchild);                preOrder(tree->nextsibling);        }}void mirrorCSTree (CSTree tree){  if (tree == NULL)    return;  if (tree->firstchild)    {      CSTree p1 = tree->firstchild;      CSTree p2 = p1->nextsibling;      p1->nextsibling = NULL;   //注意一开始的要先指向NULL      while (p2)        {          CSTree p3 = p2->nextsibling;          p2->nextsibling = p1;          mirrorCSTree (p1->firstchild);          if(p3 == NULL)                  mirrorCSTree(p2);          p1 = p2;          p2 = p3;        }      tree->firstchild = p1;    }}


其实树的镜像是非常难写正确的的. 下面是第二个版本,参数传进来的树的根节点。看起来比上面的顺眼些
树的结构和上面的一样,前序遍历为1, 2, 3, 4, 5, 6, 7, 8, 9, 10镜像后为1 7 10 8 9 6 2 3 5 4难的地方在当旋转右子树的最后一个节点的时候。当跳出while循环的时候,最后一个节点的left并没有调用mirror函数,就要想办法把它补上。最好的地方是加在while循环的里面也就是上面代码一样。如果加在while循环的后面,这个时候可能会出现重复的递归,递归不能返回的情况(非常可能出现)。我尝试了很多条件都没有使得递归停止。原因是如果在while后面加上一个mirrorTree(p1)的话,其实首先p1虽然变成p2了,但是p2的right已经改变了。这就非常麻烦了,最后的结果可能是在p1和p2之间来回递归。

void mirrorTree(BTree &rt){        if(rt == NULL)                return;        if(rt->right == NULL)        {                mirrorTree(rt->left);                return;        }        BTree p1= rt;        BTree p2= p1->right;        p1->right = NULL;        while(p2)        {                BTree p3 = p2->right;                p2->right = p1;                mirrorTree(p1->left);                if(p3 == NULL)                        mirrorTree(p2->left);                p1 = p2;                p2 = p3;        }        rt = p1;}int main(){        int a[] = {1, 2, 3, 4, -1, 5, -1, -1,-1, 6, -1, 7, 8, 9, -1, -1, 10, -1, -1, -1, -1};        int i = 0;        BTree rt = NULL;        createTree(a, i, rt);        preOrder(rt);        cout<<endl;        mirrorTree(rt);        preOrder(rt);        cout<<endl;}


 

 

 

原创粉丝点击