数据结构-线索二叉树(中序线索二叉树及遍历)

2024-03-08 13:08

本文主要是介绍数据结构-线索二叉树(中序线索二叉树及遍历),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.二叉树线索化

    二叉树的遍历是按照一定的规则把二叉树中的节点按照一定的次序排列成线性序列进行访问的,实质上就是对一个非线性结构进行线索化操作,使得每个节点(除第一个和最后一个外)都有前驱后继节点,有时为了运算方便需要记录这些前驱和后继节点,称为二叉树线索化,而对于不同的遍历规则,又分为先序线索二叉树中序线索二叉树后序线索二叉树

2.线索二叉树的定义

    (1)思路:

            一颗具有n个节点的二叉树,有n-1条指向左孩子或右孩子的分支,对于二叉链表来说,2n个指针只用了n-1个,所以可以利用另外n+1个指针作为指向前驱节点和后继节点的指针

    (2)前驱节点和后继节点

            有些书籍对这两个概念并没有简单明了的解释~,其实就是对于特定遍历方式来说,一个节点的前后节点

            ①前驱节点:

                                指定遍历方式得出的节点访问顺序中,某一节点的前一个节点。

            ②后继节点

                                指定遍历方式得出的节点访问顺序中,某一节点的后一个节点。

    (3)线索二叉树的节点表示(结构体)-线索链表(Thread Linked List)

#define Link	0	//表示该节点有非空孩子节点
#define Thread	1	//表示该节点有后续节点(对于右子树来说)template<class T>
struct BT_Thread_Node
{T Data;BT_Thread_Node* Left_Child;BT_Thread_Node* Right_Child;int Ltag;int Rtag;
};

         Ltag=0(Link)-表示Left_Child的指针指向左孩子节点;Ltag=1(Thread)-表示Left_Child的指针指向前驱节点

         Rtag=0(Link)-表示Right_Child的指针指向右孩子节点;Rtag=1(Thread)-表示Right_Child的指针指向后继节点

    (4)线索化规则(重点)

            书上也是奇奇怪怪的,其实很简单,就按照某一遍历规则,记录当前节点(Cur),上一次访问的节点(Pre)

             ①如果当前节点Cur->Left_Child=NULL(左孩子节点空),则Cur->Left_Child=Pre;Cur->Ltag=1(左指针域指向前驱节点(前一个节点Pre),修改Ltag为线索模式

            ②如果前一节点Pre->Right_Child=NULL(前节点的右孩子节点空),则Pre->Right_Child=Cur;Pre->Rtag=1(前节点的右指针域指向后继节点(也就是当前节点),修改Rtag为线索模式

3.中序线索二叉树

    (1)线索化中序二叉树


    (2)中序线索化实现

template<class T>
void Thread_Binary_tree<T>::InOrder_Thread_Op(BT_Thread_Node<T>* &Tree)
{if (Tree == NULL)		//空返回上一节点return;InOrder_Thread_Op(Tree->Left_Child);		//左if (Tree->Left_Child == NULL)			//根{Tree->Ltag = Thread;Tree->Left_Child = Pre_Node;}if (Pre_Node != NULL && Pre_Node->Right_Child == NULL){Pre_Node->Rtag = Thread;Pre_Node->Right_Child = Tree;}Pre_Node = Tree;InOrder_Thread_Op(Tree->Right_Child);		//右
}

    注:Pre_Node是类内数据成员,初始化为NULL

    (3)线索化遍历

            ①思路:

                   对于中序遍历来说,先查找线索链表的第一个节点,也就是最左方向上的最后一个节点,然后如果有右线索先寻找后继节点,查找到断线索(有右节点啦)就往下找一个右节点,继续这样摸下去,其实说到底就是有线索先按线索找(注意线索上的节点是需要访问的),等到线索断了就往下找右孩子节点。

            ②实现代码
template<class T>
void Thread_Binary_tree<T>::_InOrder_Op(BT_Thread_Node<T>* &Tree)
{if (Tree == NULL)return;BT_Thread_Node<T>* Cur_Node = Tree;while (Cur_Node)			//当前节点不能为空{while (Cur_Node->Ltag == Link)		//节点有左树时,寻找最左端的树{Cur_Node = Cur_Node->Left_Child;}cout << Cur_Node->Data << " ";while (Cur_Node&&Cur_Node->Rtag == Thread)	//节点非空并且右树是线索树时查找最前的一个线索树节点{Cur_Node = Cur_Node->Right_Child;cout << Cur_Node->Data << " ";}Cur_Node = Cur_Node->Right_Child;		//右树不是线索树,查找该节点的右孩子节点}cout << endl;
}

    (4)二叉树的析构(利用线索)

               ①思路:

                    当把树线索化了,其实就是链表,而删除呢,我觉得按链表删就ok,但是后来发现脑子不好用,就想着按遍历的顺序,栈存节点,然后把栈清了就ok,所以再写了一个程序,写了才发现其实!可以直接在遍历的时候顺便入栈了节点,好吧这次先这样,等后面出先序和后序我再改吧~

               ②代码
BT_Thread_Node<T>* BT_Node_Stack[MAXSIZE];//类私有,MAXISIZE=100
template<class T>
int Thread_Binary_tree<T>::Distory_Thread_BTree(BT_Thread_Node<T>* &Tree)
{if(Tree==NULL)return 0;int Top = -1;BT_Thread_Node<T>* Cur_Node = Tree;while (Cur_Node){while (Cur_Node->Ltag == Link){Cur_Node = Cur_Node->Left_Child;}BT_Node_Stack[++Top] = Cur_Node;while (Cur_Node&&Cur_Node->Rtag == Thread){Cur_Node = Cur_Node->Right_Child;BT_Node_Stack[++Top] = Cur_Node;}Cur_Node = Cur_Node->Right_Child;}for (Top; Top != -1; Top--){cout << BT_Node_Stack[Top]->Data;delete BT_Node_Stack[Top];}return 1;
}

    


    (5)中序线索树类实现

#include<iostream>
using namespace std;
#define Link	0	//表示该节点有非空孩子节点
#define Thread	1	//表示该节点有后续节点(对于右子树来说)
#define MAXSIZE  100template<class T>
struct BT_Thread_Node
{T Data;BT_Thread_Node* Left_Child;BT_Thread_Node* Right_Child;int Ltag;int Rtag;
};template<class T>
class Thread_Binary_tree
{
private:BT_Thread_Node<T>* Tree;BT_Thread_Node<T>* Pre_Node;BT_Thread_Node<T>* BT_Node_Stack[MAXSIZE];int Create_Thread_BTree(BT_Thread_Node<T>* &Tree);int Distory_Thread_BTree(BT_Thread_Node<T>* &Tree);void InOrder_Thread_Op(BT_Thread_Node<T>* &Tree);void _InOrder_Op(BT_Thread_Node<T>* &Tree);
public:Thread_Binary_tree();~Thread_Binary_tree();void InOrder_Thread();void _InOrder();
};template<class T>
int Thread_Binary_tree<T>::Create_Thread_BTree(BT_Thread_Node<T>* &Tree)
{int Data;cin >> Data;if (Data == -1)Tree = NULL;else{Tree = new BT_Thread_Node<T>;Tree->Data = Data;Tree->Ltag = Link;Tree->Rtag = Link;Create_Thread_BTree(Tree->Left_Child);Create_Thread_BTree(Tree->Right_Child);}return 1;
}template<class T>
int Thread_Binary_tree<T>::Distory_Thread_BTree(BT_Thread_Node<T>* &Tree)
{if(Tree==NULL)return 0;int Top = -1;BT_Thread_Node<T>* Cur_Node = Tree;while (Cur_Node){while (Cur_Node->Ltag == Link){Cur_Node = Cur_Node->Left_Child;}BT_Node_Stack[++Top] = Cur_Node;while (Cur_Node&&Cur_Node->Rtag == Thread){Cur_Node = Cur_Node->Right_Child;BT_Node_Stack[++Top] = Cur_Node;}Cur_Node = Cur_Node->Right_Child;}for (Top; Top != -1; Top--){cout << BT_Node_Stack[Top]->Data;delete BT_Node_Stack[Top];}return 1;
}template<class T>
void Thread_Binary_tree<T>::InOrder_Thread_Op(BT_Thread_Node<T>* &Tree)
{if (Tree == NULL)		//空返回上一节点return;InOrder_Thread_Op(Tree->Left_Child);		//左if (Tree->Left_Child == NULL)			//根{Tree->Ltag = Thread;Tree->Left_Child = Pre_Node;}if (Pre_Node != NULL && Pre_Node->Right_Child == NULL){Pre_Node->Rtag = Thread;Pre_Node->Right_Child = Tree;}Pre_Node = Tree;InOrder_Thread_Op(Tree->Right_Child);		//右
}template<class T>
void Thread_Binary_tree<T>::_InOrder_Op(BT_Thread_Node<T>* &Tree)
{if (Tree == NULL)return;BT_Thread_Node<T>* Cur_Node = Tree;while (Cur_Node)			//当前节点不能为空{while (Cur_Node->Ltag == Link)		//节点有左树时,寻找最左端的树{Cur_Node = Cur_Node->Left_Child;}cout << Cur_Node->Data << " ";while (Cur_Node&&Cur_Node->Rtag == Thread)	//节点非空并且右树是线索树时查找最前的一个线索树节点{Cur_Node = Cur_Node->Right_Child;cout << Cur_Node->Data << " ";}Cur_Node = Cur_Node->Right_Child;		//右树不是线索树,查找该节点的右孩子节点}cout << endl;
}template<class T>
Thread_Binary_tree<T>::Thread_Binary_tree():Pre_Node(NULL)
{Create_Thread_BTree(Tree);
}template<class T>
Thread_Binary_tree<T>::~Thread_Binary_tree()
{Distory_Thread_BTree(Tree);
}template<class T>
void Thread_Binary_tree<T>::InOrder_Thread()
{InOrder_Thread_Op(Tree);Pre_Node = NULL;		//恢复值为空,便于下次线索化
}template<class T>
void Thread_Binary_tree<T>::_InOrder()
{_InOrder_Op(Tree);
}

这篇关于数据结构-线索二叉树(中序线索二叉树及遍历)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/787181

相关文章

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

《数据结构(C语言版)第二版》第八章-排序(8.3-交换排序、8.4-选择排序)

8.3 交换排序 8.3.1 冒泡排序 【算法特点】 (1) 稳定排序。 (2) 可用于链式存储结构。 (3) 移动记录次数较多,算法平均时间性能比直接插入排序差。当初始记录无序,n较大时, 此算法不宜采用。 #include <stdio.h>#include <stdlib.h>#define MAXSIZE 26typedef int KeyType;typedef char In

leetcode105 从前序与中序遍历序列构造二叉树

根据一棵树的前序遍历与中序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 例如,给出 前序遍历 preorder = [3,9,20,15,7]中序遍历 inorder = [9,3,15,20,7] 返回如下的二叉树: 3/ \9 20/ \15 7   class Solution {public TreeNode buildTree(int[] pr

【408数据结构】散列 (哈希)知识点集合复习考点题目

苏泽  “弃工从研”的路上很孤独,于是我记下了些许笔记相伴,希望能够帮助到大家    知识点 1. 散列查找 散列查找是一种高效的查找方法,它通过散列函数将关键字映射到数组的一个位置,从而实现快速查找。这种方法的时间复杂度平均为(

PHP实现二叉树遍历(非递归方式,栈模拟实现)

二叉树定义是这样的:一棵非空的二叉树由根结点及左、右子树这三个基本部分组成,根据节点的访问位置不同有三种遍历方式: ① NLR:前序遍历(PreorderTraversal亦称(先序遍历)) ——访问结点的操作发生在遍历其左右子树之前。 ② LNR:中序遍历(InorderTraversal) ——访问结点的操作发生在遍历其左右子树之中(间)。 ③ LRN:后序遍历(PostorderT

浙大数据结构:树的定义与操作

四种遍历 #include<iostream>#include<queue>using namespace std;typedef struct treenode *BinTree;typedef BinTree position;typedef int ElementType;struct treenode{ElementType data;BinTree left;BinTre

Python 内置的一些数据结构

文章目录 1. 列表 (List)2. 元组 (Tuple)3. 字典 (Dictionary)4. 集合 (Set)5. 字符串 (String) Python 提供了几种内置的数据结构来存储和操作数据,每种都有其独特的特点和用途。下面是一些常用的数据结构及其简要说明: 1. 列表 (List) 列表是一种可变的有序集合,可以存放任意类型的数据。列表中的元素可以通过索

浙大数据结构:04-树7 二叉搜索树的操作集

这道题答案都在PPT上,所以先学会再写的话并不难。 1、BinTree Insert( BinTree BST, ElementType X ) 递归实现,小就进左子树,大就进右子树。 为空就新建结点插入。 BinTree Insert( BinTree BST, ElementType X ){if(!BST){BST=(BinTree)malloc(sizeof(struct TNo

【数据结构入门】排序算法之交换排序与归并排序

前言         在前一篇博客,我们学习了排序算法中的插入排序和选择排序,接下来我们将继续探索交换排序与归并排序,这两个排序都是重头戏,让我们接着往下看。  一、交换排序 1.1 冒泡排序 冒泡排序是一种简单的排序算法。 1.1.1 基本思想 它的基本思想是通过相邻元素的比较和交换,让较大的元素逐渐向右移动,从而将最大的元素移动到最右边。 动画演示: 1.1.2 具体步