6.2 树的定义
树是 n (n >= 0) 个结点的有限集。n=0 时称为空树。在任意一棵非空树种:(1)有且仅有一个特定的称为根的结点;(2)当 n>1 时,其余结点可分为 m (m > 0) 个互不相交的有限集,其中每一个集合本身又是一棵树,并且称为根的子树。如下图所示:
6.3树的抽象数据类型
6.4 树的存储结构
6.5 二叉树
6.5.1 二叉树定义
二叉树是 n (n>=0) 个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根节点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成。
二叉树具有五种基本形态:
- 空二叉树
- 只有一个根结点
- 根结点只有左子树
- 根结点只有右子树
- 根结点既有左子树又有右子树
6.5.2特殊二叉树
直白点说,在同一层里面左边的二叉树必须是满的。
6.6二叉树的性质
性质1.在二叉树的第i层上至多有2i-1个结点(i>=1);
性质 2.深度为k的二叉树最多有2k-1个结点;
性质3.对任何一棵二叉树T,如果其叶子结点数为n0,度为2的结点数为n2,则n0 = n2 + 1;
性质4.具有n个结点的完全二叉树的深度为[log2n] + 1,[x]表示不大于x的最大整数;
性质5.
6.7二叉树的存储结构
·
6.8 遍历二叉树
二叉树的遍历是指从根结点出发,按照某种次序
依次访问
二叉树所有结点,使得每个结点被访问一次且仅被访问一次。
二叉树遍历方法
-
前序遍历
若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子树,再前序遍历右子树。
前序遍历次序:ABDGHCEIF
- 中序遍历 若二叉树为空,则空操作返回,否则从根结点开始(注意并不是先访问根结点),中序遍历根结点的左子树,然后访问根结点,最后中序遍历右子树。
![](http://upload-images.jianshu.io/upload_images/2665449-b59c9776915baece.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/277/format/webp)
中序遍历次序:GDHBAEICF
- 后序遍历 若二叉树为空,则空操作返回,否则从左到右先叶子后结点的方式遍历访问左右子树,最后是访问根结点。
![](http://upload-images.jianshu.io/upload_images/2665449-3bd4db95a7047a2e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/297/format/webp)
后序遍历次序:GHDBIEFCA
- 层次遍历 若二叉树为空,则空操作返回,否则从树的第一层,
![](http://upload-images.jianshu.io/upload_images/2665449-00f2e056c0d449da.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/305/format/webp)
层次遍历次序:ABCDEFGHI
![](https://img2018.cnblogs.com/blog/1542450/201904/1542450-20190417194735976-1241153904.png)
6.11 树转化为二叉树
6.12 赫夫曼树
#01 二叉树顺序结构实现
#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=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("\n"); 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("\n"); 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("\n"); 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("\n");}/* 逐层、按本层序号输出二叉树 */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("\n"); }}int main(){ Status i; Position p; TElemType e; SqBiTree T; InitBiTree(T); CreateBiTree(T); printf("建立二叉树后,树空否?%d(1:是 0:否) 树的深度=%d\n",BiTreeEmpty(T),BiTreeDepth(T)); i=Root(T,&e); if(i) printf("二叉树的根为:%d\n",e); else printf("树空,无根\n"); printf("层序遍历二叉树:\n"); LevelOrderTraverse(T); printf("前序遍历二叉树:\n"); PreOrderTraverse(T); printf("中序遍历二叉树:\n"); InOrderTraverse(T); printf("后序遍历二叉树:\n"); 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("前序遍历二叉树:\n"); PreOrderTraverse(T); printf("结点%d的双亲为%d,左右孩子分别为",e,Parent(T,e)); printf("%d,%d,左右兄弟分别为",LeftChild(T,e),RightChild(T,e)); printf("%d,%d\n",LeftSibling(T,e),RightSibling(T,e)); ClearBiTree(T); printf("清除二叉树后,树空否?%d(1:是 0:否) 树的深度=%d\n",BiTreeEmpty(T),BiTreeDepth(T)); i=Root(T,&e); if(i) printf("二叉树的根为:%d\n",e); else printf("树空,无根\n"); return 0;}
#02 二叉树链表实现
// 二叉树的实现(C语言)// 链表,递归实现#include#include #include typedef char Elementtype; // 定义数据类型,可根据需要自行定制typedef struct TreeNode * Node; // Node相当于struct treeNode *// 定义数节点结构typedef struct TreeNode { Elementtype Element; Node left; // 树节点的左子节点 Node right; // 树节点的右子节点}TREE,*PTREE;// 函数声明void CreatTree(PTREE *); // 树的先序创建函数void PreOrderTree(PTREE ); // 树的前序遍历函数void InOrderTree(PTREE ); // 树的中序遍历void PostOrderTree(PTREE ); // 树的后序遍历void LeafOfTree(PTREE ); // 打印树的叶子节点函数int Get_Leaf_Num(PTREE ); // 获取树叶子节点个数int Get_Height(PTREE ); // 获取树的高度// 主函数int main() { PTREE Root; printf("请先序输入二叉树的节点数据: "); CreatTree(&Root); printf("\n前序遍历结果为:"); PreOrderTree(Root); printf("\n中序遍历结果为:"); InOrderTree(Root); printf("\n后序遍历结果为:"); PostOrderTree(Root); printf("\n打印叶子节点为:"); LeafOfTree(Root); printf("\n叶子节点个数为:%d", Get_Leaf_Num(Root)); printf("\n二叉树的高度为:%d", Get_Height(Root)); printf("\n"); return 0;}// 定义树先序创建函数void CreatTree(PTREE *Root) { char val=0; // 用于下面存放数据 val=getchar(); // 输入数据值 // 如果输入'*',则指向为空 if (val == '*') (*Root) = NULL; // 如果输入非'*',则给数据域赋值 else { (*Root) = (PTREE)malloc(sizeof(TREE)); // 申请内存空间 if ((*Root) == NULL) { printf("创建节点失败,无法分配可用内存..."); exit(-1); } else { (*Root)->Element = val; // 给节点数据域赋值 CreatTree(&(*Root)->left); CreatTree(&(*Root)->right); } }}// 树的前序遍历函数定义void PreOrderTree(PTREE Root) { if (Root == NULL) return; else { putchar(Root->Element); PreOrderTree(Root->left); PreOrderTree(Root->right); }}// 树的中序遍历函数定义void InOrderTree(PTREE Root) { if (Root == NULL) return; else { InOrderTree(Root->left); putchar(Root->Element); InOrderTree(Root->right); }}// 树的后序遍历函数定义void PostOrderTree(PTREE Root) { if (Root==NULL) return ; else{ PostOrderTree(Root->left); PostOrderTree(Root->right); putchar( Root->Element); }}// 打印树的叶子节点函数定义void LeafOfTree(PTREE Tree) { if (Tree == NULL) return ; else { if (Tree->left == NULL&&Tree->right == NULL) putchar(Tree->Element); else { LeafOfTree(Tree->left); LeafOfTree(Tree->right); } }}// 获取树的叶子节点个数函数定义int Get_Leaf_Num(PTREE Tree) { if (Tree == NULL) return 0; if (Tree->left == NULL&&Tree->right == NULL) return 1; //递归整个树的叶子节点个数 = 左子树叶子节点的个数 + 右子树叶子节点的个数 return Get_Leaf_Num(Tree->left) + Get_Leaf_Num(Tree->right);}// 获取树高的函数定义int Get_Height(PTREE Tree) { int Height = 0; if (Tree == NULL) return 0; //树的高度 = max(左子树的高度,右子树的高度) + 1 else { int L_Height = Get_Height(Tree->left); int R_Height = Get_Height(Tree->right); Height = L_Height >= R_Height ? L_Height + 1 : R_Height + 1; } return Height;}