建立的算法描述如下:首先建立N个节点,每个节点包含一个Name和Data信息,并对这些节点使用链表串接起来;然后创建一颗树的根节点,然后从链表里面依据Data字段删掉两个节点,小的作为左子树,大的作为右子树,同时将二者的数值和赋值给根节点,最后将这个根节点插入到原来的链表之上。重复以上的步骤,直到链表的长度为1,则代表二叉树建立完成。代码如下:
leaf_name=['A','B','C','D','E','F','G','H']; leaf_data=[1,2,3,4,5,6,7,8]; len=8; for i = 1:len new_node(i) = node(leaf_data(i),leaf_name(i)); end %创建链表,并向链表中插入节点 my_list = list(); for i = 1:len my_list.insertbeforehead(new_node(i)); end while(my_list.size >1) lchild_node =my_list.delete_min_node();%取出最小的元素 lchild_node.Flag01=0;%标记为左子树 rchild_node =my_list.delete_min_node();%取出第二小的元素 rchild_node.Flag01=1;%标记为右子树 root_node =node([],'root'); root_node.Lchild=lchild_node;%左子树 root_node.Rchild=rchild_node;%右子树 root_node.Data=lchild_node.Data + rchild_node.Data;%概率相加 root_node.Name=strcat(lchild_node.Name , rchild_node.Name); lchild_node.Parent=root_node; rchild_node.Parent=root_node; my_list.insertbeforehead(root_node); if(my_list.size==1)%最后一个节点,即是树的根节点。删除链表的前后指针 my_list.head.Next=[]; my_list.head.Prev=[]; my_list.head.Parent=[]; end end打印叶子节点的路径有什么作用呢,霍夫曼编码的时候需要得到每个字符的编码值,这时候就需要知道叶子的路径。具体算法是这样的,第一步,建立二叉树的时候,每个节点增加一个标志Flag01,当为0的时候代表左子树,当为1的时候代表右子树,同时添加一个Parent指针指向父母节点,当然根节点的父母节点为空;第二步,通过递归调用的方法查找到每个叶子节点;第三步,同过节点的Flag01信息打印0或者1,代表当前节点是左子树还是右子树,然后进入父母节点,重复直到根节点;依次递归结束,则叶子节点的路径查询完毕。打印的数据反过来看就是实际的编码值。代码如下:
function preorder_scan(node) if ~isempty(node)%非空 if(isempty(node.Lchild) && isempty(node.Rchild)) fprintf('%s code is -->',node.Name); while ~isempty(node.Parent) if(node.Flag01==0) fprintf('0'); else fprintf('1'); end node=node.Parent; end fprintf('\n'); return end preorder_scan(node.Lchild); preorder_scan(node.Rchild); end end根节点的Name字段和Data字段分别如下。 GHDEABCF 36 每个字符的编码结果如下,需要反着读。 G code is -->00 H code is -->10 D code is -->001 E code is -->101 A code is -->00011 B code is -->10011 C code is -->1011 F code is -->111
