目录
1 . 二叉树的存储结构
-
顺序存储结构
#define MaxSize 100
typedef int ElemType;
typedef struct TreeNode {
ElemType value;//结点中的数据元素
bool isEmpty;//结点是否为空
};
TreeNode t[MaxSize];//定义一个长度为MaxSize的数组 t 来存储各个结点
-
链式存储结构
typedef char ElemType;
typedef struct BiTNode {
ElemType data;//数据域
struct BiTNode *lchild, *rchild; //左 右孩子指针
// struct BiTNode *parent;//父指针
} BiTNode, *BiTree;
2 . 二叉树的遍历(递归算法)
-
先序遍历(递归算法)
//先序遍历
void PreOrder(BiTree T) {
if(T) {
visit(T);
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
-
中序遍历(递归算法)
//中序遍历
void InOrder(BiTree T) {
if(T) {
InOrder(T->lchild);
visit(T);
InOrder(T->rchild);
}
}
-
后序遍历(递归算法)
//后序遍历
void PostOrder(BiTree T) {
if(T) {
PostOrder(T->lchild);
PostOrder(T->rchild);
visit(T);
}
}
-
层次遍历
//二叉树的层次遍历
//算法思想
//1. 初始化一个辅助队列
//2.根结点入队
//3.若队列非空 则队头结点出队 访问该结点 并将其左右孩子插入队尾(如果有的话)
void LevelOrder(BiTree T) {
LinkQueue Q;
InitQueue(Q);//初始化辅助队列
BiTree p;
EnQueue(Q, T);//根结点入队
while(!QueueEmpty(Q)) { //队列不空则循环
DeQueue(Q, p); //队头结点出队
visit(p);//访问出队结点
if(p->lchild) { //左孩子不空则入队
EnQueue(Q, p->lchild);
}
if(p->rchild) { //右孩子不空则入队
EnQueue(Q, p->rchild);
}
}
}
-
计算树的深度
//计算树的深度
int treeDepth(BiTree T) {
if(TreeEmpty(T)) { //空树
return 0;
}
// 后序遍历
int l = treeDepth(T->lchild);//左子树深度
int r = treeDepth(T->rchild);//右子树深度
return l > r ? l + 1 : r + 1;
}
-
完整代码
#include <iostream>
using namespace std;
//二叉树的链式存储
typedef char ElemType;
typedef struct BiTNode {
ElemType data;//数据域
struct BiTNode *lchild, *rchild; //左 右孩子指针
// struct BiTNode *parent;//父指针
} BiTNode, *BiTree;
//链式队列 不带头结点
typedef struct LinkNode { //链式队列结点
BiTNode *data;
struct LinkNode *next;
} LinkNode;
typedef struct { //链式队列
LinkNode *front, *rear; //链式队列的队头和队尾指针
} LinkQueue;
bool InitQueue(LinkQueue &Q);
bool QueueEmpty(LinkQueue Q);
bool EnQueue(LinkQueue &Q, BiTNode *x);
bool DeQueue(LinkQueue &Q, BiTNode *&x);
//二叉树初始化
bool InitBiTree(BiTree &T) {
ElemType value;
cin >> value;
if(value == '#') {
T = NULL;
} else {
T = (BiTNode *)malloc(sizeof(BiTNode));
if(!T) { //空间申请失败
return false;
}
T->data = value;
InitBiTree(T->lchild);
InitBiTree(T->rchild);
}
}
//判断是否为空
bool TreeEmpty(BiTree T) {
if(!T) { //空树
return true;
} else {
return false;
}
}
//二叉树的遍历
//访问一个结点 打印字符
void visit(BiTNode *p) {
cout << p->data << " ";
}
//先序遍历
void PreOrder(BiTree T) {
if(T) {
visit(T);
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
//中序遍历
void InOrder(BiTree T) {
if(T) {
InOrder(T->lchild);
visit(T);
InOrder(T->rchild);
}
}
//后序遍历
void PostOrder(BiTree T) {
if(T) {
PostOrder(T->lchild);
PostOrder(T->rchild);
visit(T);
}
}
//计算树的深度
int treeDepth(BiTree T) {
if(TreeEmpty(T)) { //空树
return 0;
}
// 后序遍历
int l = treeDepth(T->lchild);//左子树深度
int r = treeDepth(T->rchild);//右子树深度
return l > r ? l + 1 : r + 1;
}
//二叉树的层序遍历
//算法思想
//1. 初始化一个辅助队列
//2.根结点入队
//3.若队列非空 则队头结点出队 访问该结点 并将其左右孩子插入队尾(如果有的话)
void LevelOrder(BiTree T) {
LinkQueue Q;
InitQueue(Q);//初始化辅助队列
BiTree p;
EnQueue(Q, T);//根结点入队
while(!QueueEmpty(Q)) { //队列不空则循环
DeQueue(Q, p); //队头结点出队
visit(p);//访问出队结点
if(p->lchild) { //左孩子不空则入队
EnQueue(Q, p->lchild);
}
if(p->rchild) { //右孩子不空则入队
EnQueue(Q, p->rchild);
}
}
}
//队列初始化
bool InitQueue(LinkQueue &Q) {
Q.front = Q.rear = NULL; //初始为空
return true;
}
//判断队列为空
bool QueueEmpty(LinkQueue Q) {
if(Q.front == NULL) {
return true;
} else {
return false;
}
}
//入队
bool EnQueue(LinkQueue &Q, BiTNode *x) {
LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode));
if(!s) { //空间申请失败
return false;
}
//创建新结点插入队尾
s->data = x;
s->next = NULL;
if(QueueEmpty(Q)) {
Q.front = Q.rear = s;
} else {
Q.rear->next = s;
Q.rear = s;
}
return true;
}
//出队
bool DeQueue(LinkQueue &Q, BiTNode *&x) {
if(QueueEmpty(Q)) { //空队
return false;
}
LinkNode *p = Q.front;
x = p->data;
if(Q.rear == p) { //队列最后一个元素
Q.front = Q.rear = NULL;
} else {
Q.front = p->next;
}
free(p);
return true;
}
//由遍历序列构造二叉树
//1.前序+中序
//2.后序+中序
//3.层序+中序
void test() {
BiTree T;
InitBiTree(T);//ABC##DE##F##G##
cout << "treeDepth(T):" << treeDepth(T) << endl;//4
cout << "PreOrder" << endl;
PreOrder(T);//A B C D E F G
cout << endl;
cout << "InOrder" << endl;
InOrder(T);//C B E D F A G
cout << endl;
cout << "PostOrder" << endl;
PostOrder(T);//C E F D B G A
cout << endl;
cout << "LevelOrder" << endl;
LevelOrder(T);//A B G C D E F
cout << endl;
}
int main() {
test();
return 0;
}
代码运行结果:
3 . 二叉树的遍历(非递归算法)
-
先序遍历(非递归算法)
//先序遍历
void PreOrder(BiTree T) {
LiStack S;
InitStack(S);
BiTree p = T;//遍历指针
while(p || !StackEmpty(S)) {
if(p) {//一路向左
visit(p);
Push(S, p);//当前节点入栈
p = p->lchild;//左孩子不为空一直向左走
} else {//出栈,并转向该节点的右孩子
Pop(S, p);//栈顶结点出栈
p = p->rchild;//向右子树走,
}
}
}
-
中序遍历(非递归算法)
//中序遍历
void InOrder(BiTree T) {
LiStack S;
InitStack(S);
BiTree p = T;//遍历指针
while(p || !StackEmpty(S)) {
if(p) {//一路向左
Push(S, p);//当前节点入栈
p = p->lchild;//左孩子不为空一直向左走
} else {//出栈,并转向该节点的右孩子
Pop(S, p);//栈顶结点出栈,访问
visit(p);
p = p->rchild;//向右子树走,
}
}
}
-
后序遍历(非递归算法)
//后序遍历
void PostOrder(BiTree T) {
LiStack S;
InitStack(S);
BiTree p = T;
BiTNode *r = NULL;//辅助指针,指向最近访问的节点
while(p || !StackEmpty(S)) {
if(p) {//走到最左边
Push(S, p);
p = p->lchild;
} else {//走到最右边
GetTop(S, p);//读栈顶元素(非出栈)
if(p->rchild && p->rchild != r) {//若右子树存在且未被访问过
p = p->rchild;//转向右
Push(S, p);//压入栈
p = p->lchild;//再走到最左
} else {//否则弹出栈顶元素并访问
Pop(S, p);
visit(p);
r = p;//记录最近访问过的节点
p = NULL;//节点访问完后重置p指针
}
}
}
}
-
完整代码
#include<iostream>
using namespace std;
typedef char ElemType;
typedef struct BiTNode {
ElemType data;//数据域
struct BiTNode *lchild, *rchild;//左右孩子指针
} BiTNode, *BiTree;
typedef struct LinkNode {
BiTNode *data;
struct LinkNode *next;
} *LiStack, LinkNode;
//链栈初始化
bool InitStack(LiStack &S) {
S = (LiStack)malloc(sizeof(LinkNode));
if (!S) {
return false;
}
S->next = NULL;
return true;
}
//链栈判空
bool StackEmpty(LiStack S) {
if (!S->next) {
return true;
}
return false;
}
//压栈
bool Push(LiStack &S, BiTNode *x) {
LinkNode *p;
p = (LinkNode *)malloc(sizeof(LinkNode));
if (!p) {
return false;
}
p->data = x;
p->next = S->next;
S->next = p;
return true;
}
//弹栈
bool Pop(LiStack &S, BiTNode *&x) {
if (StackEmpty(S)) {
return false;
}
LinkNode *p = S->next;
S->next = p->next;
x = p->data;
free(p);
return true;
}
//获得栈顶元素
bool GetTop(LiStack S, BiTNode *&x) {
if (StackEmpty(S)) {
return false;
}
x = S->next->data;
return true;
}
//初始化二叉树
bool InitBiTree(BiTree &T) {
ElemType value;
cin >> value;
if(value == '#') {
T = NULL;
} else {
T = (BiTNode *)malloc(sizeof(BiTNode));
T->data = value;
InitBiTree(T->lchild);
InitBiTree(T->rchild);
}
}
//打印一个字符
void visit(BiTNode *p) {
cout << p->data << " ";
}
//先序遍历
void PreOrder(BiTree T) {
LiStack S;
InitStack(S);
BiTree p = T;//遍历指针
while(p || !StackEmpty(S)) {
if(p) {//一路向左
visit(p);
Push(S, p);//当前节点入栈
p = p->lchild;//左孩子不为空一直向左走
} else {//出栈,并转向该节点的右孩子
Pop(S, p);//栈顶结点出栈
p = p->rchild;//向右子树走,
}
}
}
//中序遍历
void InOrder(BiTree T) {
LiStack S;
InitStack(S);
BiTree p = T;//遍历指针
while(p || !StackEmpty(S)) {
if(p) {//一路向左
Push(S, p);//当前节点入栈
p = p->lchild;//左孩子不为空一直向左走
} else {//出栈,并转向该节点的右孩子
Pop(S, p);//栈顶结点出栈,访问
visit(p);
p = p->rchild;//向右子树走,
}
}
}
//后序遍历
void PostOrder(BiTree T) {
LiStack S;
InitStack(S);
BiTree p = T;
BiTNode *r = NULL;//辅助指针,指向最近访问的节点
while(p || !StackEmpty(S)) {
if(p) {//走到最左边
Push(S, p);
p = p->lchild;
} else {//走到最右边
GetTop(S, p);//读栈顶元素(非出栈)
if(p->rchild && p->rchild != r) {//若右子树存在且未被访问过
p = p->rchild;//转向右
Push(S, p);//压入栈
p = p->lchild;//再走到最左
} else {//否则弹出栈顶元素并访问
Pop(S, p);
visit(p);
r = p;//记录最近访问过的节点
p = NULL;//节点访问完后重置p指针
}
}
}
}
void test() {
BiTree T;
InitBiTree(T);//ABC##DE##F##G##
cout << "PreOrder" << endl;
PreOrder(T);//A B C D E F G
cout << endl;
cout << "InOrder" << endl;
InOrder(T);//C B E D F A G
cout << endl;
cout << "PostOrder" << endl;
PostOrder(T);//C E F D B G A
cout << endl;
}
int main() {
test();
return 0;
}
代码运行结果:
4 . 线索二叉树
4-1 概述
中序线索二叉树 | 先序线索二叉树 | 后序线索二叉树 | |
找前驱 | √ | √ | |
找后继 | √ | √ |
4-2 中序线索二叉树
#include <iostream>
using namespace std;
typedef char ElemType;
typedef struct ThreadNode { //线索二叉树结点
ElemType data;
struct ThreadNode *lchild, *rchild;
int ltag, rtag; //左右线索标志
// 前驱线索(由左孩子充当) tag = 0 指针指向孩子;tag = 1 指针指向线索
// 后继线索(由右孩子充当) tag = 0 指针指向孩子;tag = 1 指针指向线索
} ThreadNode, *ThreadTree;
//辅助全局变量 pre 用于查找当前访问结点的前驱
ThreadNode *pre = NULL; //指向当前访问结点的前驱结点
//二叉树初始化
bool InitThreadTree(ThreadTree &T) {
ElemType value;
cin >> value;
if(value == '#') {
T = NULL;
} else {
T = (ThreadTree)malloc(sizeof(ThreadNode));
if(!T) { //空间申请失败
return false;
}
T->data = value;
T->ltag = 0;
T->rtag = 0;
InitThreadTree(T->lchild);
InitThreadTree(T->rchild);
}
return true;
}
//二叉树的遍历
void visit(ThreadNode *q) {
if(!q->lchild) { //左子树为空 建立前驱线索
q->lchild = pre;
q->ltag = 1;
}
if(pre != NULL && pre->rchild == NULL) {
pre->rchild = q; //建立前驱结点的后继线索
pre->rtag = 1;
}
pre = q;
}
//中序遍历二叉树 一边遍历一边线索化
void InThread(ThreadTree T) {
if(T) {
InThread(T->lchild);//中序遍历左子树
visit(T);//访问根结点
InThread(T->rchild);//中序遍历右子树
}
}
//中序线索化二叉树 T
void CreateInThread(ThreadTree T) {
pre = NULL;// pre 初始为NULL
if(T) {
InThread(T);
if(pre->rchild == NULL) {
pre->rtag = 1; //处理遍历的最后一个结点
}
}
}
//中序线索二叉树的遍历
//求中序线索二叉树中中序序列下的第一个结点
ThreadNode *FirstNode(ThreadNode *p) {
while (p->ltag == 0) {
p = p->lchild; //最左下结点(不一定是叶节点)
}
return p;
}
//求中序线索二叉树中结点 p 在中序序列下的后继
ThreadNode *NextNode(ThreadNode *p) {
if(p->rtag == 0) {
return FirstNode(p->rchild);
} else {//rtag == 1 直接返回后继线索
return p->rchild;
}
}
//不含头结点的中序线索二叉树的中序遍历算法
void Inorder(ThreadNode *T) {
for (ThreadNode *p = FirstNode(T); p != NULL; p = NextNode(p)) {
cout << p->data << " ";
}
cout << endl;
}
//求中序线索二叉树中中序序列下的最后一个结点
ThreadNode *LastNode(ThreadNode *p) {
//循环找到最右下节点(不一定是叶节点)
while(p->rtag == 0) {
p = p->rchild;
}
return p;
}
//求中序线索二叉树中结点 p 在中序序列下的前驱
ThreadNode *PreNode(ThreadNode *p) {
//左子树中最右下节点
if(p->ltag == 0) {
return LastNode(p->lchild);
}
return p->lchild;// ltag == 1直接返回前驱线索
}
//不含头结点的中序线索二叉树的 逆序 中序遍历算法
void RevInorder(ThreadTree T) {
for(ThreadNode *p = LastNode(T); p != NULL; p = PreNode(p)) {
cout << p->data << " ";
}
cout << endl;
}
void test() {
ThreadTree T;
InitThreadTree(T);//ABC##DE##F##G##
CreateInThread(T);
cout << "InOrder" << endl;
Inorder(T);//C B E D F A G
cout << "RevInorder" << endl;
RevInorder(T);//G A F D E B C
}
int main() {
test();
return 0;
}
代码运行结结果:
4-3 先序线索二叉树
#include <iostream>
using namespace std;
typedef char ElemType;
typedef struct ThreadNode { //线索二叉树结点
ElemType data;
struct ThreadNode *lchild, *rchild;
int ltag, rtag; //左右线索标志
// 前驱线索(由左孩子充当) tag = 0 指针指向孩子;tag = 1 指针指向线索
// 后继线索(由右孩子充当) tag = 0 指针指向孩子;tag = 1 指针指向线索
} ThreadNode, *ThreadTree;
//辅助全局变量 pre 用于查找当前访问结点的前驱
ThreadNode *pre = NULL; //指向当前访问结点的前驱结点
//二叉树初始化
bool InitThreadTree(ThreadTree &T) {
ElemType value;
cin >> value;
if(value == '#') {
T = NULL;
} else {
T = (ThreadTree)malloc(sizeof(ThreadNode));
if(!T) { //空间申请失败
return false;
}
T->data = value;
T->ltag = 0;
T->rtag = 0;
InitThreadTree(T->lchild);
InitThreadTree(T->rchild);
}
return true;
}
//二叉树的遍历
void visit(ThreadNode *q) {
if(!q->lchild) { //左子树为空 建立前驱线索
q->lchild = pre;
q->ltag = 1;
}
if(pre != NULL && pre->rchild == NULL) {
pre->rchild = q; //建立前驱结点的后继线索
pre->rtag = 1;
}
pre = q;
}
//先序遍历二叉树 一边遍历一边线索化
void PreThread(ThreadTree T) {
if(T) {
visit(T);//访问根结点
if(T->ltag != 1) { //lchild 不是前驱结点
PreThread(T->lchild);
}
if(T->rtag != 1) { //rchild 不是后继结点 回溯回来会造成死循环
PreThread(T->rchild);
}
}
}
//先序线索化二叉树 T
void CreatePreThread(ThreadTree T) {
pre = NULL;// pre 初始为NULL
if(T) {
PreThread(T);//先序线索化二叉树
if(pre->rchild == NULL) {
pre->rtag = 1; //处理遍历的最后一个结点
}
}
}
//先序线索二叉树的遍历
//求先序线索二叉树中结点 p 在先序序列下的后继
ThreadNode *NextNode(ThreadNode *p) {
if(p->rtag == 0) {
if(p->lchild != NULL) {
return p->lchild;
}
return p->rchild;
} else { //rtag == 1 直接返回后继线索
return p->rchild;
}
}
//不含头结点的先序线索二叉树的先序遍历算法
void Preorder(ThreadNode *T) {
for (ThreadNode *p = T; p != NULL; p = NextNode(p)) {
cout << p->data << " ";
}
cout << endl;
}
void test() {
ThreadTree T;
InitThreadTree(T);//ABC##DE##F##G##
CreatePreThread(T);
cout << "Preorder" << endl;
Preorder(T);//A B C D E F G
}
int main() {
test();
return 0;
}
代码运行结结果:
4-4 后序线索二叉树
#include <iostream>
using namespace std;
typedef char ElemType;
typedef struct ThreadNode { //线索二叉树结点
ElemType data;
struct ThreadNode *lchild, *rchild;
int ltag, rtag; //左右线索标志
// 前驱线索(由左孩子充当) tag = 0 指针指向孩子;tag = 1 指针指向线索
// 后继线索(由右孩子充当) tag = 0 指针指向孩子;tag = 1 指针指向线索
} ThreadNode, *ThreadTree;
//辅助全局变量 pre 用于查找当前访问结点的前驱
ThreadNode *pre = NULL; //指向当前访问结点的前驱结点
//二叉树初始化
bool InitThreadTree(ThreadTree &T) {
ElemType value;
cin >> value;
if(value == '#') {
T = NULL;
} else {
T = (ThreadTree)malloc(sizeof(ThreadNode));
if(!T) { //空间申请失败
return false;
}
T->data = value;
T->ltag = 0;
T->rtag = 0;
InitThreadTree(T->lchild);
InitThreadTree(T->rchild);
}
return true;
}
//二叉树的遍历
void visit(ThreadNode *q) {
if(!q->lchild) { //左子树为空 建立前驱线索
q->lchild = pre;
q->ltag = 1;
}
if(pre != NULL && pre->rchild == NULL) {
pre->rchild = q; //建立前驱结点的后继线索
pre->rtag = 1;
}
pre = q;
}
//后序遍历二叉树 一边遍历一边线索化
void PostThread(ThreadTree T) {
if(T) {
PostThread(T->lchild);//lchild 不是前驱结点
PostThread(T->rchild);//rchild 不是后继结点
visit(T);//访问根结点
}
}
//后序线索化二叉树 T
void CreatePostThread(ThreadTree T) {
pre = NULL;// pre 初始为NULL
if(T) {
PostThread(T);//后序线索化二叉树
if(pre->rchild == NULL) {
pre->rtag = 1; //处理遍历的最后一个结点
}
}
}
//后序线索二叉树的遍历
//求后序线索二叉树中结点 p 在后序序列下的前驱
ThreadNode *PreNode(ThreadNode *p) {
if(p->ltag == 0) {
if(p->rchild != NULL) {
return p->rchild;
}
return p->lchild;
} else { //ltag == 1 直接返回后继线索
return p->lchild;
}
}
//不含头结点的后序线索二叉树的 逆向 后序遍历算法
void RevPostorder(ThreadNode *T) {
for (ThreadNode *p = T; p != NULL; p = PreNode(p)) {
cout << p->data << " ";
}
cout << endl;
}
void test() {
ThreadTree T;
InitThreadTree(T);//ABC##DE##F##G##
CreatePostThread(T);
//Preorder//C E F D B G A
cout << "RevPostOrder" << endl;
RevPostorder(T);//A G B D F E C
}
int main() {
test();
return 0;
}
代码运行结结果: