讲解很多都写在注释里了,重构二叉树的过程后面单独拿出来讲
直接上代码:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <limits.h>
typedef struct BiTree
{
int data;
struct BiTree* next[2];
} BiTree;
BiTree* BiTree_init(int val)//节点初始化
{
BiTree* p = (BiTree*)malloc(sizeof(BiTree));
if (p == NULL) return NULL;
p->data = val;
p->next[0] = p->next[1] = NULL;
return p;
}
void BiTree_clear(BiTree* root)
{
if (root == NULL) return;
BiTree_clear(root->next[0]);
BiTree_clear(root->next[1]);
free(root);
}
BiTree* BiTree_insert(BiTree* root, int val)
{
if (root == NULL) return BiTree_init(val);
int pos = rand() % 2;
root->next[pos] = BiTree_insert(root->next[pos], val);
return root;
}
void BiTree_BFS(BiTree* root)
{
if (root == NULL) return;
BiTree* q[100] = { NULL };
int head = 0, tail = 0;
q[tail++] = root;
printf("%2d\n", root->data);
while (head != tail)
{
if (q[head]->next[0])
{
q[tail] = q[head]->next[0];
printf("%2d > %2d (L)\n", q[head]->data, q[tail]->data);
tail++;
}
if (q[head]->next[1])
{
q[tail] = q[head]->next[1];
printf("%2d > %2d (R)\n", q[head]->data, q[tail]->data);
tail++;
}
head++;
}
}
void BiTree_convertToGeneList_sub(BiTree* root, int* ret, int* top)
{//就是一个深搜的过程,只不过是在前中后分别加上'(' ',' ')'
//多封装一层是为了在不使用全局变量的前提下实现入栈
if (root == NULL) return;
ret[++(*top)] = root->data + 128;//为了避免数据的ASCII码值和'(' ',' ')'重合,数据存储时+128,打印时-128
if (root->next[0] || root->next[1])//左右子树都空就不带'(,)'
{
ret[++(*top)] = '(';
BiTree_convertToGeneList_sub(root->next[0], ret, top);
ret[++(*top)] = ',';
BiTree_convertToGeneList_sub(root->next[1], ret, top);
ret[++(*top)] = ')';
}
}
int* BiTree_convertToGeneList(BiTree* root)
{
if (root == NULL) return NULL;
int* ret = (int*)malloc(sizeof(int) * 1000);//临时变量出函数后空间就被释放了,必须malloc
int top = -1;
BiTree_convertToGeneList_sub(root, ret, &top);
ret[++top] = INT_MAX;//以INT_MAX作为广义表形式的结束标志,防止占用其他数据
return ret;
}
BiTree* BiTree_rebuild_GeneList_sub(int* arr, int* p)
{
if (arr == NULL || arr[*p] == INT_MAX) return NULL;
BiTree* root = BiTree_init(arr[*p] - 128);
if (arr[*p + 1] == ',' && arr[*p] >= 128) return root;
if (arr[*p + 1] == INT_MAX) return root;
int memory = arr[*p + 1];
if (arr[*p + 1] == '(') *p += 2;
if (arr[*p] == ',')
{
*p += 1;
root->next[1] = BiTree_rebuild_GeneList_sub(arr, p);
if (memory == '(') *p += 1;
}
else if (arr[*p + 1] != ')')//arr[*p] == data
{
root->next[0] = BiTree_rebuild_GeneList_sub(arr, p);
*p += 2;
if (arr[*p] >= 128)
{
root->next[1] = BiTree_rebuild_GeneList_sub(arr, p);
if (memory == '(') *p += 1;
}
}
return root;
}
BiTree* BiTree_rebuild_GeneList(int* arr)
{
if (arr == NULL || arr[0] == INT_MAX) return NULL;
int p = 0;//多封装一层也是为了不用全局变量
BiTree* root = BiTree_rebuild_GeneList_sub(arr, &p);
return root;
}
void BiTree_test()
{
BiTree* root = NULL;
int i;
for (i = 0; i < 30; i++) root = BiTree_insert(root, rand() % 100);//随机生成一颗有30个节点的二叉树
BiTree_BFS(root);//打印二叉树,以便检验重构二叉树是否正确
printf("\n\n");
int* arr = BiTree_convertToGeneList(root);//生成二叉树广义表形式
BiTree* rebuild = BiTree_rebuild_GeneList(arr);//根据二叉树广义表形式重构二叉树
BiTree_BFS(rebuild);
BiTree_clear(root);
BiTree_clear(rebuild);
}
int main()
{
//不写srand()是为了方便Debug
BiTree_test();
return 0;
}
重构二叉树:
先定义函数功能:以根节点+括号对为单位进行处理
根据 arr & p 还原二叉树,返回其根节点,并令 *p 指向队列中的合适位置
(如碰到 '(' 就要在函数结束前再令 *p 后移一位,以跳出括号对)
再写函数框架:
以根节点为单位进行处理时,先看第一个节点,因为确保这个节点是根节点
所以直接创建并初始化
它的右边要么是 INT_MAX (结束),要么是 '(' (左右子树)
BiTree* BiTree_rebuild_GeneList_sub(int* arr, int* p)
{
if (arr == NULL || arr[*p] == INT_MAX) return NULL;//特殊情况判断
BiTree* root = BiTree_init(arr[*p] - 128);//节点创建并初始化
if (arr[*p + 1] == INT_MAX) return root;//下一个位置就结束时直接返回
int memory = arr[*p + 1];//memory记录下一位置信息,如果是'('
//若下一位置是'(',函数结束前 *p 要向后移动一位,以跳出')'
if (arr[*p + 1] == '(') *p += 2;//下一个位置是'('时令指针指向括号内部,准备生成左右子树
return root;
}
再详细完善进入第一个括号对后应进行的操作
BiTree* BiTree_rebuild_GeneList_sub(int* arr, int* p)
{
if (arr == NULL || arr[*p] == INT_MAX) return NULL;
BiTree* root = BiTree_init(arr[*p] - 128);
if (arr[*p + 1] == INT_MAX) return root;
int memory = arr[*p + 1];
if (arr[*p + 1] == '(') *p += 2;
if (arr[*p] == ',')
{//进入括号对内部后,若第一个碰到的就是',',说明该根节点无左子树,*p += 1 后生成右子树
*p += 1;
root->next[1] = BiTree_rebuild_GeneList_sub(arr, p);
if (memory == '(') *p += 1;//跳出')'
}
else//arr[*p] == data,生成左子树,并根据情况生成右子树
{
root->next[0] = BiTree_rebuild_GeneList_sub(arr, p);
*p += 2;//移动到','的下一位
if (arr[*p] >= 128)//','下一位仍是数据,说明该根节点左右子树都有,生成右子树
{
root->next[1] = BiTree_rebuild_GeneList_sub(arr, p);
if (memory == '(') *p += 1;//也要注意跳出')'
}
}
return root;
}
最后补充后续根节点+括号对会碰到的特殊情况
原根节点的左孩子若无左右子树,队列后面紧跟着的是 ','
原根节点的右孩子若无左右子树,队列后面紧跟着的是 ')'
BiTree* BiTree_rebuild_GeneList_sub(int* arr, int* p)
{
if (arr == NULL || arr[*p] == INT_MAX) return NULL;
BiTree* root = BiTree_init(arr[*p] - 128);
if (arr[*p + 1] == ',' && arr[*p] >= 128) return root;//原根节点左孩子无左右子树
if (arr[*p + 1] == INT_MAX) return root;
int memory = arr[*p + 1];
if (arr[*p + 1] == '(') *p += 2;
if (arr[*p] == ',')
{
*p += 1;
root->next[1] = BiTree_rebuild_GeneList_sub(arr, p);
if (memory == '(') *p += 1;
}
else if (arr[*p + 1] != ')')//原根节点右孩子有左右子树
{
root->next[0] = BiTree_rebuild_GeneList_sub(arr, p);
*p += 2;
if (arr[*p] >= 128)
{
root->next[1] = BiTree_rebuild_GeneList_sub(arr, p);
if (memory == '(') *p += 1;
}//这两个对 *p 的操作都是让其指向合适的位置
}
return root;
}
思路正确后耐心 Debug 即可,主要就是各种 if
标签:重构,arr,return,int,BiTree,next,二叉树,广义,root From: https://blog.csdn.net/qwq_ovo_pwp/article/details/142298348