1、二叉树的顺序存储
#include <iostream>
//二叉树的顺序存储
typedef int ElemType;
#define MAXSIZE 100
typedef ElemType BiTree[MAXSIZE];//声明1种数据类型 长度为100的数组
int main()
{
BiTree bt;//实例化出1个二叉数组
/*
用空集修补当前二叉树成完全二叉树
(满二叉树(结点数 = 2^(k) - 1)从最后1个结点开始连续删除任意个结点)
所有的结点按满二叉树编号规则(不同层:从上到下(同层:从左到右))进行编号
*/
//把二叉树的N个结点存放进数组bt[0]---bt[N-1 + 修补的数量]
return 0;
}
2、二叉树的链式存储
#include <iostream>
//二叉树的链式存储
typedef int TElemType;
typedef struct BiNode
{
TElemType data;//要存储的数据
BiNode * lchild;//当前结点的左孩子结点
BiNode * rchild;//当前结点的右孩子结点
} *BiTree;
int main()
{
/*
BiNode * n1 = new BiNode;
......
BiNode * n9 = new BiNode;
n1->data = ...;
n1->lchild = ...;
n1->rchild = ...;
......
n9->data = ...;
n9->lchild = nullptr;
n9->rchild = nullptr;
*/
BiTree bt;//实例化出1个头指针(二叉链表)--指向首元结点
//bt->lchild = bt->rchild = n1;
return 0;
}
3、先序、中序、后序递归遍历二叉树
#include <iostream>
//二叉树的链式存储(二叉链表)
typedef char TElemType;
typedef struct BiNode
{
TElemType data;//要存储的数据
BiNode * lchild;//i结点的左孩子
BiNode * rchild;//i结点的右孩子
} *BiTree;
//先序遍历--得到二叉树的所有结点的唯一序列
/*
判断二叉树空?不空?
1、访问根节点
2、先序遍历左子树 PreOrderTraverse(T->lchild);
3、先序遍历右子树 PreOrderTraverse(T->rchild);
返回上一层 == 直接return
*/
int PreOrderTraverse(BiTree T);
//中序遍历--得到二叉树的所有结点的唯一序列
/*
判断二叉树空?不空?
1、中序遍历左子树 InOrderTraverse(T->lchild);
2、访问根节点
3、中序遍历右子树 InOrderTraverse(T->rchild);
返回上一层 == 直接return
*/
int InOrderTraverse(BiTree T);
//后序遍历--得到二叉树的所有结点的唯一序列
/*
判断二叉树空?不空?
1、后序遍历左子树 PostOrderTraverse(T->lchild);
2、后序遍历右子树 PostOrderTraverse(T->rchild);
3、访问根节点
返回上一层 == 直接return
*/
int PostOrderTraverse(BiTree T);
int main()
{
/*
二叉树
A
/ \
B C
\
D
*/
BiNode * n1 = new BiNode;
BiNode * n2 = new BiNode;
BiNode * n3 = new BiNode;
BiNode * n4 = new BiNode;
n1->data = 'A';
n1->lchild = n2;
n1->rchild = n3;
n2->data = 'B';
n2->lchild = nullptr;
n2->rchild = n4;
n3->data = 'C';
n3->lchild = n3->rchild = nullptr;
n4->data = 'D';
n4->lchild = n4->rchild = nullptr;
//实例化出1棵二叉树(1个头指针)
BiTree bt = new BiNode;//栈指针不能指向堆区内存
bt->data = ';';
bt->lchild = n1;//指向首元结点
bt->rchild = nullptr;
//测试先序遍历
std::cout << "----test----\n";
PreOrderTraverse(bt);
std::cout << "\n----test end----\n";
return 0;
}
//先序遍历
int PreOrderTraverse(BiTree T)
{
if (!T)
return 0;//二叉树为空--返回上一层--直接return(结束当前PreOrderTraverse(?))//递归函数的出口条件
else
{
if (T->data != ';')
std::cout << T->data << '\t';//访问根结点(输出数据值)
PreOrderTraverse(T->lchild);//先序遍历当前结点的左子树
PreOrderTraverse(T->rchild);//先序遍历当前结点的右子树
}
}
//中序遍历
int InOrderTraverse(BiTree T)
{
if (!T)
return 0;//二叉树为空--返回上一层--直接return(结束当前PreOrderTraverse(?))//递归函数的出口条件
else
{
InOrderTraverse(T->lchild);//中序遍历当前结点的左子树
if (T->data != ';')
std::cout << T->data << '\t';//访问根结点(输出数据值)
InOrderTraverse(T->rchild);//中序遍历当前结点的右子树
}
}
//后序遍历
int PostOrderTraverse(BiTree T)
{
if (!T)
return 0;//二叉树为空--返回上一层--直接return(结束当前PreOrderTraverse(?))//递归函数的出口条件
else
{
PostOrderTraverse(T->lchild);//后序遍历当前结点的左子树
PostOrderTraverse(T->rchild);//后序遍历当前结点的右子树
if (T->data != ';')
std::cout << T->data << '\t';//访问根结点(输出数据值)
}
}
4、中序遍历非递归实现
#include <iostream>
//二叉树链式存储
typedef char TElemType;
typedef struct BiNode
{
TElemType tdata;//要存储的数据
BiNode * lchild;//当前结点的左孩子
BiNode * rchild;//当前结点的右孩子
} *BiTree;
//栈--存储的数据元素为指向二叉树结点的指针
#define MAXSIZE 100
typedef struct
{
//BiTree sdata[MAXSIZE];
BiTree * base;//栈底指针//可以同时用来开辟动态数组//不会移动的
BiTree * top;//栈顶指针//指向当前最末元素的下一个位置
} SStack;
//栈为空
int SStackEmpty(SStack S);
//栈为满
int SStackFull(SStack S);
//入栈
int PushSStack(SStack & S, BiTree t);
//出栈
int PopSStack(SStack & S, BiTree & t);
//初始化栈
int InitSStack(SStack & S);
//中序非递归遍历(while循环 + 自定义栈)
int InOrderTraverse(BiTree T);
int main()
{
/*
实例化出1棵二叉树(链式存储)
A
/ \
B C
\
D
*/
//堆区开辟4个结点
BiNode * n1 = new BiNode;
BiNode * n2 = new BiNode;
BiNode * n3 = new BiNode;
BiNode * n4 = new BiNode;
n1->tdata = 'A';
n1->lchild = n2;
n1->rchild = n3;
n2->tdata = 'B';
n2->lchild = nullptr;
n2->rchild = n4;
n3->tdata = 'C';
n3->lchild = n3->rchild = nullptr;
n4->tdata = 'D';
n4->lchild = n4->rchild = nullptr;
//实例化出1个二叉树(头指针)
BiTree T = new BiNode;
T->tdata = ';';
T->lchild = n1;//串起来
T->rchild = nullptr;
std::cout << "二叉树:\n A\n \/ \\ \n B C\n \\\n D" << std::endl;
//测试中序遍历(非递归)算法
std::cout << "****begin test****\n结点序列为:\n";
InOrderTraverse(T);
std::cout << "\n****end test****\n";
return 0;
}
//栈为空
int SStackEmpty(SStack S)
{
if (S.top == S.base)
return 1;
else
return 0;
}
//栈为满
int SStackFull(SStack S)
{
if ((S.top - S.base) == MAXSIZE * sizeof(BiTree))
return 1;
else
return 0;
}
//入栈
int PushSStack(SStack & S, BiTree t)
{
if (!SStackFull(S))
{
*S.top = t;
S.top++;
return 1;
}
else
return 0;
}
//出栈
int PopSStack(SStack & S, BiTree & t)
{
if (!SStackEmpty(S))
{
t = *(S.top - 1);
S.top--;
return 1;
}
else
return 0;
}
//初始化栈
int InitSStack(SStack & S)
{
S.base = new BiTree[MAXSIZE];
S.top = S.base;
return 1;
}
/*
A
/ \
B C
/\ \
中序遍历非递归算法
1、创建栈
2、二叉树不空?---根结点入栈, 中序遍历左子树(利用循环2、3、)
3、遍历完左子树---根结点出栈,中序遍历右子树(利用循环2、3、),出循环结束
*/
int InOrderTraverse(BiTree T)
{
SStack S;
InitSStack(S);//实例化1个栈并初始化为空栈
BiTree p = T;//用来遍历结点
BiTree q = nullptr;//用来记录栈存放的根结点(出栈)
while (p || !SStackEmpty(S))//只有p为空(二叉树为空-结点遍历完成) && 栈也为空--结束循环
{
/*
p不为空---遍历二叉树结点
p为空---当前二叉树遍历结束
Q: 中序(左-根-右) 遍历完左子树-p为空, 怎么访问根结点和遍历右子树?
A:栈保存了当前的根结点,出栈即可
*/
if (p) //p不为空,遍历当前二叉树
{
//1、记录根结点(根节点入栈)
PushSStack(S, p);
//2、遍历当前根结点的左子树
p = p->lchild;
}
else //p为空, 左子树完成遍历
{
//回到根节点---开始遍历右子树
PopSStack(S, q);//q为当前左子树的根结点
if (q->tdata != ';')
std::cout << q->tdata << '\t';
//开始遍历右子树
p = q->rchild;
}
}
return 1;
}
5、层次遍历
#include <iostream>
typedef char TElemType;
//二叉树-链式存储
typedef struct BiNode
{
TElemType tdata;
BiNode * lchild;
BiNode * rchild;
} *BiTree;
//单向队列--浪费内存
#define MAXSIZE 100
typedef struct
{
BiTree data[MAXSIZE];//静态数组
int head;//头指针(队头元素)
int rear;//尾指针(队尾元素的下一个位置)
} Queue;
//初始化为空队列
void InitQueue(Queue &Q);
//队空?
int EmptyQueue(Queue Q);
//队满
int FullQueue(Queue Q);
//入队
int EnQueue(Queue & Q, BiTree bt);
//出队
int DelQueue(Queue & Q, BiTree & bt);
//层次遍历算法
int LevelTraverse(BiTree T);
int main()
{
/*
实例化出1棵二叉树(链式存储)
A
/ \
B C
\
D
*/
//堆区开辟4个结点
BiNode * n1 = new BiNode;
BiNode * n2 = new BiNode;
BiNode * n3 = new BiNode;
BiNode * n4 = new BiNode;
n1->tdata = 'A';
n1->lchild = n2;
n1->rchild = n3;
n2->tdata = 'B';
n2->lchild = nullptr;
n2->rchild = n4;
n3->tdata = 'C';
n3->lchild = n3->rchild = nullptr;
n4->tdata = 'D';
n4->lchild = n4->rchild = nullptr;
//实例化出1个二叉树(头指针)
BiTree T = new BiNode;
T->tdata = ';';
T->lchild = n1;//串起来
T->rchild = nullptr;
std::cout << "二叉树:\n A\n \/ \\ \n B C\n \\\n D" << std::endl;
//测试层次遍历算法
std::cout << "****begin test****\n结点序列为:\n";
LevelTraverse(T);
std::cout << "\n****end test****\n";
return 0;
}
//初始化为空队列
void InitQueue(Queue &Q)
{
Q.head = Q.rear = 0;
}
//队空?
int EmptyQueue(Queue Q)
{
if (Q.head == Q.rear)
return 1;
else
return 0;
}
//队满
int FullQueue(Queue Q)
{
if (Q.rear == MAXSIZE)
return 1;
else
return 0;
}
//入队
int EnQueue(Queue & Q, BiTree bt)
{
if (!FullQueue(Q))
{
Q.data[Q.rear++] = bt;
return 1;
}
else
return 0;
}
//出队
int DelQueue(Queue & Q, BiTree & bt)
{
if (!EmptyQueue(Q))
{
bt = Q.data[Q.head++];
return 1;
}
else
return 0;
}
//层次遍历算法
int LevelTraverse(BiTree T)
{
/*
A
/ \
B C
\
D
1、初始化1个队列
2、根节点入队
3、循环 (队列非空?) 队头元素出队 + 队头元素的左右孩子结点入队
*/
BiTree p = nullptr;
Queue Q;
InitQueue(Q);
EnQueue(Q, T);
while (!EmptyQueue(Q))//队列为空(所有结点均遍历)--结束循环
{
//队头元素出队(访问根节点)
DelQueue(Q, p);
if (p->tdata != ';')
std::cout << p->tdata << '\t';
if (p->lchild)
EnQueue(Q, p->lchild);
if (p->rchild)
EnQueue(Q, p->rchild);
}
return 1;
}
6、 先序+中序的序列生成二叉树
#include <iostream>
//二叉树链式存储
typedef char TElemType;
typedef struct BiNode
{
TElemType data;
BiNode * lchild;
BiNode * rchild;
} *BiTree;
//由已知序列生成二叉树
int CreatBiTree(BiTree & T);
//先序遍历
int PreOrderTraverse(BiTree T);
int main()
{
//测试生成二叉树
std::cout << "修改的先序遍历序列:ABC##DE##G##F###\n";
BiTree T = nullptr;//实例化1个空二叉树
CreatBiTree(T);
//遍历该生成的二叉树
std::cout << "测试先序遍历序列:\n";
PreOrderTraverse(T);
return 0;
}
//由已知序列生成二叉树
/*
人为规定:i结点均有2个孩子结点(空结点除外)
#代替补充的空结点
*/
int CreatBiTree(BiTree & T)
{
TElemType e;
std::cout << "Enter a word:\t";
std::cin >> e;
if (e != '#')
{
//在堆区开辟1个根节点
T = new BiNode;
T->data = e;
//生成该根结点的左子树
CreatBiTree(T->lchild);
//生成该根结点的右子树
CreatBiTree(T->rchild);
}
else //递归函数出口条件
{
/*
输入的字符为# 等价 树为空
A
/ \
空 B
/ \
C 空
/ \
空 空
*/
T = nullptr;//树为空
return 1;
}
}
//先序遍历--得到二叉树的所有结点的唯一序列
/*
判断二叉树空?不空?
1、访问根节点
2、先序遍历左子树 PreOrderTraverse(T->lchild);
3、先序遍历右子树 PreOrderTraverse(T->rchild);
返回上一层 == 直接return
*/
int PreOrderTraverse(BiTree T)
{
if (!T)
return 0;//二叉树为空--返回上一层--直接return(结束当前PreOrderTraverse(?))//递归函数的出口条件
else
{
if (T->data != ';')
std::cout << T->data << '\t';//访问根结点(输出数据值)
PreOrderTraverse(T->lchild);//先序遍历当前结点的左子树
PreOrderTraverse(T->rchild);//先序遍历当前结点的右子树
}
}
7、二叉树遍历算法的应用-复制二叉树
#include <iostream>
//二叉树
typedef char TElemType;
typedef struct BiNode
{
TElemType data;
BiNode * lchild;
BiNode * rchild;
} *BiTree;
//复制二叉树
int CopyBiTree(BiTree T, BiTree & Tnew);
//先序遍历--得到二叉树的所有结点的唯一序列
int PreOrderTraverse(BiTree T);
int main()
{
/*
二叉树
A
/ \
B C
\
D
*/
BiNode * n1 = new BiNode;
BiNode * n2 = new BiNode;
BiNode * n3 = new BiNode;
BiNode * n4 = new BiNode;
n1->data = 'A';
n1->lchild = n2;
n1->rchild = n3;
n2->data = 'B';
n2->lchild = nullptr;
n2->rchild = n4;
n3->data = 'C';
n3->lchild = n3->rchild = nullptr;
n4->data = 'D';
n4->lchild = n4->rchild = nullptr;
//实例化出1棵二叉树(1个头指针)
BiTree bt = new BiNode;//栈指针不能指向堆区内存
bt->data = ';';
bt->lchild = n1;//指向首元结点
bt->rchild = nullptr;
//测试复制二叉树算法
BiTree Tnew = nullptr;
std::cout << "----test----\n";
CopyBiTree(bt, Tnew);
PreOrderTraverse(Tnew);
std::cout << "\n----test end----\n";
return 0;
}
//复制二叉树
int CopyBiTree(BiTree T, BiTree & Tnew)
{
/*
判断二叉树空---直接return
不空---1、在堆区新建根节点(值复制)
2、复制左子树
3、复制右子树
*/
if (T)
{
Tnew = new BiNode;
Tnew->data = T->data;//新建根结点
CopyBiTree(T->lchild, Tnew->lchild);//复制左子树
CopyBiTree(T->rchild, Tnew->rchild);//复制右子树
}
else
{
Tnew = T;//复制1棵空树
return 1;
}
}
//先序遍历
/*
判断二叉树空?不空?
1、访问根节点
2、先序遍历左子树 PreOrderTraverse(T->lchild);
3、先序遍历右子树 PreOrderTraverse(T->rchild);
返回上一层 == 直接return
*/
int PreOrderTraverse(BiTree T)
{
if (!T)
return 0;//二叉树为空--返回上一层--直接return(结束当前PreOrderTraverse(?))//递归函数的出口条件
else
{
if (T->data != ';')
std::cout << T->data << '\t';//访问根结点(输出数据值)
PreOrderTraverse(T->lchild);//先序遍历当前结点的左子树
PreOrderTraverse(T->rchild);//先序遍历当前结点的右子树
}
}
8、遍历算法的应用-计算二叉树的深度、结点数、叶子数
#include <iostream>
//二叉树
typedef char TElemType;
typedef struct BiNode
{
TElemType data;
BiNode * lchild;
BiNode * rchild;
} *BiTree;
//计算二叉树的深度
int DepthBiTree(BiTree T);
//计算二叉树结点总数
int NumBiTree(BiTree T);
//计算叶子节点数
int LeafBiTree(BiTree T);
int main()
{
/*
二叉树
A
/ \
B C
\
D
*/
BiNode * n1 = new BiNode;
BiNode * n2 = new BiNode;
BiNode * n3 = new BiNode;
BiNode * n4 = new BiNode;
n1->data = 'A';
n1->lchild = n2;
n1->rchild = n3;
n2->data = 'B';
n2->lchild = nullptr;
n2->rchild = n4;
n3->data = 'C';
n3->lchild = n3->rchild = nullptr;
n4->data = 'D';
n4->lchild = n4->rchild = nullptr;
//实例化出1棵二叉树(1个头指针)
BiTree bt = new BiNode;//栈指针不能指向堆区内存
bt->data = ';';
bt->lchild = n1;//指向首元结点
bt->rchild = nullptr;
//测试计算二叉树的深度算法
std::cout << "----test----\n";
std::cout << DepthBiTree(bt->lchild);
std::cout << "\n----test end----\n";
//测试计算二叉树的结点数算法
std::cout << "----test----\n";
std::cout << NumBiTree(bt->lchild);
std::cout << "\n----test end----\n";
//测试计算二叉树的叶子结点数算法
std::cout << "----test----\n";
std::cout << LeafBiTree(bt->lchild);
std::cout << "\n----test end----\n";
return 0;
}
//计算二叉树的深度
int DepthBiTree(BiTree T)
{
/*
判断二叉树空?不空?
return 0
计算左子树深度
计算右子树深度
取两者最大值 + 1并返回
*/
if (T)
{
int m = DepthBiTree(T->lchild); //计算左子树深度
int n = DepthBiTree(T->rchild);//计算右子树深度
return ((m < n) ? n + 1 : m + 1);//返给上一层递归调用
}
else
return 0;
}
//计算二叉树结点总数
int NumBiTree(BiTree T)
{
/*
判断二叉树空?不空?
return 0
计算左子树结点数
计算右子树结点数
取两者和 + 1并返回
*/
if (T)
{
int m = NumBiTree(T->lchild); //计算左子树结点数
int n = NumBiTree(T->rchild); //计算右子树结点数
return m + n + 1; //取两者和 + 1并返回
}
else
return 0;
}
//计算叶子节点数
int LeafBiTree(BiTree T)
{
/*
判断二叉树空?不空?
return 0
计算左子树叶子结点数
计算右子树叶子结点数
取两者和并返回
*/
if (!T)
return 0;
else
{
int m = LeafBiTree(T->lchild);
int n = LeafBiTree(T->rchild);
if (m + n > 0)
return m + n;
else
return 1;//叶子节点(左为空,右为空)
}
}
9、普通树的存储结构
#include <iostream>
typedef int TElemType;
/*
树的存储结构
顺序存储
链式存储
R
/ | \
A B C
/ \ |
D E F
/ | \
G H K
*/
/*
树的顺序存储
双亲表示法
孩子链表表示法
树的链式存储
孩子兄弟表示法
*/
/*
双亲表示法(顺序存储)
i结点
要保存的数据
双亲结点的位置
*/
typedef struct DoubleParentNode
{
TElemType data;
int parent;
} DoubleParentNode;
#define MAXSIZE 100
typedef struct DoubleParentTree
{
DoubleParentNode array[MAXSIZE];
int len;//当前有多少个元素
}DoubleParentTree;
/*
孩子链表法(顺序存储)
i结点
要保存的数据
i结点所有孩子结点位置构成的链表
*/
//链表
typedef struct LinkNode
{
int index;//i结点所在的几号位置
LinkNode * next;//下一个链结点的位置
} *LinkList;
//i结点
typedef struct ChildLinkNode
{
TElemType data;
LinkList L;
} ChildLinkNode;
//树--孩子链表法
#define MAXSIZE1 100
typedef struct ChildLinkTree
{
ChildLinkNode array[MAXSIZE1];
int len;//当前几个元素
};
/*
孩子兄弟表示法(链式存储)
i结点
要保存的数据
第一个孩子结点的位置
下一个兄弟结点的位置
*/
typedef struct ChildBrotherNode
{
TElemType data;
ChildBrotherNode * firstchild;
ChildBrotherNode * nextbrother;
} ChildBrotherTree;
int main()
{
return 0;
}
10、哈夫曼树
#include <iostream>
/*
已知n个叶子节点的权, 构造这n个结点的哈夫曼树
1、n个结点构成n棵二叉树(只有根结点) T1 ... Tn 森林F = {T1, ..., Tn};
2、从森林F中取出2棵权最小树作为左右子树, 构造新树.
3、从森林F中删除这2棵树, 添加新树.
重复2、3、(n - 1次产生n - 1棵新树)直到森林中剩下1棵树---所求的n个结点的哈夫曼树.
*/
//为了从森林中取出2棵权最小的树---森林采用顺序存储(方便取值) 数组(元素均为1棵二叉树)
//二叉树
typedef struct BiNode
{
int weight;//规定: 树的权 = 所有叶子结点的权
/*
位置指针 双亲结点 左右孩子结点的位置
BiNode * parent;
BiNode * lchild;
BiNode * rchild;
*/
int parent;
int lchild;
int rchild;
} *BiTree;
//对n个结点构造哈夫曼树
void CreatHuffmanTree(BiTree &T, int n);
//数组的n个数值中找最小的两个
void Select(BiTree T, int len, int & s1, int & s2);
int main()
{
return 0;
}
//数组的len个数值中找最小的两个
void Select(BiTree T, int len, int & s1, int & s2)
{
s1 = T[1].weight;
for (int i = 1; i <= len; i++)
{
if (T[i].parent != 0 || T[i].weight <= 0)
continue;
if (T[i].weight <= s1);
s1 = i;
}
for (int j = 1; j <= len; j++)
{
if (T[j].parent != 0 || T[j].weight <= 0 || j == s1)
continue;
if (T[j].weight <= s1);
s2 = j;
}
}
//对n个结点构造哈夫曼树
void CreatHuffmanTree(BiTree &T, int n)
{
//1、构造n棵二叉树(只有根结点), n棵二叉树组成森林
T = new BiNode[2 * n];//0号下标不用, n棵二叉树 + n - 1棵新树
for (int i = 1; i <= n; i++)
{
std::cout << "Enter the " << i << " weight: ";
std::cin >> T[i].weight;
T[i].parent = T[i].lchild = T[i].rchild = 0;
}
//n - 1轮构造新树
int s1, s2;
for (int j = 1; j <= n - 1; j++)
{
//2、从森林中取2个权最小的树
Select(T, n + j - 1, s1, s2);
//作为左右子树构造新树
T[n + j].weight = T[s1].weight + T[s2].weight;
T[n + j].parent = 0;
T[n + j].lchild = s1;
T[n + j].rchild = s2;
T[s1].parent = T[s2].parent = n + j;
}
*T = T[2 * n - 1];
}