树的镜像

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

树的镜像_第1张图片

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

树的镜像_第2张图片

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

#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;
}


 

 

 

你可能感兴趣的:(c,struct,测试,tree,null,存储)