C#数据结构-线索化二叉树

为什么线索化二叉树?

对于二叉树的遍历,我们知道每个节点的前驱与后继,但是这是建立在遍历的基础上,否则我们只知道后续的左右子树。现在我们充分利用二叉树左右子树的空节点,分别指向当前节点的前驱、后继,便于快速查找树的前驱后继。

不多说,直接上代码:

/// <summary>
/// 线索二叉树 节点
</summary>
<typeparam name="T"></typeparam>
public class ClueTreeNode<T>
{
    <summary>
     内容
    </summary>
    public T data { get; set; }
     左树
    public ClueTreeNode<T> leftNode {  右树
    public ClueTreeNode<T> rightNode {  0 标识左树 1 标识 当前节点的前驱
    int leftTag {  0标识右树 1 标识 当前节点的后继
    int rightTag { ; }

    public ClueTreeNode()
    {
        data = default(T);
        leftNode = null;
        rightNode = ;
    }

     ClueTreeNode(T item)
    {
        data = item;
        leftNode = ;
    }
}
 线索化 二叉树 
/// 
 为什么线索化二叉树?
 第一:对于二叉树,如果有n个节点,每个节点有指向左右孩子的两个指针域,所以一共有2n个指针域。
 而n个节点的二叉树一共有n-1条分支线数,也就是说,其实是有 2n-(n-1) = n+1个空指针。
 这些空间不存储任何事物,白白浪费内存的资源。
 第二:对于二叉树的遍历,我们知道每个节点的前驱与后继,但是这是建立在遍历的基础上。
 否则我们只知道后续的左右子树。
 第三:对于二叉树来说,从结构上来说是单向链表,引入前驱后继后,线索化二叉树可以认为是双向链表。
class ClueBinaryTree<T> 树根节
    private ClueTreeNode<T> head {  线索化时作为前驱转存
    private ClueTreeNode<T> preNode {  ClueBinaryTree(){
        head = new ClueTreeNode<T>();
    }
     ClueBinaryTree(T val){
        head = (val);
    }


    public ClueTreeNode<T> GetRoot(){
        return head;
    }

     插入左节点
    </summary>
    <param name="val"></param>
    <param name="node"></param>
    <returns></returns>
    public ClueTreeNode<T> AddLeftNode(T val,ClueTreeNode<T> node){
        if (node == )
            throw new ArgumentNullException("参数错误");
        ClueTreeNode<T> treeNode = (val);
        ClueTreeNode<T> childNode = node.leftNode;
        treeNode.leftNode = childNode;
        node.leftNode = treeNode;
         treeNode;
    }

     插入右节点
    public ClueTreeNode<T> AddRightNode(T val,1)"> node.rightNode;
        treeNode.rightNode = childNode;
        node.rightNode = treeNode;
    }
     删除当前节点的 左节点
    public ClueTreeNode<T> DeleteLeftNode(ClueTreeNode<T>null || node.leftNode == );
        ClueTreeNode<T> leftChild = node.leftNode;
        node.leftNode = ;
         leftChild;
    }

     删除当前节点的 右节点
    public ClueTreeNode<T> DeleteRightNode(ClueTreeNode<T>null || node.rightNode == );
        ClueTreeNode<T> rightChild = node.rightNode;
        node.rightNode =  rightChild;
    }



     中序遍历线索化二叉树
    void MiddlePrefaceTraversal(){
        ClueTreeNode<T> node = head;
        while (node != )
        {
            //判断是否是
            while (node.leftTag == 0)
            {
                node = node.leftNode;
            }
            Console.Write($ {node.data});
            while (node.rightTag == 1 node.rightNode;
                Console.Write($);
            }
            node = node.rightNode;
        }
    }
     线索化二叉树
    <param name="node"></param>
    void MiddleClueNodes(ClueTreeNode<T>;
        }
        线索化左子树
        MiddleClueNodes(node.leftNode);
        当左树为空时,指向前驱,标识为 1
        if (node.leftNode == )
        {
            node.leftNode = preNode;
            node.leftTag = 如果 前驱的右树不为空
        if (preNode != null && preNode.rightNode == )
        {
            preNode.rightNode = node;
            preNode.rightTag = ;
        }
        preNode = node;
        线索化右子树
        MiddleClueNodes(node.rightNode);
    }
}

 

 

 

 

 

 现在我们测试:

创建树
ClueBinaryTree<string> clueBinaryTree = new ClueBinaryTree<string>(A);
ClueTreeNode<string> tree1 = clueBinaryTree.AddLeftNode(B,clueBinaryTree.GetRoot());
ClueTreeNode<string> tree2 = clueBinaryTree.AddRightNode(Cstring> tree3 = clueBinaryTree.AddLeftNode(DEFG中序遍历);
clueBinaryTree.MiddlePrefaceTraversal();

打印结果:

中序遍历 D B E A F C G

 

 

相关文章

文章浏览阅读6.2k次,点赞2次,收藏3次。C#数学运算表达式解...
文章浏览阅读5.2k次,点赞6次,收藏7次。程序要做到用户配置...
文章浏览阅读9k次。错误信息检测到 ContextSwitchDeadlock M...
文章浏览阅读2w次,点赞10次,收藏9次。我发生错误时的环境:...
文章浏览阅读9.8k次。C# 二进制字节流查找函数IndexOf ...
文章浏览阅读2.5w次,点赞3次,收藏9次。c#DataGridView数据...