一、顺序存储结构对数这种一对多的关系结构实现起来是比较困难的。但是二叉树是一种特殊的树,由于它的特殊性,使得用顺序存储结构也可以实现。
二、二叉树的顺序存储结构就是用一维数组存储二叉树中的结点,并且结点的存储位置,也就是数组的下标要能体现结点之间的逻辑关系,比如双亲与孩子的关系,左右兄弟的关系等。
三、完全二叉树可以将相应下标的结点存到数组的相应下标的位置上,对于一般的二叉树来说,完全可以将其按完全二叉树编号,只不过,把不存在的结点设置为“null”而已。这显然是对存储空间的浪费,所以,顺序存储结构一般只用于完全二叉树。
四、复习一下二叉树的性质
1.在二叉树的第i层上至多有2^i个结点(i从0开始)。
2.深度为k的二叉树至多有2^k -1个结点(k从1开始)。
3.对任何一颗二叉树T,如果其终端节点树为n0,度为2的结点数为n2,则n0 = n2 +1(设度为1的结点数为n1,则结点总数为n=n0+n1+n2;又由于除了根结点外,每一个结点均对应一个进入它的分支,所以分支总数=n-1,又由于度为1的结点对应着1个从它引出的分支,度为2的结点对应着2个从它引出的分支,所以分支总数=n1+2*n2,即n-1=n1+2*n2)。
4.具有n个结点的完全二叉树的深度为【log2 n】+1(【x】表示不大于x的最大整数)(深度为k的满二叉树的结点数n一定是2^k -1)
5.如果对一颗有n个结点的完全二叉树(其深度为【log2 n】+1)的结点按层序编号(从第1层到第【log2 n】+1层,每层从左到右),对任一结点i(0<=i<=n-1)有:
- 如果i=0,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结点【(i-1)/2】
- 如果2i+1>n,则结点i无左孩子;否则其左孩子是结点2i+1
- 如果2i+2>n,则结点i无右孩子;否则其右孩子是结点2i+2
五、二叉树的顺序存储结构的C语言代码实现:
#include "stdio.h" #include "stdlib.h" #include "io.h" #include "math.h" #include "time.h" #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 #define MAXSIZE 100 /* 存储空间初始分配量 */ #define MAX_TREE_SIZE 100 /* 二叉树的最大结点数 */ typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */ typedef int TElemType; /* 树结点的数据类型,目前暂定为整型 */ typedef TElemType SqBiTree[MAX_TREE_SIZE]; /* 0号单元存储根结点 */ typedef struct { int level,order; /* 结点的层,本层序号(按满二叉树计算) */ }Position; TElemType Nil=0; /* 设整型以0为空 */ Status visit(TElemType c) { printf("%d ",c); return OK; } /* 构造空二叉树T。因为T是固定数组,不会改变,故不需要& */ Status InitBiTree(SqBiTree T) { int i; for(i=0;i<MAX_TREE_SIZE;i++) T[i]=Nil; /* 初值为空 */ return OK; } /* 按层序次序输入二叉树中结点的值(字符型或整型), 构造顺序存储的二叉树T */ Status CreateBiTree(SqBiTree T) { int i=0; printf("请按层序输入结点的值(整型),0表示空结点,输999结束。结点数≤%d: ",MAX_TREE_SIZE); while(i<10) { T[i]=i+1; if(i!=0&&T[(i+1)/2-1]==Nil&&T[i]!=Nil) /* 此结点(不空)无双亲且不是根 */ { printf("出现无双亲的非根结点%d ",T[i]); exit(ERROR); } i++; } while(i<MAX_TREE_SIZE) { T[i]=Nil; /* 将空赋值给T的后面的结点 */ i++; } return OK; } #define ClearBiTree InitBiTree /* 在顺序存储结构中,两函数完全一样 */ /* 初始条件: 二叉树T存在 */ /* 操作结果: 若T为空二叉树,则返回TRUE,否则FALSE */ Status BiTreeEmpty(SqBiTree T) { if(T[0]==Nil) /* 根结点为空,则树空 */ return TRUE; else return FALSE; } /* 初始条件: 二叉树T存在。操作结果: 返回T的深度 */ int BiTreeDepth(SqBiTree T) { int i,j=-1; for(i=MAX_TREE_SIZE-1;i>=0;i--) /* 找到最后一个结点 */ if(T[i]!=Nil) break; i++; do j++; while(i>=powl(2,j));/* 计算2的j次幂。 */ return j; } /* 初始条件: 二叉树T存在 */ /* 操作结果: 当T不空,用e返回T的根,返回OK;否则返回ERROR,e无定义 */ Status Root(SqBiTree T,TElemType *e) { if(BiTreeEmpty(T)) /* T空 */ return ERROR; else { *e=T[0]; return OK; } } /* 初始条件: 二叉树T存在,e是T中某个结点(的位置) */ /* 操作结果: 返回处于位置e(层,本层序号)的结点的值 */ TElemType Value(SqBiTree T,Position e) { return T[(int)powl(2,e.level-1)+e.order-2]; } /* 初始条件: 二叉树T存在,e是T中某个结点(的位置) */ /* 操作结果: 给处于位置e(层,本层序号)的结点赋新值value */ Status Assign(SqBiTree T,Position e,TElemType value) { int i=(int)powl(2,e.level-1)+e.order-2; /* 将层、本层序号转为矩阵的序号 */ if(value!=Nil&&T[(i+1)/2-1]==Nil) /* 给叶子赋非空值但双亲为空 */ return ERROR; else if(value==Nil&&(T[i*2+1]!=Nil||T[i*2+2]!=Nil)) /* 给双亲赋空值但有叶子(不空) */ return ERROR; T[i]=value; return OK; } /* 初始条件: 二叉树T存在,e是T中某个结点 */ /* 操作结果: 若e是T的非根结点,则返回它的双亲,否则返回"空" */ TElemType Parent(SqBiTree T,TElemType e) { int i; if(T[0]==Nil) /* 空树 */ return Nil; for(i=1;i<=MAX_TREE_SIZE-1;i++) if(T[i]==e) /* 找到e */ return T[(i+1)/2-1]; return Nil; /* 没找到e */ } /* 初始条件: 二叉树T存在,e是T中某个结点 */ /* 操作结果: 返回e的左孩子。若e无左孩子,则返回"空" */ TElemType LeftChild(SqBiTree T,TElemType e) { int i; if(T[0]==Nil) /* 空树 */ return Nil; for(i=0;i<=MAX_TREE_SIZE-1;i++) if(T[i]==e) /* 找到e */ return T[i*2+1]; return Nil; /* 没找到e */ } /* 初始条件: 二叉树T存在,e是T中某个结点 */ /* 操作结果: 返回e的右孩子。若e无右孩子,则返回"空" */ TElemType RightChild(SqBiTree T,TElemType e) { int i; if(T[0]==Nil) /* 空树 */ return Nil; for(i=0;i<=MAX_TREE_SIZE-1;i++) if(T[i]==e) /* 找到e */ return T[i*2+2]; return Nil; /* 没找到e */ } /* 初始条件: 二叉树T存在,e是T中某个结点 */ /* 操作结果: 返回e的左兄弟。若e是T的左孩子或无左兄弟,则返回"空" */ TElemType LeftSibling(SqBiTree T,TElemType e) { int i; if(T[0]==Nil) /* 空树 */ return Nil; for(i=1;i<=MAX_TREE_SIZE-1;i++) if(T[i]==e&&i%2==0) /* 找到e且其序号为偶数(是右孩子) */ return T[i-1]; return Nil; /* 没找到e */ } /* 初始条件: 二叉树T存在,e是T中某个结点 */ /* 操作结果: 返回e的右兄弟。若e是T的右孩子或无右兄弟,则返回"空" */ TElemType RightSibling(SqBiTree T,TElemType e) { int i; if(T[0]==Nil) /* 空树 */ return Nil; for(i=1;i<=MAX_TREE_SIZE-1;i++) if(T[i]==e&&i%2) /* 找到e且其序号为奇数(是左孩子) */ return T[i+1]; return Nil; /* 没找到e */ } /* PreOrderTraverse()调用 */ void PreTraverse(SqBiTree T,int e) { visit(T[e]); if(T[2*e+1]!=Nil) /* 左子树不空 */ PreTraverse(T,2*e+1); if(T[2*e+2]!=Nil) /* 右子树不空 */ PreTraverse(T,2*e+2); } /* 初始条件: 二叉树存在 */ /* 操作结果: 先序遍历T。 */ Status PreOrderTraverse(SqBiTree T) { if(!BiTreeEmpty(T)) /* 树不空 */ PreTraverse(T,0); printf(" "); return OK; } /* InOrderTraverse()调用 */ void InTraverse(SqBiTree T,int e) { if(T[2*e+1]!=Nil) /* 左子树不空 */ InTraverse(T,2*e+1); visit(T[e]); if(T[2*e+2]!=Nil) /* 右子树不空 */ InTraverse(T,2*e+2); } /* 初始条件: 二叉树存在 */ /* 操作结果: 中序遍历T。 */ Status InOrderTraverse(SqBiTree T) { if(!BiTreeEmpty(T)) /* 树不空 */ InTraverse(T,0); printf(" "); return OK; } /* PostOrderTraverse()调用 */ void PostTraverse(SqBiTree T,int e) { if(T[2*e+1]!=Nil) /* 左子树不空 */ PostTraverse(T,2*e+1); if(T[2*e+2]!=Nil) /* 右子树不空 */ PostTraverse(T,2*e+2); visit(T[e]); } /* 初始条件: 二叉树T存在 */ /* 操作结果: 后序遍历T。 */ Status PostOrderTraverse(SqBiTree T) { if(!BiTreeEmpty(T)) /* 树不空 */ PostTraverse(T,0); printf(" "); return OK; } /* 层序遍历二叉树 */ void LevelOrderTraverse(SqBiTree T) { int i=MAX_TREE_SIZE-1,j; while(T[i]==Nil) i--; /* 找到最后一个非空结点的序号 */ for(j=0;j<=i;j++) /* 从根结点起,按层序遍历二叉树 */ if(T[j]!=Nil) visit(T[j]); /* 只遍历非空的结点 */ printf(" "); } /* 逐层、按本层序号输出二叉树 */ void Print(SqBiTree T) { int j,k; Position p; TElemType e; for(j=1;j<=BiTreeDepth(T);j++) { printf("第%d层: ",j); for(k=1;k<=powl(2,j-1);k++) { p.level=j; p.order=k; e=Value(T,p); if(e!=Nil) printf("%d:%d ",k,e); } printf(" "); } } int main() { Status i; Position p; TElemType e; SqBiTree T; InitBiTree(T); CreateBiTree(T); printf("建立二叉树后,树空否?%d(1:是 0:否) 树的深度=%d ",BiTreeEmpty(T),BiTreeDepth(T)); i=Root(T,&e); if(i) printf("二叉树的根为:%d ",e); else printf("树空,无根 "); printf("层序遍历二叉树: "); LevelOrderTraverse(T); printf("前序遍历二叉树: "); PreOrderTraverse(T); printf("中序遍历二叉树: "); InOrderTraverse(T); printf("后序遍历二叉树: "); PostOrderTraverse(T); printf("修改结点的层号3本层序号2。"); p.level=3; p.order=2; e=Value(T,p); printf("待修改结点的原值为%d请输入新值:50 ",e); e=50; Assign(T,p,e); printf("前序遍历二叉树: "); PreOrderTraverse(T); printf("结点%d的双亲为%d,左右孩子分别为",e,Parent(T,e)); printf("%d,%d,左右兄弟分别为",LeftChild(T,e),RightChild(T,e)); printf("%d,%d ",LeftSibling(T,e),RightSibling(T,e)); ClearBiTree(T); printf("清除二叉树后,树空否?%d(1:是 0:否) 树的深度=%d ",BiTreeEmpty(T),BiTreeDepth(T)); i=Root(T,&e); if(i) printf("二叉树的根为:%d ",e); else printf("树空,无根 "); return 0; } 输出为: 请按层序输入结点的值(整型),0表示空结点,输999结束。结点数≤100: 建立二叉树后,树空否?0(1:是 0:否) 树的深度=4 二叉树的根为:1 层序遍历二叉树: 1 2 3 4 5 6 7 8 9 10 前序遍历二叉树: 1 2 4 8 9 5 10 3 6 7 中序遍历二叉树: 8 4 9 2 10 5 1 6 3 7 后序遍历二叉树: 8 9 4 10 5 2 6 7 3 1 修改结点的层号3本层序号2。待修改结点的原值为5请输入新值:50 前序遍历二叉树: 1 2 4 8 9 50 10 3 6 7 结点50的双亲为2,左右孩子分别为10,0,左右兄弟分别为4,0 清除二叉树后,树空否?1(1:是 0:否) 树的深度=0 树空,无根
六、二叉树的顺序存储结构的Java语言代码实现:
- 接口类:
package bigjun.iplab.sequenceBiTree; /** * 二叉树的顺序存储结构通常用来对完全二叉树进行存储 */ public interface SequenceBiTreeINF { // 判断完全二叉树是否为空 public boolean isBiTreeEmpty(); // 求完全二叉树的深度 public int getBiTreeDepth(); // 求完全二叉树的根结点数据元素 public Object getBiTreeRoot() throws Exception; // 求完全二叉树的某个数据e的双亲 public Object getMyParent(Object e) throws Exception; // 求完全二叉树的某个数据e的左孩子 public Object getMyLeftChild(Object e) throws Exception; // 求完全二叉树的某个数据e的右孩子 public Object getMyRightChild(Object e) throws Exception; // 求完全二叉树的某个数据e的左兄弟 public Object getMyLeftSibling(Object e) throws Exception; // 求完全二叉树的某个数据e的右兄弟 public Object getMyRightSibling(Object e) throws Exception; // 求完全二叉树的第levelNum层的数据元素并打印出来 public void printByLevel(int levelNum) throws Exception; // 完全二叉树的前序遍历 public void preOrderTraverse(); // 完全二叉树的中序遍历 public void inOrderTraverse(); // 完全二叉树的后序遍历 public void postOrderTraverse(); // 完全二叉树的层序遍历 public void levelOrderTraverse(); }
- 实现类:
package bigjun.iplab.sequenceBiTree; public class SequenceBiTree implements SequenceBiTreeINF{ private static final int MAX_TREE_SIZE = 100; private Object[] seqBiTree; public SequenceBiTree() { seqBiTree = new Object[MAX_TREE_SIZE]; for (int i = 0; i < MAX_TREE_SIZE; i++) seqBiTree[i] = null; } public boolean isBiTreeEmpty() { return seqBiTree[0] == null; } public int getBiTreeDepth() { int i = 0; int j = -1; for (i = MAX_TREE_SIZE - 1; i >= 0; i--) { // 从后往前找到最后一个结点的位置 if (seqBiTree[i] != null) { break; } } i++; do { j++; } while (i >= Math.pow(2, j)); // 计算求得不大于log以2为底i的对数 return j; } public Object getBiTreeRoot() throws Exception { if (isBiTreeEmpty()) throw new Exception("二叉树为空,无法获取根结点的值"); return seqBiTree[0]; } public Object getMyParent(Object e) throws Exception { if (isBiTreeEmpty()) throw new Exception("二叉树为空,无法获取结点的双亲"); int parentNum = -1; for (int i = 1; i < seqBiTree.length; i++) { // 根结点没有双亲,从1开始 if (seqBiTree[i] == e) { parentNum = (i+1)/2-1; } } if (parentNum == -1) { throw new Exception("无法在二叉树中匹配到e"); } else { return seqBiTree[parentNum]; } } public Object getMyLeftChild(Object e) throws Exception { if (isBiTreeEmpty()) throw new Exception("二叉树为空,无法获取结点的双亲"); int lchildNum = -1; for (int i = 0; i < seqBiTree.length; i++) { // 根结点有可能有左孩子,从0开始 if (seqBiTree[i] == e) { lchildNum = 2*i+1; } } if (lchildNum == -1) { throw new Exception("无法在二叉树中匹配到e"); } else if (seqBiTree[lchildNum] == null) { return null; } else { return seqBiTree[lchildNum]; } } public Object getMyRightChild(Object e) throws Exception { if (isBiTreeEmpty()) throw new Exception("二叉树为空,无法获取结点的双亲"); int rchildNum = -1; for (int i = 0; i < seqBiTree.length; i++) { // 根结点有可能有左孩子,从0开始 if (seqBiTree[i] == e) { rchildNum = 2*i+2; } } if (rchildNum == -1) { throw new Exception("无法在二叉树中匹配到e"); } else if (seqBiTree[rchildNum] == null) { return null; } else { return seqBiTree[rchildNum]; } } public Object getMyLeftSibling(Object e) throws Exception { if (isBiTreeEmpty()) throw new Exception("二叉树为空,无法获取结点的右兄弟"); int lsiblingNum = -1; for (int i = 1; i < seqBiTree.length; i++) { // 根结点不可能有左兄弟,从1开始 if (seqBiTree[i] == e && i%2 == 0) { // 找到e并且其序号i为偶数(是右孩子) lsiblingNum = i - 1; } } if (lsiblingNum == -1 ) { throw new Exception("无法在二叉树中匹配到e或e本来就是左孩子"); } else if (seqBiTree[lsiblingNum] == null) { return null; } else { return seqBiTree[lsiblingNum]; } } public Object getMyRightSibling(Object e) throws Exception { if (isBiTreeEmpty()) throw new Exception("二叉树为空,无法获取结点的右兄弟"); int rsiblingNum = -1; for (int i = 1; i < seqBiTree.length; i++) { // 根结点不可能有右兄弟,从1开始 if (seqBiTree[i] == e && i%2 == 1) { // 找到e并且其序号i为奇数(是左孩子) rsiblingNum = i + 1; } } if (rsiblingNum == -1) { throw new Exception("无法在二叉树中匹配到e或e本来就是右孩子"); } else if (seqBiTree[rsiblingNum] == null) { return null; } else { return seqBiTree[rsiblingNum]; } } public void printByLevel(int levelNum) throws Exception { if (levelNum < 1 || levelNum > getBiTreeDepth()) { throw new Exception("层序号不合法"); } System.out.print("第" + levelNum + "层的数据为: "); for (int i = (int) Math.pow(2, levelNum - 1) - 1; i <= Math.pow(2, levelNum) - 2 ; i++) { if (seqBiTree[i] != null) { System.out.print(seqBiTree[i] + " "); } else { System.out.print("null" + " "); } } System.out.println(); } /**********前序遍历算法***************/ public void preTraverse(int e) { System.out.print(seqBiTree[e] + " "); if (seqBiTree[2*e+1]!=null) { preTraverse(2*e+1); } if (seqBiTree[2*e+2]!=null) { preTraverse(2*e+2); } } public void preOrderTraverse() { System.out.print("前序遍历算法得到的序列为: "); if (!isBiTreeEmpty()) { preTraverse(0); } System.out.println(); } /**********中序遍历算法***************/ public void inTraverse(int e) { if (seqBiTree[2*e+1]!=null) { inTraverse(2*e+1); } System.out.print(seqBiTree[e] + " "); if (seqBiTree[2*e+2]!=null) { inTraverse(2*e+2); } } public void inOrderTraverse() { System.out.print("中序遍历算法得到的序列为: "); if (!isBiTreeEmpty()) { inTraverse(0); } System.out.println(); } /**********后序遍历算法***************/ public void postTraverse(int e) { if (seqBiTree[2*e+1]!=null) { postTraverse(2*e+1); } System.out.print(seqBiTree[e] + " "); if (seqBiTree[2*e+2]!=null) { postTraverse(2*e+2); } } public void postOrderTraverse() { System.out.print("后序遍历算法得到的序列为: "); if (!isBiTreeEmpty()) { postTraverse(0); } System.out.println(); } /**********层序遍历算法***************/ public void levelOrderTraverse() { System.out.print("层序遍历算法得到的序列为: "); int i = MAX_TREE_SIZE - 1; while (seqBiTree[i] == null) { i--; } for (int j = 0; j <= i; j++) { if (seqBiTree[j] != null) { System.out.print(seqBiTree[j] + " "); } } System.out.println(); } public Object[] createBiTree() throws Exception { int i = 0; while (i < 10) { seqBiTree[i] = i + 1; if (i!=0 && seqBiTree[(i+1)/2-1]==null&&seqBiTree[i]!=null) { throw new Exception("出现无双亲的非根结点"); } i++; } while (i<MAX_TREE_SIZE) { seqBiTree[i] = null; i++; } return seqBiTree; } public static void main(String[] args) throws Exception { SequenceBiTree seqBiTree = new SequenceBiTree(); seqBiTree.createBiTree(); seqBiTree.preOrderTraverse(); seqBiTree.inOrderTraverse(); seqBiTree.postOrderTraverse(); seqBiTree.levelOrderTraverse(); System.out.println("二叉树的深度为: " + seqBiTree.getBiTreeDepth()); System.out.println("二叉树的根结点为: " + seqBiTree.getBiTreeRoot()); System.out.println("二叉树中,数据为8的双亲为: " + seqBiTree.getMyParent(8)); System.out.println("二叉树中,数据为4的左孩子为: " + seqBiTree.getMyLeftChild(4)); System.out.println("二叉树中,数据为4的右孩子为: " + seqBiTree.getMyRightChild(4)); System.out.println("二叉树中,数据为8的右兄弟为: " + seqBiTree.getMyRightSibling(8)); System.out.println("二叉树中,数据为9的兄弟子为: " + seqBiTree.getMyLeftSibling(9)); System.out.println("*******************************************"); System.out.println("按层序分别打印每一层的数据为: "); for (int i = 1; i <= seqBiTree.getBiTreeDepth(); i++) { seqBiTree.printByLevel(i); } System.out.println("*******************************************"); } }
- 输出:
前序遍历算法得到的序列为: 1 2 4 8 9 5 10 3 6 7 中序遍历算法得到的序列为: 8 4 9 2 10 5 1 6 3 7 后序遍历算法得到的序列为: 8 4 9 2 10 5 1 6 3 7 层序遍历算法得到的序列为: 1 2 3 4 5 6 7 8 9 10 二叉树的深度为: 4 二叉树的根结点为: 1 二叉树中,数据为8的双亲为: 4 二叉树中,数据为4的左孩子为: 8 二叉树中,数据为4的右孩子为: 9 二叉树中,数据为8的右兄弟为: 9 二叉树中,数据为9的兄弟子为: 8 ******************************************* 按层序分别打印每一层的数据为: 第1层的数据为: 1 第2层的数据为: 2 3 第3层的数据为: 4 5 6 7 第4层的数据为: 8 9 10 null null null null null *******************************************