后序线索二叉树,数据结构之线索化二叉树

 2023-09-25 阅读 22 评论 0

摘要:线索化二叉树 在一些项目中需要频繁的遍历二叉树,但是二叉树的遍历比单链表的遍历复杂多了,并且递归总是会有额外开销。。。 能不能像链表那样方便的快速遍历二叉树呢? 后序线索二叉树? 线索化二叉树指的是将二叉树中的结点进行逻辑意义上的“重排列”&

线索化二叉树 

在一些项目中需要频繁的遍历二叉树,但是二叉树的遍历比单链表的遍历复杂多了,并且递归总是会有额外开销。。。

能不能像链表那样方便的快速遍历二叉树呢?

后序线索二叉树?

线索化二叉树指的是将二叉树中的结点进行逻辑意义上的“重排列”,使其可以线性的方式访问每一个结点。

二叉树线索化之后每个结点都有一个线性下标,通过这个下标可以快速访问结点,而不需要遍历二叉树。

这个感觉很像组织链表,但是大家要知道组织链表结点之间的先后关系是没有任何逻辑关系的,只是为了插入、删除等操作方便。

那么我们应该怎样线索化二叉树呢?方法有二:

线索化方法1

线索二叉树删除算法,利用结点中的空指针域,使其指向后继结点。这也是教科书式的方法,许多教科书都会这么讲。


算法思想:

1.初始化位置指针p = NULL;

2.前序遍历二叉树:

线索二叉树怎么理解、    2.1.若p不为空,将p->left指向当前结点,并将p置为NULL;

    2.2.若当前结点的左子树为空时,将p指向当前结点。

由以上算法我们可知,线索化的实质就是将二叉链表中的空指针改为指向前驱或后继的线索,而前驱或后继的信息只有在遍历才

能得到,因此线索化的过程即为在遍历的过程中修改空指针的过程。

实现代码如下:

// 通过空指针线索化二叉树
void thread_via_left(BTreeNode* root, BTreeNode** pp)
{// 入口参数合法性检查OKif( (root != NULL) && (pp != NULL) ){// 若pp不为空,将pp->left指向当前结点,并将pp置为NULLif( *pp != NULL ){(*pp)->left = root;*pp = NULL;}// 若当前结点的左子树为空时,将pp指向当前结点if( root->left == NULL ){*pp = root;}// 递归线索化(遍历)左右子树thread_via_left(root->left, pp);thread_via_left(root->right, pp);}
}

线索二叉树和二叉搜索树一样吗。既然是前序遍历,首先就得有前序遍历的框架,即1.访问根结点中的数据;2.前序遍历左子树;3.前序遍历右子树。

线索化方法2

利用线性表保存二叉树的遍历顺序。此方法异常简单。

 

中序遍历线索二叉树。算法思想:(感谢国嵌嵌入式工作者们)

1.初始化顺序表s1

2.前序遍历二叉树,遍历过程中将当前结点插入顺序表s1

实现代码如下:

// 通过顺序表线索化二叉树
void thread_via_list(BTreeNode* root, SeqList* list)
{// 入口参数合法性检查OKif( (root != NULL) && (list != NULL) ){// 在顺序表尾部插入顺序表,访问根结点数据SeqList_Insert(list, (SeqListNode*)root, SeqList_Length(list));// 线索化(前序遍历)左子树thread_via_list(root->left, list);// 线索化(前序遍历)右子树thread_via_list(root->right, list);}
}

测试验证代码如下:

int main(int argc, char *argv[])
{// 创建二叉树BTree* tree = BTree_Create();// 定义二叉树结点指针BTreeNode* current = NULL;BTreeNode* p = NULL;// 定义顺序表变量SeqList* list = NULL;// 定义循环变量int i = 0;// 定义二叉树内容struct Node n1 = {{NULL, NULL}, 'A'};struct Node n2 = {{NULL, NULL}, 'B'};struct Node n3 = {{NULL, NULL}, 'C'};struct Node n4 = {{NULL, NULL}, 'D'};struct Node n5 = {{NULL, NULL}, 'E'};struct Node n6 = {{NULL, NULL}, 'F'};// 插入二叉树BTree_Insert(tree, (BTreeNode*)&n1, 0, 0, 0);BTree_Insert(tree, (BTreeNode*)&n2, 0x00, 1, 0);BTree_Insert(tree, (BTreeNode*)&n3, 0x01, 1, 0);BTree_Insert(tree, (BTreeNode*)&n4, 0x00, 2, 0);BTree_Insert(tree, (BTreeNode*)&n5, 0x02, 2, 0);BTree_Insert(tree, (BTreeNode*)&n6, 0x02, 3, 0);// 显示整体二叉树printf("Full Tree: \n");BTree_Display(tree, printf_data, 4, '-');printf("Thread via List:\n");// 验证顺序表线索化二叉树list = SeqList_Create(BTree_Count(tree));thread_via_list(BTree_Root(tree), list);for(i=0; i<SeqList_Length(list); i++){printf("%c, ", ((struct Node*)SeqList_Get(list, i))->v);}printf("\n");// 验证结点空指针线索化二叉树printf("Thread via Left:\n");current = BTree_Root(tree);thread_via_left(current, &p);while( current != NULL ){printf("%c, ", ((struct Node*)current)->v);current = current->left;}printf("\n");// 销毁二叉树BTree_Destroy(tree);return 0;
}

二叉树的遍历图解例题。通过上面代码比较发现,利用结点空指针线索化的方法会破坏树的结构,同时,利用结点空指针线索化二叉树之后不能够再恢

复。当然上面的问题可以通过在树结点中加入一个线索化指针而得以解决,然而线索化指针的加入又会浪费内存空间,不够灵

活。链表线索化方法不会破化树的结构,不需要线索化时销毁链表即可;链表线索化方法可以很容易的以任何一种遍历顺序对二

叉树进行线索化 。

有的人会问第一种线索化二叉树是否可以实现其他遍历方法来实现,当然可以,不过由于会破坏二叉树结构,并且不能在复位且

画出二叉树的中序线索链表?会浪费内存空间,所以不再讲述。

线索化二叉树整体实现代码:线索化二叉树代码C实现



版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/4/94519.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息