1.二叉树
#pragma once
#include<iostream>
using namespace std;
#include"顺序栈.h"
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define INFEASIBLE -1
#define MAXSIZE 100
typedef int Status;
typedef char ElemType;
//二叉树的定义
typedef struct BiNode
{
ElemType data;
struct BiNode* lchild, * rchild;
}* BiTree;
//二叉树先序遍历
Status PreOrderTraver(BiTree& T)
{
if (T == nullptr)
{
return OK;
}
visit(T);
PreOrderTraver(T->lchild);
PreOrderTraver(T->rchild);
}
//中序遍历
Status InOrderTraver(BiTree& T)
{
if (T == nullptr)
{
return OK;
}
InOrderTraver(T->lchild);
visit(T);
InOrderTraver(T->rchild);
}
//后序遍历
Status InOrderTraver(BiTree& T)
{
if (T == nullptr)
{
return OK;
}
InOrderTraver(T->lchild);
InOrderTraver(T->rchild);
visit(T);
}
//二叉树的中序遍历——非递归算法
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, q);
visit(p);
p = q->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判断,是否能将根结点的左右孩子进队
if (p->lchild != nullptr)
{
PushQueue(Q, p->lchild);
}
if (p->rchild != nullptr)
{
PushQueue(Q, p->rchild);
}
}
}
//二叉树的建立
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 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 Count0Node(BiTree& T)
{
//③:递归函数将上一个结点剖分成左右子树,如果结点的孩子为空,那么返回0
//这里不会出现结点的两个孩子都是空的,因为上一个结点执行这个递归函数的时候就已经判断了这种情况
//这个语句只是为了以下两种情况而存在的:
//1. 空树
//2. 某个分支结点只有一个孩子
if (T == nullptr)
{
return 0;
}
//①:其实呢,我们还是可以把这个问题拆分成左子树和右子树的统计问题
if (T->lchild == nullptr && T->rchild == nullptr)
{
//以T为根结点的这棵树,左右孩子都没有,那他就是叶子结点
return 1;
}
//②:如果不是这个情况,就说明这个根结点至少有一个孩子,还要继续剖分这个结点
return Count0Node(T->lchild) + Count0Node(T->rchild);
}
2.哈夫曼树:
//哈夫曼树的定义
typedef struct HNode
{
int weight; //权重
int parent, lchild, rchild; //每个结点的双亲、左右孩子的数组下标
} *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;
}
}
//哈夫曼树构造
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;
}
}
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);
}
}
//找出最小的一个
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)
{
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;
}
}