普通树转化成二叉树

普通树转化成二叉树基本方法:
1、需要使用队列存储树的节点。
2、将根加入队列。
3、循环判断,队列不为空时。
4、循环体内,从队列中取出一个节点,遍历所有的孩子节点,并依次将他们加入到队列中。期间将其第一个子节点标为左孩子。将其他子节点标记为他们前面的兄弟节点的右孩子。(比如:a 下有 b c d三个子节点,循环之后,d成了c的右孩子,c成了b的右孩子,b是a的左孩子,建议画图理解)


上面是通俗的描述,真实的算法实现时,需要分别定义两棵树结构。下面结合代码进行描述。

#include 
#include 

#define N 3 //定义每个节点的最大孩子数
#define M 9 //定义树中节点的个数

//下面进行结构体定义
struct TreeNode //普通树节点
{
    char data;
    struct TreeNode *childs[N]; //保存指针的数组
}; //结构体的分号不可缺少
typedef struct TreeNode TreeNode; //定义类型,这样定义之后,以后使用直
//接TreeNode *name;即可,不用加上struct(struct TreeNode *name;)

struct BTreeNode //二叉树结点
{
    char data;
    struct BTreeNode *lchild, *rchild; //结构体内的使用自身的时候
    //,struct不可以省,包括上面的树、下面的队列定义
};
typedef struct BTreeNode BTreeNode;

//普通树的队列定义开始
struct QueueTree
{
    int i, j; //指向数组内元素的游标
    TreeNode **queue; //二维指针,与指针数组类似,不过需要动态分配空间
    //此处使用前边定义好的结构,不需要struct
};
typedef struct QueueTree QueueTree;

QueueTree * initQueueTree() //初始化普通树队列
{
    //分配一个队列空间
    QueueTree *tree = (QueueTree *)malloc(sizeof(QueueTree)); 
    //分配M个树节点指针空间
    tree->queue = (TreeNode **)malloc(sizeof(TreeNode *)*M); 
    tree->i = 0;
    tree->j = 0;
    return  tree;
}

void freeQueueTree(QueueTree *tree) //释放分配空间
{
    free(tree->queue); //先分配先释放
    free(tree);
}

void addQueueTree(QueueTree *tree, TreeNode *node) //加入队列
{
    if(tree->j == M) //队列已满
        return;
    tree->queue[tree->j] = node;
    tree->j++;
}

TreeNode * delQueueTree(QueueTree *tree)
{
    if(tree->i == tree->j) //队列已空
        return NULL;
    TreeNode *node = tree->queue[tree->i];
    tree->i++;
    return node;
}

int emptyQueueTree(QueueTree *tree) //队列是否为空
{
    return tree->i==tree->j; //1空
}


//二叉树队列定义开始,与上面类似,保证命名不重复
struct QueueBTree
{
    int i, j;
    BTreeNode **queue;
};
typedef struct QueueBTree QueueBTree;

QueueBTree * initQueueBTree()
{
    //分配一个队列空间
    QueueBTree *btree = (QueueBTree *)malloc(sizeof(QueueBTree)); 
    //分配M个树节点指针空间
    btree->queue = (BTreeNode **)malloc(sizeof(BTreeNode *)*M); 
    btree->i = 0;
    btree->j = 0;
    return  btree;
}

void freeQueueBTree(QueueBTree *btree) //释放分配空间
{
    free(btree->queue);
    free(btree);
}

void addQueueBTree(QueueBTree *btree, BTreeNode *node) //加入队列
{
    if(btree->j == M) //队列已满
        return;
    btree->queue[btree->j] = node;
    btree->j++;
}

BTreeNode * delQueueBTree(QueueBTree *tree)
{
    if(tree->i == tree->j) //队列已空
        return NULL;
    BTreeNode *node = tree->queue[tree->i];
    tree->i++;
    return node;
}

int emptyQueueBTree(QueueBTree *tree)
{
    return tree->i==tree->j; //1空
}


//普通树转化成二叉树开始
BTreeNode * transform(TreeNode *root)
{
    if(root == NULL)
        return NULL;
    //先分配根节点空间,构造二叉树的根节点
    BTreeNode *broot = NULL;
    broot = (BTreeNode *)malloc(sizeof(BTreeNode)); 
    broot->data = root->data; //复制根节点数据
    broot->lchild = broot->rchild = NULL; //指针置空

    //初始普通树、二叉树队列,并将他们的根节点分别加入对应队列
    QueueTree *queue = initQueueTree();
    QueueBTree *bqueue = initQueueBTree();
    addQueueTree(queue, root);
    addQueueBTree(bqueue, broot);

    //循环判断,当普通树的队列不空时
    while(emptyQueueTree(queue) == 0)
    {
        //从两个队列中分别取出一个节点
        TreeNode *node = delQueueTree(queue);
        BTreeNode *btreeNode = delQueueBTree(bqueue);

        int i;
        BTreeNode *former = NULL;

        //遍历普通树节点的所有孩子节点,将孩子加入普通树队列
        for(i=0; iif(node->childs[i] != NULL)
            {
                //每遍历一个孩子节点,就分配新的二叉树节点空间
                BTreeNode *bnode = 
                (BTreeNode *)malloc(sizeof(BTreeNode)); 
                //指针置空
                bnode->lchild = bnode->rchild = NULL;
                //复制数据
                bnode->data = node->childs[i]->data;
                //二叉树结点指针调整
                if(i == 0)
                {
                    //第一个孩子节点作为二叉树上层节点左孩子
                    btreeNode->lchild = bnode;
                    former = bnode;
                }
                else
                {
                    //后面的孩子节点作为同层前面节点的右孩子
                    former->rchild = bnode;
                    former = bnode;
                }
                addQueueTree(queue, node->childs[i]);
                addQueueBTree(bqueue, bnode);
            }
        }
    }
    freeQueueTree(queue); //空间释放
    freeQueueBTree(bqueue);
    return broot;
}

//测试开始
TreeNode * initTree() //构造一棵普通树
{
    TreeNode *root = (TreeNode *)malloc(sizeof(TreeNode));
    root->data = 'a';
    TreeNode *p1 = (TreeNode *)malloc(sizeof(TreeNode));
    p1->data = 'b';
    TreeNode *p2 = (TreeNode *)malloc(sizeof(TreeNode));
    p2->data = 'c';
    TreeNode *p3 = (TreeNode *)malloc(sizeof(TreeNode));
    p3->data = 'd';
    TreeNode *p4 = (TreeNode *)malloc(sizeof(TreeNode));
    p4->data = 'e';
    TreeNode *p5 = (TreeNode *)malloc(sizeof(TreeNode));
    p5->data = 'f';
    TreeNode *p6 = (TreeNode *)malloc(sizeof(TreeNode));
    p6->data = 'g';
    TreeNode *p7 = (TreeNode *)malloc(sizeof(TreeNode));
    p7->data = 'h';
    TreeNode *p8 = (TreeNode *)malloc(sizeof(TreeNode));
    p8->data = 'i';

    root->childs[0] = p1;
    root->childs[1] = p2;
    root->childs[2] = p3;
    p1->childs[0] = p4;
    p1->childs[1] = p5;
    p1->childs[2] = p6;
    p2->childs[0] = NULL;
    p2->childs[1] = NULL;
    p2->childs[2] = NULL;
    p3->childs[0] = p7;
    p3->childs[1] = p8;
    p3->childs[2] = NULL;
    int i;
    for(i=0; ichilds[i] = NULL;
        p5->childs[i] = NULL;
        p6->childs[i] = NULL;
        p7->childs[i] = NULL;
        p8->childs[i] = NULL;
    }
    return root;
}

void destroyTree(TreeNode *root) //释放树空间
{
    if(root == NULL)
        return;
    if(root->childs[0] == NULL && root->childs[1] == NULL && root->childs[2] == NULL)
        free(root);
    else
    {
        if(root->childs[0] != NULL)
            destroyTree(root->childs[0]);
        if(root->childs[1] != NULL)
            destroyTree(root->childs[1]);
        if(root->childs[2] != NULL)
            destroyTree(root->childs[2]);
    }
}

void iterator(TreeNode *root) //层序遍历该树
{
    if(root == NULL)
        return;
    QueueTree *queue = initQueueTree();
    addQueueTree(queue, root);
    while(emptyQueueTree(queue) == 0)
    {
        TreeNode *p = delQueueTree(queue);
        printf("%c ", p->data);
        int i;
        for(i=0; iif(p->childs[i] != NULL)
            {
                addQueueTree(queue, p->childs[i]);
            }
        }
    }
    freeQueueTree(queue);
}

void preOrder(BTreeNode *root) //二叉树前序遍历
{
    if(root == NULL)
        return;
    printf("%c ", root->data);
    preOrder(root->lchild);
    preOrder(root->rchild);
}

void destroyBTree(BTreeNode *root) //二叉树空间释放
{
    if(root == NULL)
        return;
    if(root->lchild == NULL && root->rchild == NULL)
        free(root);
    else
    {
        if(root->lchild != NULL)
            destroyBTree(root->lchild);
        if(root->rchild != NULL)
            destroyBTree(root->rchild);
    }
}

int main()
{
    TreeNode *root = initTree();
    iterator(root); //层序输出普通树
    printf("\n");
    BTreeNode *broot = transform(root);
    preOrder(broot); //前序输出二叉树
    printf("\n");
    destroyBTree(broot);
    destroyTree(root);
    return 0;
}

注意:当函数的返回值类型为指针时,如果忘记写return语句,编译可以通过,运行时会自动终止。同时需要小心内存分配的问题

你可能感兴趣的:(数据结构基础复习)