首页 > 其他分享 >数据结构之树(线索树)

数据结构之树(线索树)

时间:2023-11-11 23:56:08浏览次数:29  
标签:treeNode 指向 self 节点 之树 二叉树 数据结构 线索

线索二叉树

二叉树有些节点没有左子树或没有右子树或左右子树都没有,那么就会存在空链接的情况,为了充分利用空链接,让其指向树的其他节点,这些指向其他节点的链接就是线索,这棵树也变成了线索二叉树。

二叉树变成线索二叉树的步骤

1. 二叉树先根据中序遍历的方式,进行排序(这样节点就直到其前驱节点、后继节点)

2. 判断每个节点是否存在空链接,然后把空链接线索化。

3. 线索标记: 如果该节点无左子节点,则线索/左子链接引用指向第1步排序后的该节点的前驱节点

4. 线索标记: 如果该节点无右子节点,则线索/右子链接引用指向第1步排序后的该节点的后继节点

示例:

 

 

1. 二叉树中序排序结果: HDIBEAFCG

2. 分别判断每个节点是否有空链接,有空链接的进行线索化处理

2.1 H节点:无左右子节点,存在空链接即需要线索化处理。因为H没有前驱节点,H的左子节点指向None(null)即空节点,H的右子节点指向D即指向H的后继节点

2.2 D节点:无空链接,无需线索化处理

2.2 I节点:无左右子节点,存在空链接即需要线索化处理。I的左子节点指向其前驱节点(D),I的右子节点指向其后继节点(B)

2.2 B节点:无空链接,无需线索化处理

2.3 E节点:无左右子节点,存在空链接即需要线索化处理。I的左子节点指向其前驱节点(B),I的右子节点指向其后继节点(A)

2.4 A节点:无空链接,无需线索化处理

2.5 F节点:无左右子节点,存在空链接即需要线索化处理。I的左子节点指向其前驱节点(A),I的右子节点指向其后继节点(C)

2.6 C节点:无空链接,无需线索化处理

2.7 G节点:无左右子节点,存在空链接即需要线索化处理。I的左子节点指向其前驱节点(C),I的右子节点指向其后继节点,因其无后继节点,因此为None(null)即空节点

 

 

python代码示例

# 线索树节点
class ThreadNode(object):
    def __init__(self, data='#'):
        self.data = data  # 数据
        self.lchild = None  # 左子节点
        self.rchild = None  # 右子节点
        self.ltag = 0  # 左线索,0表示有左子节点,1表示没有左子节点。该节点没有左子节点时,lchild指向该节点的前驱节点(前驱、后继节点是由其排序决定)
        self.rtag = 0  # 右线索,0表示有右子节点,1表示没有右子节点。该节点没有右子节点时rlchild指向该节点的后继节点(前驱、后继节点是由其排序决定)


# 线索树
class BinaryThreadTree(object):
    def __init__(self, data_list):
        self.data_list = data_list
        # 创建树的头结点
        self.headNode = ThreadNode()
        self.headNode.ltag = 0  # 有左子节点
        self.headNode.rtag = 1  # 无右子节点
        self.headNode.lchild = self.headNode  # 为本身
        self.preNode = ThreadNode()  # 前驱节点

    # 根据列表创建二叉树
    def __createBinaryTree(self, root=None, pos=0):
        if pos >= len(self.data_list) or self.data_list[pos] == '#':
            # 递归结束条件
            return None
        else:
            root = ThreadNode(self.data_list[pos])
            # 递归建立左子树
            root.lchild = self.__createBinaryTree(root, 2 * pos + 1)
            # 递归建立右子树
            root.rchild = self.__createBinaryTree(root, 2 * pos + 2)
            return root

    # 访问当前节点的数据
    def visitBinaryTreeNode(self, rootNode):
        if rootNode.data != '#':
            print(rootNode.data, end=' ')

    # 创建线索二叉树:首先创建二叉树,然后通过中序遍历线索化。这里使用了递归的方式。
    def createInThread(self):
        rootNode = self.__createBinaryTree()
        if rootNode is None:
            self.headNode.lchild = self.headNode
        else:
            # lchild域的指针指向二叉树的根结点
            self.headNode.lchild = rootNode
            self.preNode = self.headNode
            self.inThread(rootNode)
            # 处理最后一个结点
            self.preNode.rtag = 1
            self.preNode.rchild = self.headNode
            # rchild域的指针指向中序遍历时访问的最后一个结点
            self.headNode.rchild = self.preNode

    #  中序遍历线索化:线索化过程中,如果节点没有左子节点,将左线索指向前驱节点;如果前驱节点没有右子节点,将右线索指向当前节点。
    def inThread(self, treeNode):
        if treeNode is not None:
            # 递归, 线索化左子树
            self.inThread(treeNode.lchild)
            if treeNode.lchild is None:
                # 当前结点没有左孩子
                # 将当前结点的ltag置为1, 表示lchild域指向的是前驱
                treeNode.ltag = 1
                treeNode.lchild = self.preNode
            if self.preNode.rchild is None:
                # 前驱结点没有右孩子
                # 将前驱结点的rtag置为1, 表示rchild域指向的是后继, 即当前的TreeNode
                self.preNode.rtag = 1
                self.preNode.rchild = treeNode
            # 标记刚刚访问的结点为下个结点的前驱结点
            self.preNode = treeNode
            self.inThread(treeNode.rchild)

    # 中序遍历线索二叉树
    def inOrderThread(self):
        # treeNode就是树的根结点
        treeNode = self.headNode.lchild
        while treeNode is not self.headNode:
            while treeNode.ltag == 0:
                # 找到了树最左边的那个结点(不一定是叶结点)
                treeNode = treeNode.lchild
            self.visitBinaryTreeNode(treeNode)
            while treeNode.rchild is not self.headNode and treeNode.rtag == 1:
                # 线索后继
                treeNode = treeNode.rchild
                self.visitBinaryTreeNode(treeNode)
            # rtag=0就开始寻找右子树最左边那个结点
            treeNode = treeNode.rchild


if __name__ == '__main__':
    tree_obj = BinaryThreadTree('ABCDEFGHI#')
    tree_obj.createInThread()
    tree_obj.inOrderThread()

输出:

H D I B E A F C G 

  

优缺点

线索二叉树是对普通二叉树的一种优化,通过引入线索(线索化),可以提高对二叉树的遍历效率。:

优点:

  1. 遍历效率提高: 线索二叉树在中序遍历时,不需要使用递归或栈,而是通过线索直接找到下一个节点,因此遍历效率较高。

  2. 节省空间: 在线索二叉树中,引入的线索信息并不额外占用存储空间,因为线索是通过原有的左右子节点的空指针来表示的。相比于使用栈进行递归遍历,这节省了存储空间。

  3. 简化代码逻辑: 由于线索化后的二叉树不需要递归或栈,可以简化中序遍历等算法的实现,减少代码的复杂性。

缺点:

  1. 构建和维护的复杂性: 线索二叉树的构建和维护相对复杂,需要在插入、删除等操作时更新线索信息,容易引入错误。

  2. 不适用于频繁修改的情况: 如果二叉树的结构经常变动,比如频繁地进行插入、删除操作,线索二叉树的维护可能会变得非常繁琐,效率可能不如普通二叉树。

  3. 不利于其他遍历方式: 线索二叉树主要优化了中序遍历,对于其他遍历方式(如前序、后序)并没有明显的优势,甚至可能引入冗余的线索信息。

  4. 占用额外的指针空间: 虽然线索信息不占用额外的存储空间,但对于每个节点都需要引入两个指针(左线索、右线索),可能导致额外的指针空间占用。

在选择是否使用线索二叉树时,需要根据具体应用场景来权衡其优缺点。如果主要是中序遍历的频繁操作,且对存储空间有一定要求,线索二叉树可能是一个合适的选择。然而,在频繁修改或其他遍历方式需要优化的情况下,可能需要考虑其他数据结构。

 

 

   

 

标签:treeNode,指向,self,节点,之树,二叉树,数据结构,线索
From: https://www.cnblogs.com/allenxx/p/17826596.html

相关文章

  • Redission实现公平锁为什么要使用ZSet数据结构?
    Redission实现公平锁为什么要使用ZSet数据结构?使用ZSet结构有什么好处?看lua代码好像也并没有使用到ZSet的二分查找这种优势,在Redisson中实现公平锁时使用ZSet(有序集合)数据结构有以下几个好处:具有排序功能:ZSet是有序的数据结构,其中的每个元素都有一个分数(score)与之相关联。这使得R......
  • JavaSEday05 泛型,数据结构,List,Set集合
    javSEday05泛型,数据结构,List,Set今日目标泛型使用数据结构ListSet1泛型1.1泛型的介绍泛型是一种类型参数,专门用来保存类型用的最早接触泛型是在ArrayList,这个E就是所谓的泛型了。使用ArrayList时,只要给E指定某一个类型,里面所有用到泛型的地方都会被......
  • JavaSE day05【泛型,数据结构,List接口,Set接口】测评题
    选择题题目1(单选):查看下列代码,选出正确的传参()publicclassTest2{publicstaticvoidmain(String[]args){ArrayList<Integer>list1=newArrayList<Integer>();ArrayList<Number>list2=newArrayList<Number>();Arr......
  • 一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)
    请问以下JS代码的执行结果是什么?functioncontrol(x){if(x==3)thrownewError("break");}functionfoo(x=6){return{next:()=>{control(x);return{done:!x,value:x&&x--};}}}letx=newObject;x[Symbol.......
  • 数据结构之树(二叉排序树)
    特点二叉排序树(BinarySearchTree,BST)的特点:每个节点最多有两个子节点,分别称为左子节点和右子节点。节点的左子树中的所有节点的值都小于该节点的值。节点的右子树中的所有节点的值都大于该节点的值。左子树和右子树也分别是二叉排序树。BST的主要优点是可以实现高效的查......
  • python3: dlt - 数据结构2
    python3:dlt-数据结构2    一、源程序1[wit@fedoranull]$cattest.py2#!/usr/bin/envpython334567#file_name=test.py8#python_verion=3.11.1910111213#testthisscript14defmsg():15print......
  • python3: dlt - 数据结构
    python3:dlt-数据结构    一、程序:1[wit@fedoranull]$cattest.py2#!/usr/bin/envpython334567#testthisscript8defmsg():9print("\nhello,python3!\n")101112#runningmsg()13#msg()1415......
  • 什么是数据结构里的 Merkle 树
    Merkle树,也被称为"hashtree",是一种二叉树的数据结构。这种树的每个节点都是基于其子节点的一种特殊形式的hash。具体来说,叶节点的hash是由存储在那里的数据块(例如文件或文件的部分)生成的,而非叶节点的hash是由其子节点的hash生成的。如果Merkle树只有一个节点(也就是根节......
  • 数据结构之线性表
    线性表之顺序存储:1sqlist.h2#ifndef_SQLIST_H3#define_SQLIST_H45#defineMAX_SIZE66typedefstruct7{8intdata[MAX_SIZE];9intlast;10}sqlist,*sqlink;1112voidcreatList(sqlinkL);//建空表13intgetLength......
  • 数据结构-队列
    一、概念1、队列的定义队列是仅限在一端进行插入,另一端进行删除的线性表。队列又被称为先进先出(FirstInFirstOut)的线性表,简称FIFO。2、队首允许进行元素删除的一端称为队首3、队尾允许进行元素插入的一端称为队尾二、接口1、可写接口(1)数据入队队列的插入操作,叫做入队。它是......