精华内容
下载资源
问答
  • 线索二叉树应用实验 实验...线索二叉树是为了快速求解二叉树中结点在指定次序下的前驱和后继而将二叉链表中空的左右孩子指针分别改为指向其前驱和后继结点而得到的结构反映了运算对数据结构的设计的影响因此首先要了解
  • 数据结构 线索二叉树

    2014-04-27 15:06:01
    当以二叉链表作为储存结构时,只能找到结点的左右孩子的信息,而不能直接找到结点的前驱后继,所以我们在每个结点上增加两个指针域fwd和bawd,分别指示结点在任一次序遍历时得到的前驱后继信息。
  • 利用二叉树链表的空指针实现线索二叉树。 线索化: 若无左子树,则将其左指针指向其前驱结点; 若无右子树,则将其右指针指向其后继结点; 先序线索二叉树 **前序遍历:**1、2、4、5、3、6 中序线索二叉树(较为...

    在这里插入图片描述

    二叉树的遍历顺序

    在这里插入图片描述

    **前序遍历:**1、2、4、5、3、6

    **中序遍历:**4、2、5、1、6、3

    **后序遍历:**4、5、2、6、3、1

    线索二叉树

    利用二叉树链表的空指针实现线索二叉树。

    线索化:

    • 若无左子树,则将其左指针指向其前驱结点;
    • 若无右子树,则将其右指针指向其后继结点;

    先序线索二叉树

    **前序遍历:**1、2、4、5、3、6

    在这里插入图片描述

    中序线索二叉树(较为常用)

    **中序遍历:**4、2、5、1、6、3

    在这里插入图片描述

    中序遍历:第一个结点是最左侧结点,最后一个结点是最右边的结点。

    前驱结点:

    • 若左指针为线索,则其指向结点为前驱结点;
    • 若左指针为左孩子,则其左子树的最右侧结点为前驱结点。

    后继结点:

    • 若右指针为线索,则其指向结点为后驱结点;
    • 若右指针为右孩子,则其右子树的最左侧结点为后驱结点。
    void CreateInThread(ThreadTree T){
        ThreadTree pre = NULL;
        if(T!=NULL){
            InTread(T,pre);
            pre->rchild=NULL;
            pre->rtag=1;
        }
    }
    
    // 引用类型:需要对其进行修改
    void InTread(ThreadTree &p,ThreadTree &pre){
        // 传入参数 线索二叉树根结点、对应节点前驱结点
        if(p!=NULL){
            // 判断根结点是否为空
            InThread(p->lchild,pre);
            // 线索化,递归调用线索化左子树:左子树根结点及前驱结点
            if(p->lchikd==NULL){
                p->lchild=pre;
                p->ltag=1;
            }
            if(pre!=NULL && pre->rchild==NULL){
                pre->rchild=p;
                pre->rtag=1;
            }
            pre=p;
            InThread(p->rchild,pre);
        }
    }
    
     
    

    在这里插入图片描述

    带有头结点的中序线索二叉树:

    增加一个头结点

    • 左指针指向根结点;
    • 第一个遍历序列(4)左指针指向头结点;
    • 头结点的右指针指向最后一个遍历序列(3);
    • 遍历序列的最后一个结点(3)的右指针指向头结点。

    后序线索二叉树

    **后序遍历:**4、5、2、6、3、1

    在这里插入图片描述

    线索二叉树结点结构——线索链表

    增加两个标志位:

    在这里插入图片描述

    标 志 域 l ( r ) t a g = { 0 , l ( r ) c h i l d  域指示结点的左(右)孩子 1 , l ( r ) c h i l d  域指示结点的前驱(后继) 标志域l(r)tag=\begin{cases} 0, & \text{$l(r)child$ 域指示结点的左(右)孩子}\\ 1, & \text{$l(r)child$ 域指示结点的前驱(后继)} \end{cases} l(r)tag={0,1,l(r)child 域指示结点的左(右)孩子l(r)child 域指示结点的前驱(后继)

    typedef structure ThreadNode{
        ElemType data;
        structure ThreadNode *lchild, *rchild;
        int ltag,rtag;
    }ThreadNode,*ThreadTree;
    

    中序线索二叉树遍历

    1. 寻找第一个结点:

      // 从根结点出发,循环找到最左侧的结点
      ThreadNode *Firstnode(ThreadNode *p){
          while(p->ltag==0)
              p=p->lchild;
          return p;
      }
      
    2. 找到后继结点:

      ThreadNode *Nextnode(ThreadNode *p){
      	if(p->rtag==0)
              // tag为0为孩子结点,需要找到它右子树最左侧结点为后继
              return Firstnode(p->rchild);
          else
              // tag为1为先做点,右指针就是后继结点
              return p->rchild;
      }
      
    3. 循环调用寻找后继节点的函数:

      void InOrder(ThreadNode *T){
          for(ThreadNode *p=Firstnode(T);p!=NULL;p=Nextnode(p))
              visit(p);
      }
      
    展开全文
  • C语言数据结构线索二叉树 tips:前些天学习了二叉树的相关操作,今天来总结一下线索二叉树的操作。 线索二叉树:对二叉树以某种次序遍历得到序列中的前驱和后继,其中指向结点前驱和后继的指针称为线索,再加上...

    C语言数据结构之线索二叉树

    tips:前些天学习了二叉树的相关操作,今天来总结一下线索二叉树的操作。


    线索二叉树:对二叉树以某种次序遍历得到序列中的前驱和后继,其中指向结点前驱和后继的指针称为线索,再加上线索的二叉树称之为线索二叉树。

    线索化:对二叉树以某种次序遍历使其变成线索二叉树的过程称为线索化
    注意:线索化是要基于一棵二叉树上线索化,所以我们要先建树!


    1、线索二叉树的存储结构

    lchildltagdatartagrchild

    其中,标志域的含义:

    ltag

    • 0:lchild域指示结点的左孩子;
    • 1:lchild域指示结点的前驱;

    rtag

    • 0:rchild域指示结点的右孩子;
    • 1:rchild域指示结点的后继;

    对应的线索二叉树结构体:

    typedef struct node
    {
    	char c;//结点的数据
    	struct node *left;//左指针
    	struct node *right;//右指针
    	int ltag, rtag;//标志域,为0表示有左右孩子,为1表示指向其前趋或后继
    
    }Node, *pNode;
    

    相比普通的二叉树,线索二叉树多了标志域,标志域的值及其含义如上。


    2、中序线索二叉树的构建

    思路:

    • 按照中序遍历序列,将树结点指针中序线索化;
    • 若结点有左右孩子,则标志域为0,指针域指向左右孩子;
    • 若结点无左右孩子,则标志域为1,指针指向其中序序列的前驱和后继;

    这里可以用一个辅助指针pre,来记录递归时正在访问的结点的前驱结点。
    在中序遍历时,若当前正在访问的结点左指针为空,就将其左指针指向pre;
    若pre的右指针为空,则将其右指针指向当前结点;

    注意,这里我们要在子函数修改在主函数声明的tree和pre的值,所以这里我们在子函数中传入tree和pre的地址!

    具体实现:

    //二叉树的中序线索化,参数是当前结点及前趋结点
    //二叉树的中序线索化,参数是根结点及前趋结点
    void InThread(pNode *tree,pNode *pre)
    {
    	if (*tree != NULL)
    	{
    		InThread((&(*tree)->left),pre);//中序遍历先找到最左侧的子树
    		if ((*tree)->left == NULL)//左子树为空,则前趋指向前一个结点(左指针线索化)
    		{
    			(*tree)->left = *pre;
    			(*tree)->ltag = 1;//修改左标志域的值
    		}
    		if (*pre != NULL && (*pre)->right == NULL)//右子树为空,则由pre将右指针线索化(这里是返回上一层,现在的根结点就变成了上一层的还未线索化的右指针的后继)(右指针线索化)
    		{
    			(*pre)->right = *tree;
    			(*pre)->rtag = 1;//修改右标志域的值
    		}
    		*pre = (*tree);//pre跟着tree走,记录tree的中序前趋结点
    
    		InThread(&((*tree)->right),pre);//中序遍历先找到最右侧的子树
    	}
    }
    
    //创建中序线索化二叉树
    void CreateInThread(pNode *tree)
    {
    	pNode pre = NULL;
    
    	if (tree != NULL)
    	{
    		//将最右侧的结点右指针手动线索化
    		InThread(tree, &pre);
    		pre->right = NULL;
    		pre->rtag = 1;
    	}
    }
    

    3、中序线索二叉树的遍历

    思路:

    • 先寻找中序线索二叉树中序序列第一个结点(最左侧的结点);
    • 寻找中序线索二叉树结点的后继结点;
    • 循环遍历中序线索二叉树;

    具体实现:

    //中序线索二叉树的遍历
    pNode Firstnode(pNode tree)//找中序线索化开始的结点(最左侧的结点)
    {
    	pNode pcur = tree;
    	while (pcur->ltag == 0)
    		pcur = pcur->left;
    	return pcur;
    }
    pNode Nextnode(pNode p)//找中序线索化条件下,p结点的后继结点
    {
    	if (p->rtag == 0)//标记位为0,指向孩子(右子树最左侧的结点)
    			return Firstnode(p->right);
    	else
    		return p->right;//标记位为1,指向后继结点
    }
    void Inorder(pNode tree)//遍历中序线索二叉树
    {
    	for (pNode p = Firstnode(tree); p != NULL; p = Nextnode(p))
    		printf("%c", p->c);
    }
    

    至此,中序线索二叉树的创建以及遍历已经完成。我们在main()函数中测试一下:

    int main()
    {
    	//准备建树的元素,0号下标不存元素
    	char c[N] = { ' ','A','B','C','D','E','F','G','H','I','J' };
    
    	pNode p[N];//树的结点
    	pNode tree;//根结点
    	InitBiTree(p, c);//初始化树
    	
    	CreateBitree(p);//层次建树
    
    	tree = p[1];//1号结点作为根结点
    
    	printf("二叉树的中序遍历:");
    	midorder(tree);
    	printf("\n");
    	
    	//将二叉树中序线索化
    	CreateInThread(&tree);//创建中序线索二叉树
    	printf("---------------------------------------\n");
    	
    	printf("tree->c=%c\n", tree->c);
    	
    	printf("---------------------------------------\n");
    
    	printf("中序线索二叉树遍历:");
    	Inorder(tree);//遍历中序线索二叉树
    	printf("\n");
    	
    	return 0;
    }
    

    测试结果:
    在这里插入图片描述
    可以看到二叉树的中序遍历结果与中序线索二叉树遍历结果相同!


    tips:人生就像赛跑,不在乎你是否第一个到达终点,而在乎你有没有跑完全程。
    展开全文
  • 数据结构 线索二叉树 严蔚敏 数据结构 线索二叉树 严蔚敏 数据结构 线索二叉树 严蔚敏 数据结构 线索二叉树 严蔚敏 数据结构 线索二叉树 严蔚敏 数据结构 线索二叉树 严蔚敏
  • 二叉树的链式存储时会有较多空间的浪费,当一颗有 n 个节点的二叉树存储共有2n个指针域,但是只有n-1个被用到,所以剩下的n+1个都会被浪费掉,因此可以想一种办法把剩余的空间利用起来,线索二叉树应运而生。...

    二叉树的链式存储时会有较多空间的浪费,当一颗有 n 个节点的二叉树存储共有2n个指针域,但是只有n-1个被用到,所以剩下的n+1个都会被浪费掉,因此可以想一种办法把剩余的空间利用起来,线索二叉树应运而生。
    将二叉树重新定义如下每个节点为下列形式
    lchild ltag data rtag rchild
    其中:ltag=0 时lchild指向左子女;
    ltag=1 时lchild指向前驱;
    rtag=0 时rchild指向右子女;
    rtag=1 时rchild指向后继;
    所以结构体可定义为:

    typedef enum{
    	Link,//枚举,第一个默认为0,后面的自动 +1
    	Thread
    }PointerTag;
    
    typedef struct Tree_Node{
    	char ch;
    	struct Tree_Node *left;
    	struct Tree_Node *right;
    	PointerTag ltag;
    	PointerTag rtag;
    	
    }Tree;
    
    

    中序线索化

    //中序线索化并实现打印
    void midThread(Tree *tree){
    	if(tree){
    		midThread(tree->left);
    		printf("%c ",tree->ch);
    		if(!tree->left){
    			tree->ltag = Thread;
    			tree->left = pre;
    		}
    		if(!tree->right)
    		tree->rtag = Thread;
    		if(pre && pre->rtag == Thread) {
    			pre->right = tree;
    		}
    		pre = tree;
    		midThread(tree->right);
    	}
    } 
    

    后序线索化

    void end(Tree *tree){
    	if(tree){
    		end(tree->left);
    		end(tree->right);
    		printf("%c ",tree->ch);
    		if(!tree->left){
    			tree->ltag = Thread;
    			tree->left = pre;
    		}
    		if(!tree->right)
    		tree->rtag = Thread;
    		if(pre && pre->rtag == Thread)
    		pre->right = tree;
    		pre = tree;
    	}
    }
    

    完整代码如下

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef enum{
    	Link,
    	Thread
    }PointerTag;
    
    typedef struct Tree_Node{
    	struct Tree_Node *left;
    	struct Tree_Node *right;
    	char ch;
    	PointerTag ltag;
    	PointerTag rtag;
    }Tree;
    
    Tree *pre;
    
    Tree *create(){
    	Tree *tree;
    	char ch;
    	scanf("%c",&ch);
    	if(ch == '*')
    	tree = NULL;
    	else{
    		tree = (Tree *)malloc(sizeof(Tree));
    		tree->ch = ch;
    		tree->left = create();
    		tree->right = create();
    	}
    	return tree;
    }
    
    void midThread(Tree *tree){
    	if(tree){
    		midThread(tree->left);
    		printf("%c ",tree->ch);
    		if(!tree->left){
    			tree->ltag = Thread;
    			tree->left = pre;
    		}
    		if(!tree->right)
    		tree->rtag = Thread;
    		if(pre && pre->rtag == Thread)
    		pre->right = tree;
    		pre = tree;
    		midThread(tree->right);
    	}
    }
    
    
    
    void end(Tree *tree){
    	if(tree){
    		end(tree->left);
    		end(tree->right);
    		printf("%c ",tree->ch);
    		if(!tree->left){
    			tree->ltag = Thread;
    			tree->left = pre;
    		}
    		if(!tree->right)
    		tree->rtag = Thread;
    		if(pre && pre->rtag == Thread)
    		pre->right = tree;
    		pre = tree;
    	}
    }
    int main(){
    	Tree *tree = create();
    	midThread(tree); 
    	//end(tree);//调用时只能一个一个调用
    }
    
    
    展开全文
  • 数据结构-线索二叉树

    2019-08-13 16:30:31
    遍历二叉树是按一定的规则将二叉树中所有结点排列为一个有序序列,这实质上是对一个非线性的数据结构进行线性化的操作。经过遍历的结点序列,除第一个结点和最后一个结点以外,其余每个结点都有且仅有一个直接前驱...

    线索二叉树
    1.什么是线索二叉树
    遍历二叉树是按一定的规则将二叉树中所有结点排列为一个有序序列,这实质上是对一个非线性的数据结构进行线性化的操作。经过遍历的结点序列,除第一个结点和最后一个结点以外,其余每个结点都有且仅有一个直接前驱结点和一个直接后继结点。
    当以二叉链表作为存储结构时,只能找到结点的左、右孩子的信息,而不能直接得到结点任意一个序列中的直接前驱结点和直接后继结点是什么,这种信息只有在对二叉树遍历的动态过程中才能得到。若增加前驱指针和后继指针将使存储密度进一步降低。
    在用二叉链表存储的二叉树中,单个结点的二叉树有两个空指针域;两个结点的二叉树有三个空指针域。
    不难证明:n个结点的二叉树有n+1个空指针域。也就是说,一个具有n个结点的二叉树,若采用二叉链表存储结构,在其总共2n个指针域中只有n-1个指针域是用于存储结点子树的地址,而另外n+1个指针域存放的都是∧(空指针域)。因此,可以充分利用二叉链表存储结构中的那些空指针域,来保存结点在某种遍历序列中的直接前驱结点和直接后继结点的地址信息。
    指向直接前驱结点或指向直接后继结点的指针称为线索(thread),带有线索的二叉树称为线索二叉树。对于二叉树以某种次序遍历使其变为线索二叉树的过程称为线索化。
    2.线索二叉树的方法
    由于二叉树结点的序列可由不同的遍历方法得到,因此,线索二叉树也分为先序线索二叉树、中序线索二叉树和后序线索二叉树三种。在三种线索二叉树中一般以中序线索化用得最多,所以下面以图6-10所示的二叉树为例,说明中序线索二叉树的方法。中序线索二叉树的具体步骤如下。
    (1)先写出原二叉树的中序遍历序列:DGBAECHF。
    (2)若结点的左子树为空,则此线索指针将指向前一个遍历次序的结点。
    (3)若结点的右子树为空,则此线索指针将指向下一个遍历次序的结点。

    线索二叉树的结点结构定义如下。
    typedef struct threadbinode
    {
    datatype data; //二叉链表的结点
    bool ltag; //左孩子标志,当ltag为true时,表示左孩子存在(lchild所指为该结点左
    孩子);反之,则表示左孩子不存在(lchild所指为该结点直接后继结点)
    struct threadbinode lchild; //左孩子指针
    bool rtag; //其含义与ltag类似
    struct threadbinode rchild; //右孩子指针
    }ThreadBiNode; //二叉链表结点的类型
    二叉树进行中序线索化的递归函数代码如下。
    void InThreadBiTree(ThreadBiNode *T, ThreadBiNode *pre,ThreadBiNode *
    rear)
    { //pre指向整个二叉树T中序序列的直接前驱节点
    //rear指向整个二叉树T中序序列的直接后继节点
    if(trueT-> ltag)
    InThreadBiTree(T-> lchild,pre,T);
    //左子树的直接前驱结点就是整棵二叉树的直接前驱结点,左子树的直接后继结点就是整棵
    二叉树的根结点
    else
    T-> lchild=pre;
    if(true
    T-> rtag)
    InThreadBiTree(T-> rchild,T,rear);
    //右子树的直接前驱结点就是整棵二叉树的根结点,右子树的直接后继结点就是整棵二叉树
    的直接后继结点
    else
    T-> rchild=rear;
    }
    由于整棵二叉树中序序列的直接前驱结点和直接后继结点均可为空,因此对二叉树T进行中序线索化可采用语句InThreadBiTree(T,NULL,NULL)。
    另外,为了便于操作,在存储线索二叉树时需要增设一个结点,其结构与其他线索二叉树的结点结构一样。但是头结点的数据域不存放信息,它的左指针域指向二叉树的根结点,右指针域指向自己。而原二叉树在某种序列遍历下的第一个结点的前驱线索和最后一个结点的后继线索都指向头结点。
    3.线索二叉树的优点
    (1)利用线索二叉树进行中序遍历时,不必采用堆栈处理,速度比一般二叉树的遍历速度快,并且节约存储空间。
    (2)任意一个结点都能直接找到它相应遍历顺序的直接前驱结点和直接后继结点。
    4.线索二叉树的缺点
    (1)结点的插入和删除较麻烦,并且速度也比较慢。
    (2)线索子树不能共用。

    展开全文
  • 一、线索二叉树的概念 在二叉树的链式存储结构中,增加指向前趋和后续结点的信息,称为线索。加上线索的二叉树称为线索二叉树。对二叉树以某种次序进行遍历使其成为线索二叉树的过程称为线索化。 二、线索化二叉树...
  • 初入数据结构线索二叉树以及Java代码实现 前提概念 Java代码实现 前提概念 什么是线索二叉树? 我们知道二叉树的是一棵树的度小于等于2的有序树;那么线索二叉树又是什么呢?线索二叉树实际是一...
  • 数据结构 线索二叉树 原理及实现

    千次阅读 2014-11-16 15:58:00
    通过考察各种二叉链表,不管儿叉树的形态如何,空链域的个数总是多过非空链域的个数。准确的说,n各结点的二叉链表共有2n个链域,... 记ptr指向二叉链表中的一个结点,以下是建立线索的规则:  (1)如果ptr->lc
  • 数据结构 代码实现 #include "string.h" #include "stdio.h" #include "stdlib.h" #include "io.h" #include "math.h" #include "time.h" #define OK 1 #define ERROR 0 #define TRUE 1 #defi
  • 线索二叉树 #include <stdio.h> #include <stdlib.h> typedef char ElemType; //线索存储标志位 //Link(0):表示指向左右孩子的指针 //Thread(1):表示指向前驱后继的线索 typedef enum {Link,...
  • 数据结构线索二叉树

    千次阅读 2018-08-15 16:15:10
    数据结构线索二叉树 1.二叉链表中空间资源的浪费 我们利用节点建立了二叉链表,但是我们发现二叉链表中存在这许多空指针,那么这部分空间就被浪费了,我们应该想办法解决这个问题 假设有一个节点个数为...
  • 线索二叉树线索二叉树:前序遍历的线索二叉树:中序遍历的线索二叉树(常):后序遍历的线索二叉树线索二叉树的节点结构及代码实现:中序线索二叉树的构造:中序线索二叉树的遍历: 线索二叉树: 在实现一颗二叉树...
  • /* ******************************************************************************** * 数据结构 * * * * 作者: zhi-...
  • 主要介绍了C语言数据结构线索二叉树及其遍历的相关资料,为了加快查找节点的前驱和后继。对二叉树的线索化就是对二叉树进行一次遍历,在遍历的过程中检测节点的左右指针是否为空,如果是空,则将他们改为指向前驱和...
  • 线索二叉树的基本概念线索、构造、存储结构; 中、先、后序遍历结构图;画出线索二叉树,以及二叉树线索化的代码实现。
  • 线索二叉树简单来说就是利用原来的指针域通过标记区分将每个节点的直接前驱和后继结点记录下来,这个记录下前后结点的过程就叫线索化,线索化后的二叉树就是线索二叉树。 主要写了前序、中序、后序三种方法的线索...
  • 在二叉树的结点上加上线索的二叉树称为线索二叉树,对二叉树以某种遍历方式(如先序、中序、后序或层次等)进行遍历,使其变为线索二叉树的过程称为对二叉树进行线索化。 文章目录一、c语言实现先序线索、中序线索、...
  • 线索二叉树 数据结构 categories: 数据结构学习笔记 文章目录构建规则存储结构类型定义中序搜索二叉树示意图构建中序线索二叉树线索构造过程算法设计中序遍历线索二叉树遍历规则寻找开始结点算法遍历过程遍历算法...
  • 利用二叉链表的空地址,存放指向结点在某种遍历下(不同的遍历方法,前驱和后继不同)的前驱和后继的地址,我们把这种指向前驱和后继的指针称为线索,加上线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树 ...
  • 二叉树是另一种树形结构,其特点是每个结点最多含两棵子树(也就是说,二叉树的度≤2)。 二叉树是一种有序树,若将其左、右子树颠倒,则成为另一颗不同的二叉树二叉树可以为空 1.2 二叉树和度为2的有序树 在...
  • 这篇文章我们接着讲二叉树。... 线索二叉树的定义3. 二叉树的线索化1. 二叉树的线索化代码实现4. 线索二叉树的基本运算 1. 二叉树遍历–先序遍历、中序遍历、后序遍历和层次遍历 所谓二叉树的遍历,是指...
  • 线索二叉树 思考:在有n个节点的二叉链表中必定有n+1个空链域(下面会说为什么),遍历运算是最重要也是最常用的运算,之前的无论递归与非递归算法实现遍历效率都不算高。能不能利用这未使用的n+1空指针域,设计出...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 9,514
精华内容 3,805
关键字:

数据结构线索二叉树

数据结构 订阅
友情链接: Mohujulei.rar