首先是关于树,二叉树,完全二叉树的一些知识
一、树 (一)、基本概念 1. 度:一个节点的子树的个数 2. 叶子节点:度为零的节点 3. 内部节点:度不为零的节点 4. 节点的层次,从根开始为第一层,之后的每个孩子节点为第i层 二、二叉树 (一)、基本性质 1.二叉树的第i层 多有 2^(i-1) 个节点 2.高度为k的二叉树最多有2^k – 1 个节点 3.对于任意的二叉树 若其终端节点(叶子节点)为n0 度为2的节点个数为 n2 则有 n0 = n2 + 1 4.对于具有n个节点的完全二叉树 深度为log(2)n 向下取整再加 1 三、完全二叉树 完全二叉树使用顺序储存将极大的节省空间 我们设节点的编号为i,节点的个数为n (1<= i <=n) 1. 若节点标号为 i = 0 则该节点为根节点;若 i>1 则该节点的双亲节点为i/2向下取整有,等价于双亲节点的编码在1~n/2之间 2. 若 2*i <= n,则该节点的左孩子编号为2i,否则该节点没有左孩子。 2. 若 2*i +1 <= n, 则该节点的右孩子编号为2*i+1,否则该节点没有右孩子。
四、创建顺序存储结构的完全二叉树
顺序存储结构的完全二叉树结构简单且节省空间 ,而一般二叉树不适用于顺序结构储存
1 . 我们分析 完全二叉树的编号规则,对于编码是1~n 的 方式很容易实现,但是在顺序存储中(数组下标索引)是以0~n-1来编码的。需要一些特殊的方法来实现。
2 . 对于第一个节点,它的编码应该是0,那么它的 左右孩子节点分别应该是 1,2 但是如果按照2*i ,2*i+1的计算方式则是0,1。 明显的他不能是自己的左孩子。
3 . 对于0开始的编码,节点序号为i 他的左右子节点应该是 2*i+1, 2*i+2, 而它的双亲节点编码应该是 1~ n/2-1。
4 . 对于判断是否为左右孩子节点的公式吗,因为我们从 1~n 的排序变为了 0~n-1 所以我们的判断条件也变成了2*i+1<=n-1,2*i+2<=n-1。
图解:
创建一个Struct
typedef struct BiTnode{ int data; struct BiTnode *lchild, *rchild; }BiTnode,*BiTree;
我们 malloc 一片连续的大小为BiTnode*n的空间 然后使用数组下标索引先将值赋予这些值 之后在将每个节点的左右孩子通过上面所得到的公式进行连接,
#include <stdio.h> #include <stdlib.h> typedef struct BiTnode{ int data; struct BiTnode *lchild, *rchild; }BiTnode,*BiTree; /*根据数组生成完全二叉树*/ void Init(int data[], BiTree *T,int n){ int i; /*分配一片连续的空间,我们可以通过访问下标来访问在这片空间*/ *T = (BiTree)malloc(sizeof(BiTnode)*n); for(i=0;i<n;i++){ /*给这片连续的空间赋值,将数组的值存入,应为我们使用的顺序储存*/ (*T)[i].data = data[i]; (*T)[i].lchild = NULL; (*T)[i].rchild = NULL; } /*为双亲节点确定子节点 n/2 是双亲节点的个数(序号)限定*/ for(i=0;i<=(n/2)-1;i++){ if(2*i+2<=n){ (*T)[i].lchild = &((*T)[2*i+1]); } if(2*i+3<= n){ (*T)[i].rchild = &((*T)[2*i+2]); } } } int main(){ BiTree T; int data[] = {1,2,3,4,5,6}; Init(data,&T,6); return 0; }
通过内存查看 我们确定了创建成功