一、二叉树的定义
二叉树(Binary Tree)是n(n>= 0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根节点和两颗互不相交的、分别称为根节点的左子树和右子树的二叉树组成。
/*二叉树的二叉链表存储表示*/
typedef struct BiTNode
{
int data;
struct BiTNode * left, * right;
BiTNode(int da = 0) : data(da), left(NULL), right(NULL) { };
}BiTNode, *BiTree;
二、二叉树的性质
性质1 在二叉树的第i层上至多有2^(i-1)个结点(i >= 1)。
性质2 深度为k的二叉树至多有2^k - 1个结点(k >= 1)。
性质3 对任何一颗二叉树T,如果其终端结点数为n0, 度为2的结点数为n2,则n0 = n2 + 1。
性质4 具有n个结点的完全二叉树的深度为
性质5 对一颗有n个结点的完全二叉树的结点按层序编号(从第一层到第层,每层从左到右),则对任一结点i(1 <= i <= n),有
(1) 如果i=1,则结点i是二叉树的根,无双亲。如果i>=1,其双亲结点为
(2) 如果2i>n,则结点i无左孩子;否则其左孩子是结点2i
(3) 如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1
三、特殊二叉树
满二叉树: 一颗深度为k且有2^k - 1个结点的二叉树称为满二叉树
完全二叉树: 深度为k,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应时,称为完全二叉树。
四、二叉树的遍历
(1) 先序遍历
先序遍历二叉树的操作定义:若二叉树为空,则空操作;否则 (1)访问根结点; (2)先序遍历左子树;(3)先序遍历右子树。
/*先序遍历的递归实现*/
void PreOrderTraverse(BiTree T)
{
if (T == NULL) return;
cout << T->data << " "; // 访问根节点
PreOrderTraverse(T->left); // 遍历左子树
PreOrderTraverse(T->right); // 遍历右子树
}
/*******************************************************
* 二叉树先序遍历的非递归实现
* 具体过程:
1. 首先申请一个新的栈,记为s
2. 然后将二叉树压入s
3. 如果s不为空,则弹出栈顶元素并打印根节点;
如果右子树不为空,则将右子树入栈;
如果左子树不为空,则将左子树入栈。
********************************************************/
void NRPreOrderTraverse(BiTree T)
{
if (T == NULL) return;
stack<BiTree> s; // 创建一个栈
BiTree p = NULL; // 用来存放从栈中弹出的二叉树
s.push(T);
while (!s.empty()) {
p = s.top(); // 返回栈顶元素
cout << p->data << " "; // 打印当前树的根节点
s.pop();
if (p->right)
s.push(p->right); // 右子树入栈
if (p->left)
s.push(p->left); // 左子树入栈
}
}
/*先序遍历的非递归实现*/
void NRPreOrderTraverse(BiTree T)
{
stack<BiTree> s;
BiTree p = T;
while (p != NULL || !s.empty()) {
while (p != NULL) {
cout << p->data << " ";
s.push(p);
p = p->left;
}
if (!s.empty()) {
p = s.top();
s.pop();
p = p->right;
}
}
}
(2) 中序遍历
中序遍历二叉树的操作定义:若二叉树为空,则空操作;否则 (1)中序遍历左子树; (2)访问根结点;(3)中序遍历右子树。
/*中序遍历的递归实现*/
void InOrderTraverse(BiTree T)
{
if (T == NULL) return;
PreOrderTraverse(T->left); // 遍历左子树
cout << T->data << " "; // 访问根节点
PreOrderTraverse(T->right); // 遍历右子树
}
/*******************************************************
* 二叉树中序遍历的非递归实现
* 具体过程:
1. 申请一个栈s,申请一个BiTree变量p并初始化为T
2. 先把p压入栈s中,并依次把整棵树的左边界压入
栈中,即不断令p=p->left,然后重复步骤2
3. 不断重复步骤2直到p为空,此时弹出栈顶元素,
令p等于栈顶元素值,打印根节点的值,然后令
p=p->right,然后重复步骤2
4. 当s为空并且p为空时,整个过程结束
********************************************************/
void NRInOrderTraverse(BiTree T)
{
stack<BiTree> s;
BiTree p = T;
while (p != NULL || !s.empty()) {
while (p != NULL) {
s.push(p);
p = p->left;
}
if (!s.empty()) {
p = s.top();
cout << p->data << " ";
s.pop();
p = p->right;
}
}
}
(3) 后序遍历
后序遍历二叉树的操作定义:若二叉树为空,则空操作;否则 (1)后序遍历左子树; (2)后序遍历右子树;(3)访问根结点
/*后序遍历的递归实现*/
void PostOrderTraverse(BiTree T)
{
if (T == NULL) return;
PreOrderTraverse(T->left); // 遍历左子树
PreOrderTraverse(T->right); // 遍历右子树
cout << T->data << " "; // 访问根节点
}
/*******************************************************
* 二叉树后序遍历的非递归实现
* 具体过程:
1. 申请两个栈s1,s2。s1初始化为T。
2. 从s1中弹出栈顶元素,记为p,然后将p的左子树压入s1中,
然后将p的右子树压入s1中。
3. 将p压入栈s2中
4. 重复步骤2、步骤3。直到s1为空,过程停止
5. 从s2中依次弹出并打印,打印的顺序就是后序遍历的顺序
********************************************************/
void NRPostOrderTraverse(BiTree T)
{
if (T == NULL) return;
stack<BiTree> s1, s2; // 创建两个栈
s1.push(T);
BiTree p = NULL; // 用来存放从栈中弹出的二叉树
while (!s1.empty()) {
p = s1.top();
s1.pop();
if (p->left) s1.push(p->left);
if (p->right) s1.push(p->right);
s2.push(p);
}
while (!s2.empty()) {
cout << s2.top()->data << " ";
s2.pop();
}
}
/*后序遍历的非递归实现*/
void NRPostOrderTraverse(BiTree T) {
BiTree p = T;
BiTree r = NULL;
stack<BiTree> s;
while (p != NULL || !s.empty()) {
while (p != NULL) {
s.push(p);
p = p->left;
}
if (!s.empty()) {
p = s.top();
if (p->right != NULL && p->right != r)
p = p->right;
else {
s.pop();
cout << p->data << " ";
r = p;
p = NULL;
}
}
}
}
/*二叉树后序遍历的非递归实现*/
void NRPostOrderTraverse(BiTree T)
{
if (T == NULL) return;
stack<BiTree> s; // 创建栈
s.push(T);
BiTree p = NULL;
BiTree r = NULL; // 记录最近一次弹出的元素
while (!s.empty()) {
p = s.top();
if (p->left != NULL && r != p->left && r != p->right)
s.push(p->left);
else if (p->right != NULL && r != p->right)
s.push(p->right);
else {
s.pop();
cout << p->data << " ";
r = p;
}
}
}
(4) 层序遍历
从上到下,从左到右依次打印二叉树每个结点中存储的数据
/*二叉树的层序遍历*/
void PrintFromTopToBottom(BiTree T)
{
if (T == NULL) return;
deque<BiTree> p;
p.push_back(T);
while (p.size()) {
BiTree pNode = p.front();
p.pop_front();
cout << pNode->data << " ";
if (pNode->left)
p.push_back(pNode->left);
if (pNode->right)
p.push_back(pNode->right);
}
}