本篇文章主要整理二叉树的先序和中序线索化,以及对线索树的两种遍历。
线索化的引入:
对于有n个节点的二叉树中,就会有n+1个空指针,导致空间的浪费。
推导:对于任何一棵二叉树,叶子节点也就是度为0的节点数为n0,度为2的节点数为
n2,则有n0 = n2+1。(总结点数为n)
n0+n1+n2 = n
n2+1 = n0.
两等式联立:2*n0+n1 = n+1.
所以我们引入了线索化二叉树,即就是对空指针域的充分利用。如果该结点有左右子树,
左右指针域指向其左右孩子,如果没有左子树(或者右子树),左指针域(或者
右指针域)指向其前驱(或者后继)。这里就需要有左右的标注,lTag和rTag。如果是
0,说明指向其孩子,如果是1,说明指向其前驱(或者后继)。
下边画图举例说明:
首先还是得先创建一棵二叉树,像前边的方法那样,递归完成。
先序线索化二叉树:
先序遍历先序线索二叉树:
中序线索化二叉树:
对于中序线索化,就是类似先序线索化了,只是根节点的访问时间不一样罢了。
这里就不给出图解了。文末将会给出全部代码~~~
中序遍历中序线索树:
下边给出实现代码:
#pragma once
#include<iostream>
using namespace std;
#include<assert.h>
enum Type
{
LINK,//指向孩子
THREAD//指向前驱或者后继
};
template<typename T>
struct BinaryTreeTNode
{
T _data;
BinaryTreeTNode* _lchild;
BinaryTreeTNode* _rchild;
Type _lTag;
Type _rTag;
BinaryTreeTNode(const T& x = T())
:_data(x)
,_lchild(NULL)
,_rchild(NULL)
,_lTag(LINK)
,_rTag(LINK)
{}
};
template<typename T>
class BinaryTreeThreading
{
typedef BinaryTreeTNode<T> Node;
public:
BinaryTreeThreading(T* a, size_t size, const T& invalid)
:_root(NULL)
,prev(NULL)
{
size_t index = 0;
_root = _Create(a, size, index, invalid);
}
void PreOrderThreading()
{
_PreOrderThreading(_root);
}
void InOrderThreading()
{
_InOrderThreading(_root);
}
void InOrder()//中序遍历线索二叉树
{
Node* cur = _root;
while (cur)
{
while (cur->_lTag == LINK)
{
cur = cur->_lchild;
}
cout << cur->_data << " ";
while (cur->_rTag == THREAD && cur->_rchild != NULL)
{
cur = cur->_rchild;
cout << cur->_data << " ";
}
cur = cur->_rchild;
}
cout << endl;
}
void PreOrder()//先序遍历
{
Node* cur = _root;
while (cur)
{
while (cur->_lTag == LINK)
{
cout << cur->_data << " ";
cur = cur->_lchild;
}
cout << cur->_data << " ";
cur = cur->_rchild;
}
cout << endl;
}
protected:
Node* _Create(T* a,size_t size,size_t& index,const T& invalid)
{
assert(a != NULL);
Node* root = NULL;
if (a[index] != invalid && index < size)
{
root = new Node(a[index]);
root->_lchild = _Create(a, size, ++index, invalid);
root->_rchild = _Create(a, size, ++index, invalid);
}
return root;
}
void _PreOrderThreading(Node* root)
{
if (root)
{
if (!root->_lchild)
{
root->_lTag = THREAD;
root->_lchild = prev; //前继线索
}
if (prev && !prev->_rchild)
{
prev->_rTag = THREAD;
prev->_rchild = root; //后继线索
}
prev = root;
if (LINK == root->_lTag)
_PreOrderThreading(root->_lchild);
if (LINK == root->_rTag)
_PreOrderThreading(root->_rchild);
}
}
void _InOrderThreading(Node* root)
{
if (root)
{
_InOrderThreading(root->_lchild);
if (root->_lchild == NULL)
{
root->_lTag = THREAD;
root->_lchild = prev;
}
if (prev && prev->_rchild == NULL)
{
prev->_rTag = THREAD;
prev->_rchild = root;
}
prev = root;
_InOrderThreading(root->_rchild);
}
}
private:
Node* _root;
Node* prev;
};
测试代码:
#include"BinaryTreeThreading.h"
void test()
{
int array1[10] = { 1, 2, 3, '#', '#', 4, '#' , '#', 5, 6 };
BinaryTreeThreading<int> b1(array1,10,'#');
b1.InOrderThreading();
b1.InOrder();
int array2[15] = { 1,2,'#',3,'#','#',4,5,'#',6,'#',7,'#','#',8 };
BinaryTreeThreading<int> b2(array2, 15, '#');
b2.PreOrderThreading();
b2.PreOrder();
}
int main()
{
test();
system("pause");
return 0;
}
先序线索和中序线索先到这里,后序线索之后补充~~