树
- 树的定义
- 树的有关概念
- 森林:是m(m>=0)棵互不相交的树的集合
- 树结构与线性结构的区别
- 线性结构(一对一)
- 树结构(一对多)
二叉树的定义
- 二叉树性质和存储结构
- 第i层上至少有1个结点
- 性质2:深度为k的二叉树至多有2的k次方-1个结点(k>=1)
- 深度为k的二叉树至少有k个结点
- 满二叉树
- 完全二叉树
- 遍历二叉树
二叉树的遍历操作
#include <iostream>
#include <queue>
#include <vector>
#include <stack>
using namespace std;
typedef struct BiNode
{
int data;
struct BiNode *lchild, *rchild;
} *BiTree;
void visit(BiTree &TreeNode)
{
vector<int> vec;
if (!TreeNode)
{
cerr << "null node" << endl;
}
int val = TreeNode->data;
vec.push_back(val);
for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
{
cout << *it << " ";
}
}
// 先序遍历
bool PreOrderTraverse(BiTree &TreeNode)
{
if (TreeNode == nullptr)
{
return true;
}
visit(TreeNode);
PreOrderTraverse(TreeNode->lchild);
PreOrderTraverse(TreeNode->rchild);
return true;
}
// 中序遍历
bool InOrderTraverse(BiTree &Treenode)
{
if (Treenode == nullptr)
{
return true;
}
InOrderTraverse(Treenode->lchild);
visit(Treenode);
// cout << Treenode->data << " ";
InOrderTraverse(Treenode->rchild);
return true;
}
// 后序遍历
bool PostOrderTraverse(BiTree &TreeNode)
{
if (TreeNode == nullptr)
{
return false;
}
PostOrderTraverse(TreeNode->lchild);
PostOrderTraverse(TreeNode->rchild);
visit(TreeNode);
return true;
}
// 中序遍历 非递归
void LDR(BiTree &TreeNode)
{
stack<BiTree> st;
BiTree cur = TreeNode;
while (cur != NULL || !st.empty())
{
if (cur != NULL)
{
st.push(cur);
cur = cur->lchild;
}
else
{
cur = st.top();
st.pop();
visit(cur);
cur = cur->rchild;
}
}
}
// 层序遍历
void LevelOrder(BiTree &TreeNode)
{
queue<BiTree> que;
if (TreeNode != NULL)
{
que.push(TreeNode);
}
vector<vector<int>> res;
while (!que.empty())
{
int size = que.size();
vector<int> vec;
for (int i = 0; i < size; i++)
{
BiTree node = que.front();
que.pop();
vec.push_back(node->data);
if (node->lchild)
que.push(node->lchild);
if (node->rchild)
que.push(node->rchild);
}
res.push_back(vec);
}
for (vector<vector<int>>::iterator iter = res.begin(); iter != res.end(); iter++)
{
for (vector<int>::iterator it = (*iter).begin(); it != (*iter).end(); it++)
{
cout << *it << " ";
}
}
}
// 二叉树的建立
void CreateTree(BiTree &TreeNode)
{
int input;
cin >> input;
if (input == -1)
{
TreeNode = NULL;
}
else
{
TreeNode = new BiNode;
TreeNode->data = input;
CreateTree(TreeNode->lchild);
CreateTree(TreeNode->rchild);
}
}
int main()
{
BiTree node;
CreateTree(node);
cout << "前序遍历:";
PreOrderTraverse(node);
cout << "中序遍历:";
InOrderTraverse(node);
cout << "中序遍历:";
PostOrderTraverse(node);
cout << "层次遍历:";
LevelOrder(node);
cout << "中序非递归遍历:";
LDR(node);
return 0;
}
- 运行结果:
树和森林
哈夫曼树
基本概念
- 满二叉树不一定是哈夫曼树
- 权重值越大的离根节点越近
- 具有相同带权结点的哈夫曼树不唯一
哈夫曼树的构造
- 构造哈夫曼树示例
- 总结
- 哈夫曼树的实现
#include <iostream>
#include <queue>
#include <vector>
#include <stack>
using namespace std;
typedef struct HNode
{
/* data */
int weight; // 权重
int parent, left, right; // 双亲、左孩子、右孩子
} *Huffman;
// 哈夫曼树初始化
void HuffmanInit(Huffman &H, int n)
{
// 数组大小为2n-1,下标从1开始所以是2n
H = new HNode[2 * n];
for (int i = 1; i < 2 * n; i++)
{
H[i].parent = H[i].left = H[i].right = 0;
}
int weight;
for (int i = 1; i <= n; i++)
{
cin >> weight;
H[i].weight = weight;
}
}
// 寻找两个结点的函数
//s1 s2 为引用类型
void Select(Huffman &H, int n, int &s1, int &s2)
{
vector<int> vec;
for (int i = 1; i <= n; i++)
{
if (H[i].parent == 0)
{
// 双亲为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;
}
}
s1 = *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;
}
}
s2 = *flag2; // 第二个结点
}
// 哈夫曼树构造
void CreateHuffman(Huffman &H, int length)
{
// 哈夫曼树初始化
HuffmanInit(H, length);
// 找出森林中最小的两棵树创建新树
for (int i = length + 1; i < 2 * length; i++)
{
int s1 = 0, s2 = 0;
// 在数组中找出两个双亲为0且权重值是最小的结点,并返回数组中结点序号
// 在1-n的数组范围中寻找
Select(H, i - 1, s1, s2);
H[s1].parent = i;
H[s2].parent = i;
H[i].left = s1;
H[i].right = s2;
H[i].weight = H[s1].weight + H[s2].weight;
}
for (int i = 1; i < 2 * length; i++)
{
printf("节点 %d 权值为 :%d 双亲为:%d 左孩子为 :%d 右孩子为:%d \n", i, H[i].weight, H[i].parent, H[i].left, H[i].right);
}
}
int main()
{
Huffman H;
int n = 6;
CreateHuffman(H, n);
return 0;
}
- 运行结果
哈夫曼编码
- 基本概念
- 示例
- 哈夫曼编码实现
// 实现哈夫曼编码
void HuffmanCode(Huffman &H, int n)
{
// CreateHuffman(H, n);
// 遍历哈夫曼树中前n个元素,寻找新树结点的左右孩子,根据左右孩子赋值0或1
for (int i = 1; i <= n; i++)
{
int chd = i;
int par = H[chd].parent;
stack<int> st;
// 父节点等于0表示访问到根节点,循环结束
while (par != 0)
{
if (H[par].left == chd)
st.push(0);
else
st.push(1);
chd = par;
par = H[chd].parent;
}
while (!st.empty())
{
int out = st.top();
st.pop();
cout << out;
}
cout << endl;
}
}
- 运行结果