树和二叉树:哈夫曼树和线索二叉树

最优二叉树:
叶子结点的权值:对叶子结点赋予的一个有意义的数值量。
二叉树的带权路径长度:设二叉树具有n个带权值的叶子结点,从根结点到各个叶子结点的路径长度与相应叶子结点权值的乘积之和。
哈夫曼树:给定一组具有确定权值的叶子结点,带权路径长度最小的二叉树。
哈夫曼树的特点:
1 权值越大的叶子结点越靠近根结点,而权值越小的叶子结点越远离根结点。
2 只有度为0(叶子结点)和度为2(分支结点)的结点,不存在度为1的结点.
哈夫曼算法基本思想:
⑴ 初始化:由给定的n个权值{w1,w2,…,wn}构造n棵只有一个根结点的二叉树,从而得到一个二叉树集合F={T1,T2,…,Tn};
⑵ 选取与合并:在F中选取根结点的权值最小的两棵二叉树分别作为左、右子树构造一棵新的二叉树,这棵新二叉树的根结点的权值为其左、右子树根结点的权值之和;
⑶ 删除与加入:在F中删除作为左、右子树的两棵二叉树,并将新建立的二叉树加入到F中;
⑷ 重复⑵、⑶两步,当集合F中只剩下一棵二叉树时,这棵二叉树便是哈夫曼树。
设置一个数组huffTree[2n-1]保存哈夫曼树中各点的信息,数组元素的结点结构
weight:权值域,保存该结点的权值;
lchild:指针域,结点的左孩子结点在数组中的下标;
rchild:指针域,结点的右孩子结点在数组中的下标;
parent:指针域,该结点的双亲结点在数组中的下标;
struct element
{ int weight;
int lchild, rchild, parent;
};
1:数组huffTree初始化,所有元素结点的双亲、左
右孩子都置为-1;
2. 数组huffTree的前n个元素的权值置给定值w[n];
3. 进行n-1次合并
3.1 在二叉树集合中选取两个权值最小的根结点,
其下标分别为i1, i2;
3.2 将二叉树i1、i2合并为一棵新的二叉树k(初值为n;依次递增);
代码:

void HuffmanTree(element huffTree[ ], int w[ ], int n ) {
   for (i=0; i<2*n-1; i++) {
      huffTree [i].parent= -1;
      huffTree [i].lchild= -1;
      huffTree [i].rchild= -1;   
   }
   for (i=0; i<n; i++) 
      huffTree [i].weight=w[i];
   for (k=n; k<2*n-1; k++) {
       Select(huffTree, &i1, &i2); //选出两个最小的权值。
       huffTree[k].weight=huffTree[i1].weight+huffTree[i2].weight;
       huffTree[i1].parent=k;     
       huffTree[i2].parent=k; 
       huffTree[k].lchild=i1;    
       huffTree[k].rchild=i2;
   }
}

哈夫曼编码:
编码:给每一个对象标记一个二进制位串来表示一组对象。
例:ASCII,指令系统
等长编码:表示一组对象的二进制位串的长度相等。
不等长编码:表示一组对象的二进制位串的长度不相等。
前缀编码:一组编码中任一编码都不是其它任何一个编码的前缀 。
前缀编码保证了在解码时不会有多种可能。
线索二叉树
在有n个结点的二叉链表中共有2n个链域,但只有n-1个有用的非空链域,其余n+1个链域是空的。
**我们可以利用剩下的n+1个空链域来存放遍历过程中结点的前驱和后继信息。
线索:将二叉链表中的空指针域指向前驱结点和后继结点的指针被称为线索;
线索化:使二叉链表中结点的空链域存放其前驱或后继信息的过程称为线索化;
线索二叉树:加上线索的二叉树称为线索二叉树
itag=0: lchild指向该结点的左孩子
itag=1: lchild指向该结点的前驱结点。
rtag=0: rchild指向该结点的右孩子
rtag=1: rchild指向该结点的后继结点

enum flag {Child, Thread}; //枚举类型:枚举常量Child=0,Thread=1;
template
struct ThrNode
{
T data;
ThrNode *lchild, *rchild;
flag ltag, rtag;
};
中序线索链表:
建有带有标志位的二叉树:

template <class T>ThrNode<T>* InThrBiTree<T>::Creat( ){
    ThrNode<T> *root;
    T ch;
    cout<<"请输入创建一棵二叉树的结点数据"<<endl;
    cin>>ch;
    if (ch=="#") root = NULL;
    else{	
         root=new ThrNode<T>;    
         root->data = ch;
         root->ltag = Child; root->rtag = Child;
         root->lchild = Creat( );
         root->rchild = Creat( ); 
    } 
	return root;
}

函数设置形参root和全局变量pre,分别表示要处理的树的根结点和其前驱结点
如果root!=NULL
中序线索化root的左子树
中序线索化root本身
如果root->lchild= =NULL
root->left=pre,root->ltag=1;
如果root->rchild==NULL,root->rtag=1,
如果pre!=NULL, 并且pre->rtag=1,
pre->rchild=root,;
pre=root
中序线索化root的右子树

中序线索化二叉树:递归

template <class T>  void ThrBiTree<T>::ThrBiTree (ThrNode<T>*root) {
      if (root==NULL) return;         //递归结束条件
   
      ThrBiTree(root->lchild); 	
if (!root->lchild){             //对root的左指针进行处理
        root->ltag = Thread;   
        root->lchild = pre;        //设置pre的前驱线索
   }
   if (!root->rchild) root->rtag = Thread; 
    if(pre != NULL){
       if (pre->rtag==Thread)  pre->rchild = root; 
  }
   pre = root;
   ThrBiTree(root->rchild);
}

template <class T>
InThrBiTree<T>::InThrBiTree( )
{ 
 //ThrNode<T>* pre = NULL;
 this->root = Creat( );    
 ThrBiTree(root);
}

在中序线索二叉树中查找结点的中序遍历的后继:

template <class T> ThrNode<T>* InThrBiTree<T>::Next(ThrNode<T>* p)
{
    ThrNode<T>* q;  //要查找的p的后继
    if (p->rtag==Thread)   q = p->rchild;
    else{   
        q = p->rchild; 
        while (q->ltag==Child)	{
            q = q->lchild;
        }
    }
    return q;
}

中序遍历中序线索二叉树


template <class T> 
void InThrBiTree<T>::InOrder(ThrNode<T> *root){
    ThrNode<T>* p = root;
    if (root==NULL)  return; 
    while (p->ltag==Child)   {       p = p->lchild;    }
    cout<<p->data<<" ";
    while (p->rchild!=NULL) {
        p = Next(p);
        cout<<p->data<<" ";
    }
    cout<<endl;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值