通过数组创建二叉树

4,720 阅读9分钟

由完全二叉树数组构建树

1. 通过递归思想实现。

设完全二叉树的数组表示为:['A', 'B', 'c', 'D', '#', '#', 'E'];则可以看出下标为 i 的元素的左右子树分别为 2*i+1,2*i+2。及 ;'A' 的左子树为 'B',右子树为 'C'。

故代码实现:

void createTree(Tree **root, int i, int *tree, int length)
{
    if(tree[i] == '#' || i >= length)
        return;
    *root = (Tree *)malloc(sizeof(Tree));
    (*root)->data = tree[i];
    createTree((*root)->leftTree, 2*i+1, tree, n);
    createTree((*root)=>rightTree, 2*i+2, tree, n);
}

// 代码分析
// 1. 参数:root 为根节点,i 为数组下标,tree 为数组, n 为 数组长度
// 2. 根节点需要为根节点地址的地址,由于地址为引用类型,若参数只是为跟结点的地址,
// 每次调用时的地址都是同一个,这会让根节点里的信息随着调用而改变。而传进地址的地址,
// 则会随着每次调用而改变地址。这正是我们想要的,根据不同的地址存储不同的根节点。

整体代码如下:

#include<stdio.h>
#include<stdlib.h>

// 定义完全二叉树数组
char tree[30] = "ABCD##E#F####GH";
// 定义长度
int length = 15;

typedef struct TREE{
    char data;
    struct TREE *leftTree;
    struct TREE *rightTree;
}Tree;

Tree * createNode();                       // 创建结点
void createTree(Tree **, intchar *);     // 创建二叉树
void prePrintTree(Tree *);                 // 前序打印二叉树
void midPrintTree(Tree *);                 // 中序打印二叉树

int main()
{
    Tree *head = NULL;
    createTree(&head, 0, tree);
    prePrintTree(head);
    printf("\n");
    midPrintTree(head);
    printf("\n");
}

Tree * createNode()
{
    Tree *root = (Tree *)malloc(sizeof(tree));
    root->leftTree = NULL;
    root->rightTree = NULL;
    return root;
}

// 创建二叉树
void createTree(Tree **root, int i, char * tree)
{

    if(i > length-1 || tree[i] == '#')
        return ;
    *root = createNode();
    (*root)->data = tree[i];
    createTree(&((*root)->leftTree), 2*i+1, tree);
    createTree(&((*root)->rightTree), 2*i+2, tree);

}

// 前序打印
void prePrintTree(Tree *root)
{
    if(root == NULL)
        return ;
    printf("%c ", root->data);
    prePrintTree(root->leftTree);
    prePrintTree(root->rightTree);
}

// 中序打印
void midPrintTree(Tree *root)
{
    if(root == NULL)
        return;
    midPrintTree(root->leftTree);
    printf("%c ", root->data);
    midPrintTree(root->rightTree);
}




2. 通过队列实现

设完全二叉树为['A', 'B', 'C', 'D', '#', '#', 'E'],我们可以通过一层一层的创建树,且创建的顺序和数组的顺序一样。

实现思路:

  1. 创建一个队列,其有特性:队头出队,队尾入队。
  2. 现将头结点入队,然后标记现有队列的元素个数。
  3. 循环现有个数:出队,将其数据值等于数组相应的元素值。然后将其左右结点入队。
  4. 由于队列是先进先出,且每次循环前有标记现有的个数,故每次出队都是旧数据(这一层的结点),对于新进的数据(下一层的结点)则由下次循环是遍历。

代码实现:

int i = 0, j;

    Tree *head = NULL;             // 声明树首节点
    Tree **root;                   

    // 创建循环队列
    Stack *stack = (Stack *)malloc(sizeof(Stack));
    stack->head = 0;
    stack->foot = 0;

    stackPush(stack, &head);       // 先将首节点入栈

    while(i < length)              // 遍历数组,遍历完时,树生成完成
    {
        j = (stack->foot - stack->head + 20)%20;    // 记录当前队列的数量,这个队列是循环队列

        for(j; j>0; j--){                          // 遍历旧的队列元素并出队
            root = stackPop(stack);                
            *root = createNode();
            (*root)->data = tree[i];              // 结点的数据值等于数组的元素值
            i++;                                  // 数组下标加1

            stackPush(stack, &((*root)->leftTree));    // 将结点的左右子树入队
            stackPush(stack, &((*root)->rightTree));
        }
    }

整体代码如下:

#include<stdio.h>
#include<stdlib.h>

char tree[30] = "ABCD##E#F####GH";     // 定义完全二叉树和数组
int length = 15;                       // 数组长度

typedef struct TREE{                   // 定义树结点
    char data;
    struct TREE *leftTree;
    struct TREE *rightTree;
}Tree;

typedef struct STACK{                  // 定义队列
    Tree **array[20];
    int head;
    int foot;
}Stack;

Tree * createNode();                       // 创建树节点
void stackPush(Stack *stack, Tree **);     // 入队操作(循环队列)
Tree **stackPop(Stack *stack);             // 出队操作
void prePrintTree(Tree *);                 // 前序输出

int main()
{
    int i = 0, j;

    Tree *head = NULL;                // 定义头结点
    Tree **root;

    // 创建循环队列
    Stack *stack = (Stack *)malloc(sizeof(Stack));
    stack->head = 0;
    stack->foot = 0;

    stackPush(stack, &head);         // 将头结点入队

    while(i < length)
    {
        j = (stack->foot - stack->head + 20)%20;
        printf("%d\n", j);
        for(j; j>0; j--){
            root = stackPop(stack);
            *root = createNode();
            (*root)->data = tree[i];
            printf("%c", (*root)->data, (*root)->leftTree);
            i++;
            //(*root)->leftTree = createNode();
            //(*root)->rightTree = createNode();
            stackPush(stack, &((*root)->leftTree));
            stackPush(stack, &((*root)->rightTree));
        }
    }
    printf("\n");
    prePrintTree(head);

}

Tree * createNode()
{
    Tree *root = (Tree *)malloc(sizeof(tree));
    root->leftTree = NULL;
    root->rightTree = NULL;
    return root;
}

// 进队列
void stackPush(Stack *stack, Tree **root)
{
    if(stack->foot == stack->head-1){
        printf("队满");
        return;
    }
    if(stack->foot < 19){
        stack->array[stack->foot] = root;
        stack->foot ++;
    }
    else{
        stack->array[stack->foot] = root;
        stack->foot = 0;
    }
}    

// 出队列
Tree **stackPop(Stack *stack)
{
    Tree **root;
    if(stack->foot == stack->head){
        printf("队空");
        return NULL;
    }
    if(stack->head < 20){
        root = stack->array[stack->head];
        stack->head ++;
    }
    else{
        root = stack->array[stack->head];
        stack->head = 0;
    }
    return root;
}

void prePrintTree(Tree *root)
{
    if(root == NULL)
        return ;
    if(root->data != '#')
        printf("%c  ", root->data); 
    prePrintTree(root->leftTree);
    prePrintTree(root->rightTree);
}