线索二叉树:前驱和后继需要看遍历出来的序列才能决定是谁。
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
#define MAX_SIZE 100
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
// 二叉链表结构定义
typedef struct BiNode
{
int data; // 存放数据
struct BiNode* lchild, * rchild; // 左右孩子指针
}BiNode, *BiTree; //前面是普通节点类型,也就是一个结构体而已;后面是结构体指针,指向这个节点;
// 三叉链表结构定义
typedef struct TriTNode
{
int data;
struct TriTNode* lchild, * parent, * rchild; // 增加指向双亲结点的指针域
}TriTNode, *TriTree;
// 递归遍历算法:
// 二叉树先序遍历算法:这里递归一层一层深入,找到最后的叶子结点,就一层一层退出,直到根节点那层都执行完才会进入主程序
int PreOrderTraverse(BiTree T) // 等价于 *BiNode T
{
if (T == nullptr)
{
return FALSE;
}
else
{
cout << "节点元素为:" << T->data << endl; // 访问根结点
PreOrderTraverse(T->lchild); // 递归遍历左子树
PreOrderTraverse(T->rchild); // 递归遍历右子树
}
}
// 二叉树中序遍历:
int InOrderTraverse(BiTree T)
{
if (T == nullptr)
{
return FALSE;
}
else
{
PreOrderTraverse(T->lchild); // 递归遍历左子树
cout << "节点元素为:" << T->data << endl; // 访问根结点 - 输出元素
PreOrderTraverse(T->rchild); // 递归遍历右子树
}
}
// 二叉树后序遍历
int PostOrderTraverse(BiTree T)
{
if (T == nullptr)
{
return FALSE;
}
else
{
PreOrderTraverse(T->lchild); // 递归遍历左子树
PreOrderTraverse(T->rchild); // 递归遍历右子树
cout << "节点元素为:" << T->data << endl; // 访问根结点 - 输出元素
}
}
// 非递归算法
// 中序非递归遍历算法:先存储的不能访问,后存储的先访问 ——> 栈
// 基本思想:(1)建立一个栈;(2)根结点进栈,遍历左子树;(3)根结点出栈,输出根节点,访问右子树;
// 用顺序栈存储:栈的定义
typedef struct SqStack
{
int* base; // 栈底指针
int* top; // 栈顶指针 —— 在栈顶元素的上一个位置
int stacksize; // 栈的空间
};
// 初始化
bool InitStack(SqStack& S)
{
S.base = new int[MAX_SIZE]; // 在堆区开辟空间;并将栈底指针指向
if (!S.base) exit(OVERFLOW);
S.top = S.base; // 使栈顶指针等于栈底指针
S.stacksize = MAX_SIZE;
return true;
}
// 判断是否为空
bool IsEmpty(SqStack S)
{
if (S.base == S.top)
{
return true;
}
else
{
return false;
}
}
bool PushStack(SqStack& S, int e)
{
if ((S.top - S.base) == S.stacksize) // 判断栈满
{
cout << "栈满了!!" << endl;
return false;
}
else
{
// 等价于 *(S.top)++ = e;
*(S.top) = e; // 将 S.top 指针指向的位置赋值为 e
(S.top)++;
return true;
}
}
// 顺序栈的出栈:
/*
流程:(1)判断是否栈空,若空了则报错(下溢)
(2)获取栈顶元素 e
(3)栈顶指针减一
*/
bool PopStack(SqStack& S, int& e)
{
if (S.base == S.top) // 等价于 if(IsEmpty(S))
{
cout << "栈已经空了!!" << endl;
return false;
}
--(S.top); // 先将 top 指针下移
e = *(S.top); // 再将 top 指针指向的位置的值赋给 e 带回
return true;
}
int InOrderStackTraverse(BiTree T)
{
BiTree p, q; // 创建两个指针
SqStack S; // 创建一个栈 S
InitStack(S); // 初始化栈
p = T; // 让指针 p 指向 指针 T所指向的地址
// p 访问子树根结点;不为空则继续执行 if(p) 语句,表示将根节点入栈S并移到左子树;若为空执行 else 语句,然后出栈并输出根节点;
while (p || !IsEmpty(S))
{
if (p) {
PushStack(S, p->data); // 将 p 指向结点的元素入栈
q = p;
p = p->lchild; // p 继续去左子树
}
else
{
int e;
PopStack(S, e); // 根节点出栈
cout << "元素值为:" << e << endl;
p = q->rchild; // p 通过指向根节点处的指针 q 去到右子树了;这里永远需要 另一个指针指向 p 的上一个子树的根节点,否则p去不到右子树了
}
}
return OK;
}
// 先序遍历创造二叉树:链表形式
int CreateBiTree(BiTree& T)
{
char ch;
cout << "请输入二叉树结点的数据" << endl;
cin >> ch;
if (ch == '#')
{
T = nullptr;
}
else
{
T = new BiNode; // 创造新结点 - 向计算机内存申请空间给新结点,成功就继续,不成功退出。并且分配的空间给T,即由指针T指向这块空间
if (!T)
{
exit(OVERFLOW);
}
else
{
T->data = ch; // 根结点 或者 每个小树的根节点 - T指针指向的这块空间的结点的值域为 输入值 ch;
CreateBiTree(T->lchild); // 递归,每个树结构走完左子树才能一层层退出,再执行右子树
CreateBiTree(T->rchild); //
}
}
return OK;
}
// 复制二叉树:先序遍历:
// 1. 如果是空树,递归结束 -> 2. 否则申请新结点空间,复制根结点
// 2.1 递归复制左子树 2.2 递归复制右子树
int Copy(BiTree T, BiTree& NewT)
{
if (T == nullptr)
{
NewT = nullptr;
return 0;
}
else
{
NewT = new BiNode; // 向内存申请空间用来开辟一个新结点,并用指针NewT指向新结点所在的空间
NewT->data = T->data; // 通过指针NewT指向的新结点,从而让新结点值域改为 T的值域
Copy(T->lchild, NewT->lchild); // T和NewT都要走向同一个结点处。
Copy(T->rchild, NewT->rchild);
}
return OK;
}
// 计算二叉树深度 - 递归
// 1. 如果是空树,则深度为0 -> 2. 否则,递归计算左子树深度记为m,递归计算右子树深度为n,比较m和n,大者最后再加1
int Depth(BiTree T)
{
if (T == nullptr)
{
cout << "树为空!" << endl;
return 0;
}
else // 这里要理解:记住一层层返回(递归的思想),即最后一个小树计算完把比较的数据传给上级树,一层一层回传
{
int m = Depth(T->lchild);
int n = Depth(T->rchild);
if (m > n)
{
return m + 1;
}
else
{
return n + 1;
}
}
}
// 计算二叉树总个数:
// 1. 如果是空树,则结点总个数为0 -> 2.否则,结点个数就是 左子树结点个数 + 右子树结点个数 + 1
int NodeCount(BiTree T)
{
if (T == nullptr)
{
return 0;
}
else
{
int L = NodeCount(T->lchild);
int R = NodeCount(T->rchild);
return L + R + 1;
//return NodeCount(T->lchild) + NodeCount(T->rchild) + 1;
}
}
// 计算二叉树叶子结点树
// 1. 如果是空树,则叶子结点总个数为0 -> 2.否则,结点个数就是 左子树叶子结点个数 + 右子树叶子结点个数
int LeafNodeCount(BiTree T)
{
if (T == nullptr)
{
return 0;
}
if (T->lchild == nullptr && T->rchild == nullptr)
{
return 1;
}
else
{
return LeafNodeCount(T->lchild) + LeafNodeCount(T->rchild);
}
}
int main()
{
BiTree T;
BiTree NewT;
CreateBiTree(T);
Copy(T, NewT);
cout << "先序遍历二叉树NewT,结点元素为:" << endl;
PreOrderTraverse(NewT);
cout << "中序遍历二叉树NewT,结点元素为:" << endl;
InOrderTraverse(NewT);
cout << "后序遍历二叉树NewT,结点元素为:" << endl;
PostOrderTraverse(NewT);
cout << "二叉树深度为:" << Depth(NewT) << endl;
cout << "二叉树总结点为" << NodeCount(NewT) << endl;
cout << "二叉树叶子节点为:" << LeafNodeCount(NewT) << endl;
return 0;
}