二叉树备忘
二叉树基本概念及性质
二叉树(binary tree)是一棵树,每个结点最多有两个儿子(0/1/2),本质上就是图(graph);根据定义,二叉树有以下五种形态:

二叉树的特点如下图:

特殊的二叉树有斜二叉树,满二叉树和完全二叉树,
- 斜二叉树:每一层只有一个结点,每个结点仅有左子树的称为左斜树,反之称为右斜树;
- 满二叉树:所有的分支结点都有左子树和右子树,所有的叶结点都处在同一层;
- 完全二叉树:树中的结点按层编号,与满二叉树对应编号的结点位置相同,即完全二叉树“是满二叉树的一部分”,因此满二叉树一定是完全二叉树,但是完全二叉树不一定是满的;
二叉树可以表示多叉树,
在多叉树中,“长子-兄弟法”用firstChild()表示父结点的长子结点【左子树】,<子结点>用nextSibling()依次指向【右子树】,

二叉树的存储结构
二叉树的存储结构分为顺序存储结构(数组)和链式存储结构,其中顺序存储结构只适用于存储完全二叉树;
二叉树非递归遍历
1. 先(根)序遍历(“根左右”)
1.2 迭代实现 & 两种版本:
迭代版本一:根结点入栈,根据栈FILO的特性,先遍历的左孩子后入先出,后遍历的右孩子先入后出;
迭代版本一:根结点入栈,根据栈FILO的特性,先遍历的左孩子后入先出,后遍历的右孩子先入后出;

迭代版本二:先自上而下访问左侧链上的节点,将每个左侧链节点的右孩子入栈,再自下而上访问它们的右子树;

2. 中(根)序遍历(“左根右”)
2.2 迭代遍历:
借用辅助栈,沿着左侧链下行,自下而上访问左侧链结点,并遍历对应的右子树;
时间复杂度为O(n),空间复杂度线性正比于二叉树的高度,最坏情况下与结点总数相当;

3. 后(根)序遍历(“左右根”)
3.2 迭代遍历方法:
访问当前结点,遍历以其右兄弟(若存在)为根的子树,向上回溯至父结点(若存在),转入下一个片段;

4. 层序遍历
从根结点开始,自上而下逐层遍历,同一层中从左到右遍历;

二叉树重构
已知先序序列和中序序列可确定一棵唯一的二叉树;
已知后序序列和中序序列可确定一棵唯一的二叉树;
仅凭借先序序列和后序序列不能确定一棵唯一的二叉树,当左子树或者右子树有空树情况时,无法判断左右子树哪一方为空树,引起歧义,从而重构二叉树不唯一;
重构二叉树为真二叉树(结点的度为0或者2),左右子树同时为空或者不为空,凭借先序序列和后序序列可以确定唯一的真二叉树;
重构二叉树为真二叉树(结点的度为0或者2),左右子树同时为空或者不为空,凭借先序序列和后序序列可以确定唯一的真二叉树;
二叉树创建&遍历完整代码部分
前序序列: 1 2 4 7 -1 -1 8 -1 -1 -1 3 5 -1 9 -1 -1 6 -1 -1前序遍历: 1 2 4 7 # # 8 # # # 3 5 # 9 # # 6 # #中序遍历: # 7 # 4 # 8 # 2 # 1 # 5 # 9 # 3 # 6 #后序遍历: # # 7 # # 8 4 # 2 # # # 9 5 # # 6 3 1
/** File name:BinaryTreeByList.c* Description: 前序序列创建二叉树,前序/中序/后序递归遍历二叉树* Author: yzwall* Data: 2016/9/19 20:12*/#include <stdio.h>#include <stdlib.h>//////////////////////////////////////////////////////////typedef int ElementType;// 二叉树结点结构typedef struct BiTreeNode {ElementType element;struct BiTreeNode *lchild; // 左孩子结点指针struct BiTreeNode *rchild; // 右孩子结点指针} BiTreeNode;//////////////////////////////////////////////////////////// 前序递归遍历preorder recursive traversalvoid traversalPreOrder(BiTreeNode *bt) {if(bt == NULL) {printf("#\n");return; // 递归无返回值,可通过return;返回上次递归位置} else {printf("%d\n", bt->element); // 遍历根结点traversalPreOrder(bt->lchild); // 遍历左子树traversalPreOrder(bt->rchild); // 遍历右子树}}// 中序递归遍历inorder recursive traversalvoid traversalInOrder(BiTreeNode *bt) {if(bt == NULL) {printf("#\n");return;} else {traversalInOrder(bt->lchild); // 遍历左子树printf("%d\n", bt->element); // 遍历根结点traversalInOrder(bt->rchild); // 遍历右子树}}// 后序递归遍历postorder recursive traversalvoid traversalPostOrder(BiTreeNode *bt) {if(bt == NULL) {printf("#\n");return;} else {traversalPostOrder(bt->lchild); // 遍历左子树traversalPostOrder(bt->rchild); // 遍历右子树printf("%d\n", bt->element); // 遍历根结点}}/** 前序输入二叉树结点值(单字符输入,#表示空结点)根据前序输入构造二叉链表表示二叉树* note: 将结点指针作为返回值,直接将结点指针作为参数传入,传值传递了bt的一个备份,开辟新结点时malloc会赋值给备份* note: 二级指针可解决该问题,代码可读性差*/BiTreeNode *createBiTreeFirstOrder() {BiTreeNode *bt;ElementType element;scanf("%d", &element);if(element == -1) {bt = NULL; // 空结点//return; // 递归已有出口return bt, return;会使得空结点值赋值null值失效;} else {bt = (BiTreeNode *)malloc(sizeof(BiTreeNode));if(bt == NULL) {exit(-1);printf("BiTreeNode memory allocate failed.\n");} else {bt->element = element; // 构造根结点bt->lchild = createBiTreeFirstOrder(); // 构造左子树bt->rchild = createBiTreeFirstOrder(); // 构造右子树}}return bt;}//////////////////////////////////////////////////////////int main() {setvbuf(stdout,NULL,_IONBF,0);setvbuf(stderr, NULL, _IONBF, 0);BiTreeNode *bt;bt = createBiTreeFirstOrder(); // 根据前序输入构造二叉树printf("\n前序遍历:\n");traversalPreOrder(bt); // 前序递归遍历二叉树printf("\n中序遍历:\n");traversalInOrder(bt); // 前序递归遍历二叉树printf("\n后序遍历:\n");traversalPostOrder(bt); // 前序递归遍历二叉树return 0;}
所有博文来自个人为知笔记,内容多为读书笔记和理解内容;
浙公网安备 33010602011771号