学习反思:
二叉树学习到现在基本上告一段落了,老师的进度已经完成,剩下的就是我们自己的事情了,比如好好复习,做完剩下的练习题目。
对于我还没有做出来的那个练习题,我心中其实只有一点点想法,比如说在交换的时候变化指向左右子树的指针,但是这个过程是个递归的过程,如何把握使两个节点只交换一次,应该是需要考虑的内容之一……吧?还有就是怎么交换指针,需要交换的是这个节点的两个子节点,应该可以参考单链的操作?
总之既然能有人做出来,那么这个题就不是不能被做出来的题目。
所以……下节课这个题目应该会被完结了,正式开启图论副本,可是图论好难的亚子……连老师都说难呜呜呜,平时做的题目都是数组邻接表存储的模式,说实话用链表还真少。包括以前的一些内容,我可怜的数组都被抛弃了呜呜呜,毕竟数组只要找到逻辑规律就很容易写了,可是链表是实打实的又难思考又难写,还要写个class,真是的!
咳咳咳,学习学习。
二叉树的顺序存储:
二叉树的顺序存储结构就是用一维数组存储二叉树中的结点,并且结点的存储位置(下标)应能体现结点之间的逻辑关系——父子关系。
就是让一棵棵二叉树先变成完全二叉树的编号,然后去掉没有的节点,用数组保存存在的节点。
这个存储的条件,是利用了二叉树的父子节点的下标之间的关系:
- 父亲节点 的编号是子节点的两倍,所以父亲节点除以二是左孩子,除以二加一是右孩子。
- 完全二叉树的下标是从一开始到节点数目结束,所以开的数组大小可算,如果是只告诉你数目以及下标,完全可以依靠最大的下标来开数组(比如就开这么大)
左右子树按照这个方法找,赋值同。所以顺序存储很简单,很开心。
二叉链表
基本思想:令二叉树的每个结点对应一个链表结点,链表结点除了存放与二叉树结点有关的数据信息外,还要设置指示左右孩子的指针。
节点结构:
data:数据域,存放该结点的数据信息;
lchild:左指针域,存放指向左孩子的指针;
rchild:右指针域,存放指向右孩子的指针。
代码:
template <class T>
struct BiNode
{
T data;
BiNode<T> *lchild, *rchild;
};
二叉链表的实现
对于一个稳稳的二叉链表,我们需要知道的除了节点的构造,最重要的就是函数怎么写。
二叉链表函数的写法十分简单,但是还是需要很多注意事项;
代码:
template <class T>
class BiTree
{
public:
BiTree(); //构造函数
void PreOrder(){PreOrder(root);} //为什么不直接写在这里面呢?因为这里需要调用根节点,然鹅根节点是私有的,我们不能调用,所以才直接让这个函数调用。
void InOrder() {InOrder(root);}
void PostOrder() {PostOrder(root);}
void LevelOrder(){LeverOrder(root)};
private:
BiNode<T> *root;
BiNode<T> * Creat( );
void PreOrder(BiNode<T> *root);
void InOrder(BiNode<T> *root);
void PostOrder(BiNode<T> *root);
void LevelOrder(BiNode<T> *root);
};
剩下的那些内容,自己查书就好了,都不是很难,但是要记住关键点。
最难的是构造函数,其他的都不太需要动脑子。
构造函数:
二叉树的建立需要依靠一种名叫拓展二叉树的树,就是把所有节点的空节点都补成#的一种二叉树,对它进行前序遍历形成的序列叫做拓展前序二叉序列。
- 按扩展前序遍历序列输入结点的值
- 如果输入结点值为“#”,则建立一棵空的子树
- 否则,根结点申请空间,将输入值写入数据域中,
- 以相同方法的创建根结点的左子树
- 以相同的方法创建根结点的右子树
代码:
template <class T>
BiTree ::BiTree()//这是public里面的
{
root=creat();
}
template <class T>
BiNode<T> * BiTree ::Creat(){//这是private里面的
BiNode<T> *root; char ch;
cin>>ch;
if (ch=='# ') root=NULL;
else {
root=new BiNode<T>;
root->data=ch;
root->lchild=creat();
root->rchild= creat();
}
return root
}
非递归遍历的那些不好用,就不写了……反正我也会递归的。
求各种参数
1.求节点数目
思路:节点数目=左子树节点数目+右子树节点数目+1
*递归
边界条件:节点为空
2.求叶子数目
思路:叶子数目=左叶子+右叶子;
边界条件:叶子空返回1,自己空返回0
3.求树的深度
思路:深度=max(左子树的深度,右子树的深度)+1;
边界条件:节点为空返回0
最优二叉树——哈夫曼树
最优二叉树是所有叶子节点的权值乘路径长度相加,得到的值最小的一棵树。
哈夫曼树的特点:
- 权值越大的叶子结点越靠近根结点,而权值越小的叶子结点越远离根结点。
- 只有度为0(叶子结点)和度为2(分支结点)的结点,不存在度为1的结点.
得到最优二叉树的方法是:
⑴ 初始化:由给定的n个权值{w1,w2,…,wn}构造n棵只有一个根结点的二叉树,从而得到一个二叉树集合F={T1,T2,…,Tn};
⑵ 选取与合并:在F中选取根结点的权值最小的两棵二叉树分别作为左、右子树构造一棵新的二叉树,这棵新二叉树的根结点的权值为其左、右子树根结点的权值之和;
⑶ 删除与加入:在F中删除作为左、右子树的两棵二叉树,并将新建立的二叉树加入到F中;
⑷ 重复⑵、⑶两步,当集合F中只剩下一棵二叉树时,这棵二叉树便是哈夫曼树。