目录
赫夫曼编码
赫夫曼树的一个重要应用是赫夫曼编码。这里的编码是将要传送的文字转换为二进制的字符串(由0和1组成的字符串)。
根据给定字符串权值求赫夫曼编码的过程,实际上就是根据给定权值构造赫夫曼树的过程。以A、B、C、D的权值(或出现频率)分别为0.4,0.3,0.1,0.2为例
插入、删除、查找的时间复杂度
二叉树的主要性质
性质1:非空二叉树的叶子结点数等于双分支结点数加1。
性质2:
完全二叉树的一些性质
1.高度(或深度)为k的二叉树最多有2^k-1个节点。换句话说,满二叉树中前k层的节点个数为2^k-1。
2.具有n个节点的完全二叉树的高度(或深度)为「log2n」+1,符号是向下取整。
树的先序、中序、后序、层次遍历代码
#include<iostream>
#include<stack>
#include<queue>
using namespace std;
/*
实现二叉树的先序、中序、后序遍历,包括递归方式和非递归
方式
*/
class Node {
public:
int value;
Node *left;
Node *right;
Node(int data)
{
value = data;
left = right = NULL;
}
};
/递归版本
void preOrderRecur(Node *head)
{
if (head == NULL)
return;
cout << head->value << " ";
preOrderRecur(head->left);
preOrderRecur(head->right);
}
void inOrderRecur(Node *head)
{
if (head == NULL)
return;
preOrderRecur(head->left);
cout << head->value << " ";
preOrderRecur(head->right);
}
void posOrderRecur(Node *head)
{
if (head == NULL)
return;
preOrderRecur(head->left);
preOrderRecur(head->right);
cout << head->value << " ";
}
/非递归版本/
//先序非递归
void preOrderUnRecur(Node *head)
{
if (head != NULL)
{
stack<Node*> s1;
s1.push(head);
while (s1.empty() == 0)
{
head = s1.top();
cout << head->value << " ";
s1.pop();
if (head->right != NULL)
s1.push(head->right);
if (head->left != NULL)
s1.push(head->left);
}
}
}
//中序非递归
void inOrderUnRecur(Node *head)
{
if (head != NULL)
{
stack<Node*> s1;
while (s1.empty() == 0 || head != NULL)
{
if (head != NULL)
{
s1.push(head);
head = head->left;
}
else
{
head = s1.top();
cout << head->value << " ";
s1.pop();
head = head->right;
}
}
}
}
//后序非递归
/*
先序是根左右,后序是左右根,所以思想就是按根右左先排好,
然后放入另一个栈中,然后按顺序出栈,就成了左右根
*/
void posOrderUnRecur1(Node *head)
{
if (head != NULL)
{
stack<Node*> s1;
stack<Node*> s2;
s1.push(head);
while (s1.empty() == 0)
{
head = s1.top();
s1.pop();
s2.push(head);
if (head->left != NULL)
s1.push(head->left);
if (head->right != NULL)
s1.push(head->right);
}
while (s2.empty() == 0)
{
cout << s2.top()->value << " ";
s2.pop();
}
}
}
//层次遍历
void LevelOrder(Node *head)
{
queue<Node *> qNode;
if (head == NULL)
return;
qNode.push(head);
while(!qNode.empty())
{
head = qNode.front();
cout << head->value << " ";
qNode.pop();
if (head->left != NULL)
qNode.push(head->left);
if (head->right != NULL)
qNode.push(head->right);
}
}
求二叉树的宽度
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
class BiTree {
public:
int value;
BiTree *left;
BiTree *right;
BiTree(int v) :value(v), left(nullptr), right(nullptr) {}
};
int WidthOfBiTree(BiTree *root)
{
if (root == nullptr)
return 0;
int maxValue = 0;
queue<BiTree *> q;
q.push(root);
while (!q.empty())
{
//每一层的结点总数
int len = q.size();
if (len > maxValue)
maxValue = len;
while (len)
{
BiTree *node = q.front();
q.pop();
--len;
if (node->left != nullptr)
q.push(node->left);
if (node->right != nullptr)
q.push(node->right);
}
}
return maxValue;
}
输出二叉树每一层的最右节点
思想同样可以解决非递归求解二叉树的深度
#include<queue>
using namespace std;
class BiTree {
public:
int value;
BiTree *left;
BiTree *right;
BiTree(int v) :value(v), left(nullptr), right(nullptr) {}
};
void findRightNode(BiTree *root)
{
if (root == nullptr)
return;
int maxValue = 0;
queue<BiTree *> q;
q.push(root);
while (!q.empty())
{
//每一层的结点总数
int len = q.size();
while (len)
{
BiTree *node = q.front();
if (len == 1)
cout << node->value << endl;
q.pop();
--len;
if (node->left != nullptr)
q.push(node->left);
if (node->right != nullptr)
q.push(node->right);
}
}
return;
}
二叉排序树转换成有序双向链表
//结点的结构
struct BSTNode{
int data;
BSTNode *left;
BSTNode *right;
};
//主函数
BSTNode* Convert2DoubleLinkList(BSTNode *root)
{
if(root == NULL)
return NULL;
BSTNode *last = NULL;
//二叉排序树转换成排序双向链表
Convert(root, &last);
//取得双向链表的头指针
while(root->left != NULL)
root = root->left;
return root;
}
//二叉排序树转换成双向链表
void Convert(BSTNode *root, BSTNode** last)
{
if(root == NULL)
return;
//遍历左子树
Convert(root->left, last);
//处理根节点
root->left = *last;
if((*last) != NULL)
(*last)->right = root;
*last = root;
//遍历右子树
Convert(root->right, last);
}
二叉搜索树的查找、插入、删除
#include<iostream>
using namespace std;
struct BSTNode {
int value;
BSTNode *left;
BSTNode *right;
BSTNode(int v) :value(v), left(nullptr), right(nullptr) {}
};
//二叉搜索树查找算法
BSTNode* bst_search(BSTNode* node, int value)
{
while (node != nullptr)
{
if (value == node->value)//找到
return node;
else if (value < node->value)//向左
node = node->left;
else//向右
node = node->right;
}
return nullptr;
}
//二叉搜索树插入算法
bool bst_insert(BSTNode** root, int value)
{
BSTNode *cur = *root;
BSTNode *pre = nullptr;//记录待插入元素的父节点
while (cur != nullptr)
{
if (value == cur->value)//树中原本存在,插入失败
return false;
else if (value < cur->value)//向左
{
pre = cur;
cur = cur->left;
}
else//向右
{
pre = cur;
cur = cur->right;
}
}
cur = new BSTNode(value);
if (pre == nullptr)
*root = cur;
else
cur->value < pre->value ? pre->left = cur : pre->right = cur;
return true;
}
//二叉搜索树删除算法
bool bst_delete(BSTNode** root, int value)
{
BSTNode *parent = nullptr;
BSTNode *node = *root;
BSTNode *temp = nullptr;
while (node != nullptr)
{
if (value < node->value)//向左
{
parent = node;
node = node->left;
}
else if (value>node->value)//向右
{
parent = node;
node = node->right;
}
else//找到了待删除的节点
{
if (node->left == nullptr && node->right == nullptr)//待删除的节点是叶子节点
{
if (parent == nullptr)//根节点
{
delete node;
root = nullptr;
}
else//非根节点
{
(parent->left == node) ? parent->left = nullptr : parent->right = nullptr;
delete node;
node = nullptr;
}
}
else if (node->left != nullptr && node->right == nullptr)//待删除的节点只有左孩子
{
if (parent == nullptr)//根节点
{
temp = node;
root = &(node->left);//根节点发生了变化
delete temp;
temp = nullptr;
}
else//非根节点
{
(parent->left == node) ? parent->left = node->left : parent->right = node->left;
delete node;
node = nullptr;
}
}
else if (node->right != nullptr && node->left == nullptr)//待删除的节点只有右孩子
{
if (parent == nullptr)//根节点
{
temp = node;
root = &(node->right);//根节点发生了变化
delete temp;
temp = nullptr;
}
else//非根节点
{
(parent->left == node) ? parent->left = node->right : parent->right = node->right;
delete node;
node = nullptr;
}
}
else//待删除的节点既有左孩子又有右孩子
{
BSTNode *leftNode = node->left;
parent = node;
//找到左子树的最右节点,转移成为删除这个节点
while (leftNode->right != nullptr)
{
parent = leftNode;
leftNode = leftNode->right;
}
// 交换leftNode与node
int swapValue = leftNode->value;
leftNode->value = node->value;
node->value = swapValue;
//删除leftNode
(parent->left == leftNode) ? (parent->left = leftNode->left) : (parent->right = leftNode->left);
delete leftNode;
leftNode = nullptr;
}
return true;
}
}
return false;
}
二叉树的最大距离(即相距最远的两个叶子节点)
要求的二叉树的最大距离其实就是求:肯定是某个节点左子树的高度加上右子树的高度加2,所以求出每个节点左子树和右子树的高度,取左右子树高度之和加2的最大值即可,假设空节点的高度为-1,也就是说叶结点的高度为1。
函数的返回值是当前树的高度,nMaxDistance是最大距离。
int HeightOfBinaryTree(BinaryTreeNode*pNode, int&nMaxDistance){
if (pNode == NULL)
return -1; //空节点的高度为-1
//递归
int nHeightOfLeftTree = HeightOfBinaryTree(pNode->m_pLeft, nMaxDistance) + 1; //左子树的的高度加1
int nHeightOfRightTree = HeightOfBinaryTree(pNode->m_pRight, nMaxDistance) + 1; //右子树的高度加1
int nDistance = nHeightOfLeftTree + nHeightOfRightTree; //距离等于左子树的高度加上右子树的高度+2
nMaxDistance = nMaxDistance > nDistance ? nMaxDistance : nDistance; //得到距离的最大值
return nHeightOfLeftTree > nHeightOfRightTree ? nHeightOfLeftTree : nHeightOfRightTree;
}
二叉树的最大路径和
给定一个非空二叉树,返回其最大路径和。
本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
int maxPathSum(TreeNode* root)
{
int value = INT_MIN;
int *max_sum = &value;
dfs(root, max_sum);
return *max_sum;
}
//dfs的返回值是给父亲用的,所以不可能出现左中右这种,
//只能是左中或者中右
int dfs(TreeNode* root, int *max_sum)
{
if (root == nullptr)
return 0;
int l = dfs(root->left, max_sum);
int r = dfs(root->right, max_sum);
int sum = root->val;
if (l > 0)
sum += l;
if (r > 0)
sum += r;
//记录最大值
*max_sum = max(*max_sum, sum);
//给父亲节点返回时,必须包含此节点,否则不就连不起来了
return max(r, l) > 0 ? max(r, l) + root->val : root->val;
}