数据结构——二叉树
1 二叉树定义
是n(n>0)个结点的有限集合,当n=0是称为空树;在任意一棵非空树中:有且仅有一个根结点,当n>1时,除根结点外的其余结点可分为左子树和右子树;
1.1 二叉树特点
1.2 二叉树形态
1.3 特殊二叉树
1.3.1 斜树
左斜二叉树:二叉树的所有结点都只有左子树
右斜二叉树:二叉树的所有结点都只有右子树
1.3.2 满二叉树
一棵深度为k,且有2k-1个结点的二叉树
特点:
每一层上的结点树总是最大结点数;
所有枝结点(枝结点就是下图中前7个结点)都有左右子树;
可对满二叉树的结点进行连续编号,若规定从跟结点开始,按“自上而下,自左向右”的原则进行;
1.3.3 完全二叉树
如果深度为k,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1到n的结点一一对应
注:对于上图的完全二叉树,叶子结点不能出现在第二层,只能出现在第三或第四层,因为在第二层不能满足与满二叉树的编号一一对应。
特点:
1.完全二叉树是满二叉树的一部分,而满二叉树是完全二叉树的特例
2.若完全二叉树的深度为k,则所有的叶子结点都出现在第k层或k-1层
3.对于任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+1
2 二叉树的性质
性质1:在非空二叉树中,第i层上至多有2i-1个结点(i>=1)
性质2:深度为k的二叉树,至多有2k-1个结点(k>=1)
性质3:对任何一棵二叉树,若其叶子结点为n0,度为2的结点数为n2,则n0=n2+1;
性质4:具有n个结点的完全二叉树,其深度为log2n+1;
性质5:如果对一棵有n个结点的完全二叉树,其结点按层编号,对任意结点i有(n>=i>=1)
如果i=1,则结点i是二叉树的根;
如果i>1,择期双亲结点为i/2;
如果2i>n,则结点i无左孩子,即为叶子结点,否则其左孩子结点为2i
如果2i+1>n,则结点i无右孩子,否则其右孩子结点为2i+1
3 二叉树的存储结构
3.1 二叉树的顺序存储结构
3.1.1 满二叉树的顺序存储结构
3.1.2 完全二叉树的顺序存储结构
3.1.3 一般二叉树的顺序存储结构
3.2 二叉树的链式存储结构
3.2.1 二叉树链式结构定义
typedef int DataType typedef struct BitNode { DataType data; struct BitNode *left,*right; }BitNode;
3.2.2 链式存储结构扩展
3.2.3 扩展链式存储结构定义
typedef int DataType typedef struct BitNode { DataType data; struct BitNode *left,*right,*parent; }BitNode;
4 二叉树遍历
遍历
是按照指定的规律,从根结点开始,对二叉树的每个结点访问一次,且仅访问一次;
访问是指对结点做某种处理,如:输出信息、修改结点的值等;
遍历方式
二叉树是一种非线性结构
每个结点都可能有左右两棵子树
需要寻找一种规律,使二叉树的结点能排列在一个线性列队上,从而便于遍历
二叉树的基本组成
根结点、左子树、右子树
依次遍历这三部分就是遍历了二叉树
若以L、D、R分别表示遍历左子树、遍历根结点、遍历右子树
则有六种遍历方案:DLR、DRL、LDR、LRD、RDL、RLD
若规定先左后右,则只有三种情况:DLR:先序遍历
LDR:中序遍历
LRD:后序遍历
4.1 先序遍历
遍历根结点、遍历左子树、遍历右子树
void preOrderTraverse(BitNode *root) { if(root==NULL) return; printf("%d",root->data); preOrderTraverse(root->left); preOrderTraverse(root->right); }
4.2 中序遍历
遍历左子树、遍历根结点、遍历右子树
void inOrderTraverse(BitNode *root) { if(root==NULL) return; preOrderTraverse(root->left); printf("%d",root->data); preOrderTraverse(root->right); }
4.3 后续遍历
遍历左子树、遍历右子树、遍历根结点
void postOrderTraverse(BitNode *root) { if(root==NULL) return; preOrderTraverse(root->left); preOrderTraverse(root->right); printf("%d",root->data); }