#include<iostream>
#include<vector>
using namespace std;
#define MAXSIZE 100
#define OK 1
#define ERROR 0
typedef int ElemType;
typedef int Status;
// 二叉树的定义
typedef struct BiNode
{
ElemType data;
struct BiNode* lchild, * rchild;
}BiNode, * BiTree;
// 二叉树的先序遍历 DLR
bool PreOrderTraverse(BiTree& T)
{
if (T == nullptr)
{
return true;
}
//访问根结点
// visit(T);
cout << T->data << endl;
//递归遍历左孩子
PreOrderTraverse(T->lchild);
//递归遍历右孩子
PreOrderTraverse(T->rchild);
return true;
}
// 二叉树的中序遍历 LDR
bool InOrderTraverse(BiTree& T)
{
if (T == nullptr)
{
return true;
}
//第一步:访问左孩子
InOrderTraverse(T->lchild);
//第二步:访问根结点
//visit(T);
cout << T->data << endl;
//第三步:访问右孩子
InOrderTraverse(T->rchild);
return true;
}
// 二叉树的后序遍历 LRD
bool PostOrderTraverse(BiTree& T)
{
if (T == nullptr)
{
return true;
}
//第一步:访问左孩子
PostOrderTraverse(T->lchild);
//第二步:访问右孩子
PostOrderTraverse(T->rchild);
//第三步:访问根结点
//visit(T);
cout << T->data << endl;
return true;
}
/*
三种算法的时间复杂度:O(n),空间复杂度:O(n)
三种算法的思想都是DFS(深度优先算法)
*/
// 二叉树的中序遍历——非递归算法
void LDR(BiTree& T)
{
//第一步:创建一个栈,用于保存二叉树的结点
SqStack S;
InitSqStack(S);
BiTree p = T;
while (p || !IsEmpty(S))
{
if (p)
{
Push(S, p);
p = p->lchild;
}
else
{
Pop(S, p);
// visit(p);
cout << p->data << endl;
p = p->rchild;
}
}
}
// 二叉树的层次遍历算法
void LevelOrder(BiTree& S)
{
/*
算法设计思路:
1.将根结点入队
2.队列不为空时循环,从队列中出列一个元素,访问它,并作以下步骤:
2.1 如果该元素的左孩子不为空,让该元素的左孩子入队
2.2 如果该元素的右孩子不为空,让该元素的右孩子入队
*/
SqQueue Q;
InitSqQueue(Q);
BiTree p;
PushQueue(Q, S);
while (!QueueEmpty(Q))
{
//将根结点出队
DeQueue(Q, p);
//访问根结点
cout << p->data << endl;
//if判断,是否能将根结点的左右孩子进队
//p指针是在队列元素出队时所赋予的,
//算法里让p指针移动的动作就是把出队元素的地址直接赋给p
if (p->lchild != nullptr)
{
PushQueue(Q, p->lchild);
}
if (p->rchild != nullptr)
{
PushQueue(Q, p->rchild);
}
}
}
// 思想是广度优先算法BFS
//二叉树的建立(DLR先序遍历,递归算法)
bool CreatBiTree(BiTree& T)
{
ElemType input;
cin >> input;
if (input == -1)//建立空结点的标志为 -1(这个自己设定一个就好)
return false;
T = new BiNode;
//D
T->data = input;
//L
CreatBiTree(T->lchild);
//R
CreatBiTree(T->rchild);
return true;
}
// 二叉树的复制
bool CopyBiTree(const BiTree& T, BiTree& NewT)
{
if (T == nullptr)
{
return false;
}
NewT = new BiNode;
//D
NewT->data = T->data;
//L
CopyBiTree(T->lchild, NewT->lchild);
//R
CopyBiTree(T->rchild, NewT->rchild);
return true;
}
// 计算二叉树的深度
int Depth(BiTree& T)
{
if (T == nullptr)
{
return 0;
}
int m = Depth(T->lchild);
int n = Depth(T->rchild);
if (m > n)
return m + 1;
else
return n + 1;
}
// 求二叉树的结点数
int CountNode(BiTree& T)
{
if (T == nullptr)
{
return 0;
}
// //L
// int m = CountNode(T->lchild);
// //R
// int n = CountNode(T->rchild);
// //
// return m + n + 1;
//更加简单的语句
return CountNode(T->lchild) + CountNode(T->rchild) + 1;
}
// 求二叉树的叶子结点数
int Count0Node(BiTree& T)
{
//③:递归函数将上一个结点剖分成左右子树,如果结点的孩子为空,那么返回0
//这里不会出现结点的两个孩子都是空的,因为上一个结点执行这个递归函数的时候就已经判断了这种情况
//这个语句只是为了以下两种情况而存在的:
//1. 空树
//2. 某个分支结点只有一个孩子
if (T == nullptr)
{
return 0;
}
if (T->lchild == nullptr && T->rchild == nullptr)
{
return 1;
}
//如果不是这个情况,就说明这个根结点至少有一个孩子,还要继续剖分这个结点
return Count0Node(T->lchild) + Count0Node(T->rchild);
}
// 哈夫曼树
// 哈夫曼树的定义
typedef struct HNode
{
int weight; //权重
int parent, lchild, rchild; //每个结点的双亲、左右孩子的数组下标
}HNode, * HuffmanTree;
// 哈夫曼树的初始化
void InitHTree(HuffmanTree& H, const int n)
{
//哈夫曼树的存储结构为顺序存储
//由哈夫曼树的构造过程得知,n个权重结点构造出的哈夫曼树具有2*n-1个结点
//通常哈夫曼树的顺序存储结构下标从1开始计数,因此,如果我们使用数组实现的话
//那么数组的长度应该是2*n
H = new HNode[2 * n];
for (int i = 1; i < 2 * n; i++)
{
H[i].parent = H[i].lchild = H[i].rchild = 0;//右结合律
}
int input;
for (int i = 1; i <= n; i++)
{
cin >> input;
H[i].weight = input;
}
}
// 哈夫曼树的构造算法
/*
1、构造森林全是根
2、选用两小造新树
3、删除两小添新人
4、重复2、3剩单根
*/
// 哈夫曼树的结点的度数为0或1,没有度为1的结点
// 包含n个叶子结点的哈夫曼树共有2n-1个结点
void CreatHuffman(HuffmanTree& H, const int length)
{
//第一步:对哈夫曼树进行初始化
InitHTree(H, length);
//第二步:找出当前森林中最小的两棵树,创建新树,并让原来的两个树作为新树的孩子
for (int i = length + 1; i < 2 * length; i++)
{
int i1 = 0, i2 = 0;
Select(H, i - 1, i1, i2);//重点是这个Select算法
H[i].weight = H[i1].weight + H[i2].weight;//
H[i1].parent = H[i2].parent = i;
H[i].lchild = i1;
H[i].rchild = i2;
}
}
// Select算法
void Select(HuffmanTree& H, const int n, int& i1, int& i2)
{
vector<int> vec;
for (int i = 1; i <= n; i++)
{
if (H[i].parent == 0)// 插入没有双亲结点的结点
{
vec.push_back(i);// 在vec的最后一个元素后面插入元素,其值为i
}
}
//找出最小的一个
auto flag1 = vec.begin();
for (auto it = vec.begin() + 1; it != vec.end(); it++)
{
if (H[*it].weight < H[*flag1].weight)
{
flag1 = it;
}
}
i1 = *flag1; //最小的元素下标
vec.erase(flag1);
auto flag2 = vec.begin();
for (auto it = vec.begin() + 1; it != vec.end(); it++)
{
if (H[*it].weight < H[*flag2].weight)
{
flag2 = it;
}
}
i2 = *flag2; //第二小的元素的下标
}
// 哈夫曼编码算法
void HuffmanCode(HuffmanTree& H, const int n)
{
//第一步:调用函数创建一个顺序存储结构的哈夫曼树,同上的函数一样
CreatHuffman(H, n);
//第二步:遍历哈夫曼树中每一个叶子结点,也即哈夫曼数组中的前n个元素
for (int i = 1; i <= n; i++)
{
int chd = i;
int par = H[chd].parent;
//自下而上得到哈夫曼编码,用栈来保存再合适不过了
SqStack S;
InitStack(S);
while (par != 0)
{
// 左分支标注0,右分支标注1
H[par].lchild == chd ? /*0进栈*/ Push(S, 0) : /*1进栈*/ Push(S, 1);
chd = par;
par = H[chd].parent;
}
//出栈//黑框中打印编码
while (!IsEmpty(S))
{
int out;
Pop(S, out);
cout << out;
}
cout << endl;
}
}
数据结构:二叉树(C++)
最新推荐文章于 2024-05-31 21:10:27 发布