一.二叉树的介绍
二叉树的特点是二叉树的每个结点的度都不大于2,可以视为每个结点都有左孩子和右孩子。故二叉树结点的数据结构为
typedef int BDataType;
typedef struct BTNode
{
BDataType data;
struct BTNode * left;
struct BTNdoe * right;
}BTNode;
二.二叉树的特点
1.设根结点所在的层数为第1层,则第i层最多有个结点。
2.深度为k的二叉树最多有个结点。
3.对任何一个二叉树,设其中度为0的结点个数为n0,度为1的结点个数为n1,度为2的结点个数为n2,则n0=n2+1。
4.对具有n个结点的完全二叉树来说,如果从上到下从左向右的顺序对所有的结点进行编号,则对于编号为i的结点有:
a)若i>0,则结点的双亲结点编号为;若i=0,则该结点为根结点,没有双亲结点。
b)若,则它的左孩子结点编号为;否则无左孩子。
c)若,则它的右孩子结点编号为;否则无右孩子。
d)深度为,上取整。
三.创建二叉树
用前序遍历并不能确定一棵二叉树的形态,如ABCDE表示的二叉树的形态有
当用#表示空结点时,上左图的前序序列为AB##C#DE###,此时可以根据这个序列唯一确定二叉树的形态。所以用一个特殊符号表示空结点结合树的前序遍历可以确定出二叉树。
创建二叉树的思想为:用递归的思想,前序遍历创建根结点,前序遍历创建根结点的左子树,前序遍历创建根结点的右子树。设前序遍历的序列用preOrder数组存放,则在创建子树的时候需要确定传的新的数组。在创建根结点时,根结点的数值为传的数组的第一个元素值,即preOrder[0]。创建左子树时,传的数组为preOrder+1。创建右子树时,需要计算出创建左子树用了多少个结点,才能传数组。因此在创建二叉树的函数中还需要加上创建该树用过的结点个数。事实上,该函数共返回了两个值,一个是出个创建好的二叉树(子树)(直接),一个是创建该树所用的结点个数(通过地址传回)。此外,考虑到最终没有结点可以创造的情况,即数组没有元素,也就是size=0.故还需在函数中传size。代码为
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int BDataType;
typedef struct BTNode
{
BDataType data;
struct BTNode* left;
struct BTNode* right;
}BTNode;
//创造结点
BTNode *CreateNode(BDataType data)
{
BTNode *node = (BTNode*)malloc(sizeof(BTNode));
assert(node != NULL);
node->data = data;
node->left = node->right = NULL;
return node;
}
//创造二叉树
BTNode *CreateTree(int preOrder[], int size, int *pused)
{
if (size == 0)//没有结点可以创造
{
*pused = 0;
return NULL;
}
int leftused = 0;
int rightused = 0;
BDataType rootValue = preOrder[0];
if (rootValue == -1)//该节点为空结点
{
*pused = 1;
return NULL;
}
BTNode *root = CreateNode(rootValue);
root->left = CreateTree(preOrder + 1, size - 1, &leftused);
root->right = CreateTree(preOrder + 1 + leftused, size - 1 - leftused, &rightused);
*pused = 1 + leftused + rightused;
return root;
}
//测试代码
void test()
{
int preOrder[] = { 1, 2, -1, -1, 3, -1, 4, 5, -1, -1, -1 };
int size = sizeof(preOrder) / sizeof(BDataType);
int pused = 0;
BTNode *root = CreateTree(preOrder, size, &pused);
printf("成功!\n");
}