二叉树的线索化
来源:互联网 发布:知乎气功 编辑:程序博客网 时间:2024/06/06 00:53
什么是线索化
在前面二叉树的遍历中我们可以了解到,二叉树的先序、中序、后序、层序遍历,所以我们都知道当以二叉树链表作为存储结构时,只能找到结点的左、右孩子信息,而不能直接得到结点在任一序列中的前驱和后继信息,这种信息只有在遍历的动态过程中才能得到。
所以我们能想到的最简单的办法是在每个结点上增加两个指针雨fwd和bkwd,分别指示结点在任一序列遍历时得到的前驱和后继信息。这样可以大大降低存储空间密度;另一方面,在有n个结点的二叉链表中必定存在n+1个空指针域,由此就可以存放它的前驱和后继的信息。
所以:若结点有左子树,则其lchild域指示器左孩子,否则令lchild域指示其前驱;若结点有右子树,则其rchild域指示其右孩子,否则令rchild域指示其后继。为此增加了两个标志域:
以这种结点结构构成的二叉链表作为二叉树的存储结构,叫做线索链表;
构建线索化二叉树
先序构建线索化二叉树:
我们在构建结点的时候,所有用来标记线索化的指针域全部设为LINK;所以,在构建线索化二叉树时,需要将线索化的结点改为THREAD,其实在构建二叉树的时候就是找到所有的叶子结点,然后进行修改,前驱在寻找的时候只需要将结点的上一个结点保存起来,到时候用前驱指向就可以了,后继就比较困难了;下图可以看到,prev的后继就是pRoot 所以:
以下是先序构建线索二叉树的代码:
enum PointFlag{LINK, THREAD}; //LINK表示结点,THREAD表示线索化template<class T>struct BinaryTreeNodeThd { BinaryTreeNodeThd(const T& data) : _data(data) , _pLeft(NULL) , _pRight(NULL) , _parent(NULL) , _leftThread(LINK) , _rightThread(LINK) {} T _data; BinaryTreeNodeThd<T>* _pLeft; BinaryTreeNodeThd<T>* _pRight; BinaryTreeNodeThd<T>* _parent; PointFlag _leftThread; PointFlag _rightThread;};void _PreThreading(Node* pRoot, Node*& Prev) { if (NULL != pRoot) { //遍历根结点 if (NULL == pRoot->_pLeft)//找到最左边的结点 { pRoot->_pLeft = Prev; //将前驱赋给它 pRoot->_leftThread = THREAD; //将它的改为THREAD } if (Prev && Prev->_pRight == NULL) //Prev是pRoot的前一个结点, 前驱就用两者的关系解决 { Prev->_pRight = pRoot; Prev->_rightThread = THREAD; } Prev = pRoot; //将Prev的值修改掉 //递归遍历左子树 if (pRoot->_leftThread == LINK) _PreThreading(pRoot->_pLeft, Prev); //递归遍历右子树 if (pRoot->_rightThread == LINK) _PreThreading(pRoot->_pRight, Prev); } }
完整版代码:
#include<iostream>using namespace std;enum PointFlag{LINK, THREAD}; //LINK表示结点,THREAD表示线索化template<class T>struct BinaryTreeNodeThd { BinaryTreeNodeThd(const T& data) : _data(data) , _pLeft(NULL) , _pRight(NULL) , _parent(NULL) , _leftThread(LINK) , _rightThread(LINK) {} T _data; BinaryTreeNodeThd<T>* _pLeft; BinaryTreeNodeThd<T>* _pRight; BinaryTreeNodeThd<T>* _parent; PointFlag _leftThread; PointFlag _rightThread;};template<class T>class BinaryTreeThd{ typedef BinaryTreeNodeThd<T> Node;public: BinaryTreeThd() : _pRoot(NULL) {} BinaryTreeThd(const T array[], size_t size, const T& invalid) { size_t idx = 0; Node* parent = NULL; _CreatTree(_pRoot, array, size, idx, invalid, parent); } void PreThreading() //前序构建线索二叉树 { Node* prev = NULL; _PreThreading(_pRoot, prev); } void InThreading() //中序构建线索二叉树 { Node* prev = NULL; _InThreading(_pRoot, prev); } void PostThreading() //后序构建线索二叉树 { Node* prev = NULL; _PostThreading(_pRoot, prev); } void PreOrder() { Node* pCur = _pRoot; while (pCur) { while (pCur->_leftThread == LINK) { cout << pCur->_data << " "; pCur = pCur->_pLeft; } cout << pCur->_data << " "; pCur = pCur->_pRight;/* while (pCur->_rightThread == THREAD) { pCur = pCur->_pRight; cout << pCur->_data << " "; } if (pCur->_leftThread == LINK) pCur = pCur->_pLeft; else pCur = pCur->_pRight;*/ } } void InOrder() { Node* pCur = _pRoot; while (pCur) { while (pCur->_leftThread == LINK) { pCur = pCur->_pLeft; } cout << pCur->_data << " "; while (pCur && pCur->_rightThread == THREAD) { pCur = pCur->_pRight; if (pCur) cout << pCur->_data << " "; } if (pCur) pCur = pCur->_pRight; } } void PostOrder() { Node* pCur = _pRoot; Node* prev = NULL; while (pCur) { while (pCur->_pLeft != prev && pCur->_leftThread == LINK)//找到最左边的结点 pCur = pCur->_pLeft; while (pCur && pCur->_rightThread == THREAD)//判断结点的右子树是否为线索 { cout << pCur->_data << " "; prev = pCur; pCur = pCur->_pRight; } if (_pRoot == pCur) //判断是否为根结点, 左单只的情况 { cout << pCur->_data << endl; return; } while (pCur && pCur->_pRight == prev) { cout << pCur->_data << " "; prev = pCur; pCur = pCur->_parent; } if (pCur && pCur->_rightThread == LINK) pCur = pCur->_pRight; } }private: void _CreatTree(Node*& pRoot, const T array[], size_t size, size_t &idx, const T& invalid, Node*& parent) { if (idx < size && array[idx] != invalid) { pRoot = new Node(array[idx]); pRoot->_parent = parent; _CreatTree(pRoot->_pLeft, array, size, ++idx, invalid, pRoot); _CreatTree(pRoot->_pRight, array, size, ++idx, invalid, pRoot); } } void _PreThreading(Node* pRoot, Node*& Prev) { if (NULL != pRoot) { //遍历根结点 if (NULL == pRoot->_pLeft)//找到最左边的结点 { pRoot->_pLeft = Prev; //将前驱赋给它 pRoot->_leftThread = THREAD; //将它的改为THREAD } if (Prev && Prev->_pRight == NULL) //Prev是pRoot的前一个结点, 前驱就用两者的关系解决 { Prev->_pRight = pRoot; Prev->_rightThread = THREAD; } Prev = pRoot; //将Prev的值修改掉 //递归遍历左子树 if (pRoot->_leftThread == LINK) _PreThreading(pRoot->_pLeft, Prev); //递归遍历右子树 if (pRoot->_rightThread == LINK) _PreThreading(pRoot->_pRight, Prev); } } void _InThreading(Node* pRoot, Node*& Prev) { if (pRoot != NULL) { _InThreading(pRoot->_pLeft, Prev); if (pRoot->_pLeft == NULL) { pRoot->_pLeft = Prev; pRoot->_leftThread = THREAD; } if (Prev && Prev->_pRight == NULL) { Prev->_pRight = pRoot; Prev->_rightThread = THREAD; } Prev = pRoot; if (pRoot->_rightThread == LINK) { _InThreading(pRoot->_pRight, Prev); } } } void _PostThreading(Node* pRoot, Node*& Prev) { if (pRoot) { _PostThreading(pRoot->_pLeft, Prev); _PostThreading(pRoot->_pRight, Prev); if (pRoot->_pLeft == NULL) { pRoot->_pLeft = Prev; pRoot->_leftThread = THREAD; } if (Prev && Prev->_pRight == NULL) { Prev->_pRight = pRoot; Prev->_rightThread = THREAD; } Prev = pRoot; } }private: Node* _pRoot;};void Test(){ char array[] = "124###35##6"; BinaryTreeThd<char> b(array, strlen(array), '#'); //b.PreThreading(); //b.InThreading(); b.PostThreading(); //b.PreOrder(); //b.InOrder(); b.PostOrder();}int main(){ Test(); return 0;}
阅读全文
0 0
- 线索二叉树的线索化算法
- 二叉树的线索化
- 二叉树的线索化
- 二叉树的线索化
- 二叉树的线索化
- 二叉树的线索化
- 二叉树的线索化
- 二叉树的线索化
- 二叉树的线索化
- 二叉树的线索化
- 二叉树的线索化
- 二叉树的线索化
- 二叉树的线索化
- 二叉树的线索化
- 二叉树的线索化
- 二叉树的线索化
- 二叉树的线索化
- 二叉树的线索化
- HARDFP ABI理解
- linux并发控制之顺序锁
- 【FRDM-KW41Z学习笔记】使用恩智浦测试工具评估FRDM-KW41Z开发板
- EA&UML日拱一卒--序列图(Sequence Diagram)::循环
- C#实现毫秒到格式化时间串
- 二叉树的线索化
- 第十五天
- VB中的val-SSD4
- linux查找日志技巧
- 写文件dat文件函数+另存为对话框使用+时间设定函数分析
- 调用系统相关功能
- Python 类代码编写基础
- AssetBundle资源包--1
- kafka常用命令