1、二叉搜索树和双向链表
二叉搜索树结构:左子节点比根节点小,右子节点比根节点大
查找和插入的步骤类似,但是插入是失败的查找,它要找到一个空的左子结点或者右子结点。它们的算法复杂度都是O(logn),与二叉树的高度有关。即:较平衡的二叉树对应较低的复杂度。
因此,出现了AVL二叉搜索树,也就是对它的结构有了更严格的要求。它的任一子树,左子树和右子树的高度的绝对值之差不超过一。每个节点都可以用平衡因子这个指标,取正负1,0时,该节点是平衡的。
在删除某结点时,可能会破坏原有的结构,不再满足二叉搜索树的条件(通过平衡因子可以容易的判断出来),此时需要进行调整。
例子:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
思路:就是二叉树的中序遍历
我用的递归法,返回的是链表的头部。
而在和根节点连接时,需要的是左子树的末尾和右子树的头部。
所以得到左子树返回的链表的头部后,需要一个while循环,得到这个链表的尾部。
一定要注意的是,这个循环结束后pleft这个变量不再是链表头部,所以一定要拷贝一下这个指到p变量中去。
当左子结点不存在时,根节点就是首部
TreeNode* p=pRootOfTree;
因此这个初值很关键。
class Solution {
public:
TreeNode* Convert(TreeNode* pRootOfTree)
{
TreeNode* pleft=pRootOfTree;
TreeNode* pright=pRootOfTree;
TreeNode* p=pRootOfTree;
if(pRootOfTree==NULL)
return NULL;
//if(pRootOfTree->left==NULL&&pRootOfTree->right==NULL)//叶节点
//return pRootOfTree;
if(pRootOfTree->left!=NULL)
{
pleft=Convert(pRootOfTree->left);
p=pleft;
while(pleft->right!=NULL)
{
pleft=pleft->right;
}
pleft->right=pRootOfTree;
pRootOfTree->left = pleft;
}
if(pRootOfTree->right!=NULL)
{
pright=Convert(pRootOfTree->right);
pright->left=pRootOfTree;
pRootOfTree->right = pright;
}
return p;
}
};
2、Huffman树
带权路径长度(计算公式如下)最小的二叉树:权值较大的放在离根节点较近的地方。
Wk为第k个叶子结点的权值;Lk为该结点的路径长度(与深度有关,离根节点较近,该值越小)。
这个和霍夫曼编码思想是一样的:出现频率大的码字对应短码,出现频率小的码字对应长码。码长对应路径长度。
在进行霍夫曼编码时,需要对原始数据扫描两次,第一遍得到每一个取值的频率;建立二叉树之后(小值优先的原则),第二遍扫描,编码。规定左子树为0,右子树1.