0
点赞
收藏
分享

微信扫一扫

第5章(树和二叉树)

飞鸟不急 2022-01-26 阅读 62
数据结构

目录

1. 树和二叉树的定义

1.1 树的定义

  • 树(Tree): n ( n ≥ 0 )个结点的有限集
    • 空树:n = 0
    • 非空树 T :
      • 有且只有一个称之为根的结点
      • 除根结点外的其余结点可分为 m ( m > 0)个互不相交的有限集 T_1 ,T_2 ,··· ,T_m
        • 其中每个集合本身又是一颗树,称为根的子树(SubTree)

1.2 树的基本术语

  • 结点:树种的一个独立单元,包含一个数据元素及若干指向其子树的分支
  • 结点的度:结点拥有的子树数量
  • 树的度:树内各结点度的最大值
  • 叶子(终端结点):度为 0 的结点
  • 非终端结点(分支结点):度不为 0 的结点;除根节点外,非终端结点也称为内部结点
  • 双亲和孩子
    • 结点的子树的根称为该结点的孩子
    • 该结点称为孩子的双亲
  • 兄弟:同一个双亲的孩子之间互称兄弟
  • 祖先:从根到该结点所经分支上的所有结点
  • 子孙:以某结点为根的子树种的任一结点
  • 层次:从根开始定义起,根为第一层,根的孩子为第二层,依次类推
  • 堂兄弟:双亲在同一层的结点互为堂兄弟
  • 树的深度(高度):树中结点的最大层次
  • 有序树和无序树
    • 有序树:树中结点的各子树是从左至右有次序的(不能互换)
      • 第一个孩子:最左边的子树的根
      • 最后一个孩子:最右边的子树的根
    • 无序树:与有序树相反
  • 森林:m ( m ≥ 0 )棵互不相交的树的集合

1.3 二叉树的定义

  • 二叉树(Binary Tree):n ( n ≥ 0 )个结点所构成的集合

    • 空树:n = 0
    • 非空树 T :
      • 有且只有一个称之为根的结点
      • 除根结点外的其余结点分为两个互不相交的子集 T_1 和 T_2 ,分别称为 T 的左子树和右子树
        • T_1 和 T_2 本身又都是二叉树
  • 二叉树和树的区别

    • 二叉树每个结点至多只有两棵子树
      • 二叉树中不存在度大于 2 的结点
    • 二叉树的子树有左右之分,其次序不能任意颠倒
  • 二叉树的 5 种基本形态

    • 空二叉树
    • 仅有根结点的二叉树
    • 右子树为空的二叉树
    • 左、右子树均非空的二叉树
    • 左子树为空的二叉树

2. 二叉树的性质和存储过程

2.1 二叉树的性质

  • 满二叉树:深度为 k 且含有 2^k - 1 个结点

    • 每一层上的结点数都是最大的结点数
      • 每一层 i 的结点数都具有最大值 2^(i-1)
  • 完全二叉树:深度为 k 的,有 n 个结点的二叉树,每一个结点都与深度为 k 的满二叉树中编号从 1 至 n 的结点一一对应

    • 叶子结点只可能是在层次最大的两层上出现
    • 对任一结点,若其右分支下的子孙的最大层次为 l ,则其左分支下的子孙的最大层次必为 l 或 l+1
  • 重要性质

    • 性质 1 :在二叉树的第 i 层上至多有 2^(i-1) 个结点(i ≥ 1)

    • 性质 2 :深度为 k 的二叉树至多有 2^k - 1 个结点(k ≥ 1)

    • 性质 3 :对任何一颗二叉树 T ,如果其终端结点数为 n_0 ,度为 2 的结点数为 n_2 ,则 n_0 = n_2 + 1
      n = n 0 + n 1 + n 2 n = n_0 + n_1 + n_2 n=n0+n1+n2

      n = ( 1 n 1 + 2 n 2 ) + 1 n = (1n_1 + 2n_2) + 1 n=(1n1+2n2)+1

    n 0 = n 2 + 1 n_0 = n_2 + 1 n0=n2+1

    • 性质 4 :具有 n 个结点的完全二叉树的深度为 ⌊ log_2 (n) ⌋ + 1
    • 性质 5 :如果对一棵有 n 个结点的完全二叉树(其深度为 ⌊ log_2 (n) ⌋ + 1 )的结点按层序编号(从第 1 层到第 ⌊ log_2 (n) ⌋ + 1 层,每层从左到右 ),则对任一结点 i ( 1 ≤ i ≤ n )
      • i = 1 :结点 i 是二叉树的根,无双亲
      • i > 1 :其双亲是结点 ⌊ i/2 ⌋
      • 2i > n :结点 i 无左孩子(结点 i 为叶子结点)或左孩子为结点 2i
      • 2i + 1 > n :结点 i 无右孩子或右孩子为结点 2i+1

2.2 二叉树的存储结构

2.2.1 顺序存储结构

#define MAXSIZE 10									// 二叉树的最大结点数

typedef TElemType SqBiTree[MAXSIZE];				// 0 号单元存储根结点		
SqBiTree bt;
  • 对于完全二叉树:从根起按层序存储,依次自上而下、从左至右存储结点元素
    • 将完全二叉树上编号为 i 的结点元素存储在如上定义的一维数组中下标为 i-1 的分量中
  • 对于一般二叉树:将其每个结点与完全二叉树上的结点相对照,存储在一维数组的相应分量中

2.2.2 链式存储结构

  • 构成
    • 数据域
    • 左指针域
    • 右指针域
    • 指向双亲结点的指针域
  • 在含有 n 个结点的二叉链表中有 n+1 个空链域
typedef struct BiTNode {
    ElemType elem;									// 结点数据域
    struct BiTNode *lchild;							// 左孩子指针
    struct BiTNode *rchild;							// 右孩子指针
} BiTNode, *BiTree;

3. 遍历二叉树和线索二叉树

3.1 遍历二叉树

  • 遍历二叉树(traversing ):按某条搜索路径巡防树种每个结点,使得每个结点均被访问一次,且仅被访问一次

  • 先序遍历二叉树

    • 访问根节点
    • 先序遍历左子树
    • 先序遍历右子树
  • 中序遍历二叉树

    • 中序遍历左子树
    • 访问根节点
    • 中序遍历右子树
  • 后序遍历二叉树

    • 后序遍历左子树
    • 后序遍历右子树
    • 访问根节点
  • 先序遍历:从上至下,从左至右

  • 中序遍历:从左至右,从上至下

  • 后序遍历:从下至上,从左至右

3.1.1 中序遍历的递归算法

void InOrderTraverse(BiTree T) {
	if (T) {
		InOrderTraverse(T->lchild);					// 中序遍历左子树
		printf("value = %d\n", T->value);			// 访问根节点
		InOrderTraverse(T->rchild);					// 中序遍历右子树
	}
}

3.1.2 中序遍历的非递归算法

  • 步骤
    • 初始化一个空栈 S ,指针 p 指向根结点
    • 申请一个结点空间 q ,用来存放栈顶弹出的元素
    • 当 p 非空或栈 S 非空时,循环执行以下操作
      • p 非空,p 进栈,p 指向该结点的左孩子
      • p 为空,弹出栈顶元素并访问,将 p 指向该结点的右孩子
void InOrderTraverse(BiTree T) {
    BiTree* p = T;
    BiNode q = (BiNode*)malloc(sizeof(BiNode));
    
    InitStack(S);
    while (p || StackEmpty(S)) {
        if (p) {									// p 非空
            Push(S, p);								// 根指针进栈
            p = p->lchild;							// 遍历左子树
        } else {
            Pop(S, q);								// 退栈
            printf("value = %d\n", T->value);		// 访问根节点
            p = q->rchild;							// 遍历右子树
        }
    }
}

3.1.3 先序遍历的顺序建立二叉链表

void CreateBiTree(BiTree* T) {
	int value;
	printf("Enter : ");
	scanf("%d", &value);

	if (value == 0) {
		(*T) = NULL;								// 递归结束,创建空树
	}
	else {
		(*T) = (BiTNode*)malloc(sizeof(BiTNode));	// 生成根结点
		(*T)->value = value;						// 根结点数据域置为 value
		CreateBiTree(&((*T)->lchild));				// 递归创建左子树
		CreateBiTree(&((*T)->rchild));				// 递归创建右子树
	}
}

3.1.4 复制二叉树

void Copy(BiTree T, BiTree* NewT) {
	if (T == NULL)
	{
		*NewT = NULL;								// 递归结束
	}
	else {
		*NewT = (BiTNode*)malloc(sizeof(BiTNode));	
		(*NewT)->value = T->value;					// 复制根结点
		printf("copy value = %d\n", T->value);
		Copy(T->lchild, &(*NewT)->lchild);			// 递归复制左子树
		Copy(T->rchild, &(*NewT)->rchild);			// 递归复制右子树
	}
}

3.1.5 计算二叉树的深度

int Depth(BiTree T) {
	if (T)
	{
		int i = Depth(T->lchild);					// 递归计算左子树的深度记为 i
		int j = Depth(T->rchild);					// 递归计算右子树的深度记为 j
		return (i > j) ? i + 1 : j + 1;
	}
	else
	{
		return 0;									// 递归结束,深度为 0
	}
}

3.1.6 统计二叉树中结点的个数

int NodeCount(BiTree T) {
	return T ? NodeCount(T->lchild) + NodeCount(T->rchild) + 1 : 0;
    // T 不为空 : 结点个数 = 左子树的结点个数 + 右子树结点个数 + 1
    // T 为空 : 结点个数为 0 ,递归结束
}

测试代码

#include <stdio.h>
#include <stdlib.h>

void InOrderTraverse(BiTree);
void CreateBiTree(BiTree);
void Copy(BiTree, BiTree);
int Depth(BiTree);
int NodeCount(BiTree);

typedef struct BiTNode {
	int value;
	struct BiTNode* lchild;
	struct BiTNode* rchild;
} BiTNode, *BiTree;

int main() {
	BiTree tree1;
	BiTree tree2;
	CreateBiTree(&tree1);
	printf("Create Success\n");
	printf("****************\n");

	InOrderTraverse(tree1);
	printf("Traverse Success\n");
	printf("****************\n");

	Copy(tree1, &tree2);
	printf("Copy Success\n");
	printf("****************\n");

	InOrderTraverse(tree2);
	printf("Traverse Success\n");
	printf("****************\n");

	int depth = Depth(tree1);
	printf("depth = %d\n", depth);
	printf("****************\n");

	int count = NodeCount(tree1);
	printf("count = %d\n", count);
	printf("****************\n");
}

void InOrderTraverse(BiTree T) {
	if (T) {
		InOrderTraverse(T->lchild);
		printf("value = %d\n", T->value);
		InOrderTraverse(T->rchild);
	}
}

void CreateBiTree(BiTree* T) {
	int value;
	printf("Enter : ");
	scanf("%d", &value);

	if (value == 0) {
		*T = NULL;
	}
	else {
		*T = (BiTNode*)malloc(sizeof(BiTNode));
		(*T)->value = value;
		CreateBiTree(&((*T)->lchild));
		CreateBiTree(&((*T)->rchild));
	}
}

void Copy(BiTree T, BiTree* NewT) {
	if (T == NULL)
	{
		*NewT = NULL;
	}
	else {
		*NewT = (BiTNode*)malloc(sizeof(BiTNode));
		(*NewT)->value = T->value;
		printf("copy value = %d\n", T->value);
		Copy(T->lchild, &(*NewT)->lchild);
		Copy(T->rchild, &(*NewT)->rchild);
	}
}

int Depth(BiTree T) {
	if (T)
	{
		int i = Depth(T->lchild);
		int j = Depth(T->rchild);
		return (i > j) ? i + 1 : j + 1;
	}
	else
	{
		return 0;
	}
}

int NodeCount(BiTree T) {
	return T ? NodeCount(T->lchild) + NodeCount(T->rchild) + 1 : 0;
}
举报

相关推荐

0 条评论