目录
树结构及其算法-线索二叉树
C++代码
树结构及其算法-线索二叉树
虽然我们把树转换为二叉树可减少空间的浪费——由2/3降低到1/2,但是如果仔细观察之前使用链表建立的n节点二叉树,那么会发现用来指向左右两个节点的指针只有n-1个链接,另外的n+1个指针都是空链接。
所谓线索二叉树(Threaded Binary Tree),就是把这些空链接加以利用,再指到树的其他节点,这些链接就称为线索(Thread),而这棵树就称为线索二叉树。将二叉树转换为线索二叉树的步骤如下:
- 先将二叉树通过中序遍历方式按序排出,并将所有空链接改成线索。
- 如果线索链接指向该节点的左链接,就将该线索指向中序遍历顺序下的前一个节点。
- 如果线索链接指向该节点的右链接,就将该线索指向中序遍历顺序下的后一个节点。
- 指向一个空节点,并将此空节点的右链接指向自己,而空节点的左子树是此线索二叉树。
线索二叉树的基本结构如下:
- LBIT:左控制位
- LCHILD:左子树链接
- DATA:节点数据
- RCHILD:右子树链接
- RBIT:右控制位
和链表所建立的二叉树不同之处在于。为了区别正常指针或线索而加入的两个字段:LBIT和RBIT。
- 若LCHILD为正常指针,则LBIT=1。
- 若LCHILD为线索,则LBIT=0。
- 若RCHILD为正常指针,则RBIT=1。
- 若RCHILD为线索,则RBIT=0。
节点的声明方式如下:
struct TreeNode {
int data;
int leftThread;
int rightThread;
TreeNode* leftNode;
TreeNode* rightNode;
};
以下是使用线索二叉树的优缺点:
优点:
- 在二叉树中进行中序遍历时,不需要使用堆栈处理,但一般二叉树需要。
- 由于充分使用了空链接,因此避免了链接闲置浪费的情况。另外,在中序遍历时速度较快,节省不少时间。
- 任一节点都容易找出它的中序先行者与中序后继者,在中序遍历时可以不使用堆栈或递归。
缺点:
- 在加入或删除节点时的速度比一般二叉树慢。
- 线索子树间不能共用。
C++代码
#include<iostream>
using namespace std;
struct TreeNode {
int data;
int leftThread;
int rightThread;
TreeNode* leftNode;
TreeNode* rightNode;
TreeNode() {
data = 0;
leftThread = 0;
rightThread = 0;
leftNode = nullptr;
rightNode = nullptr;
}
TreeNode(int tempData, int tempLeftThread = 0, int tempRightThread = 0, TreeNode* tempLeftNode = nullptr, TreeNode* tempRightNode = nullptr) {
this->data = tempData;
this->leftThread = tempLeftThread;
this->rightThread = tempRightThread;
this->leftNode = tempLeftNode;
this->rightNode = tempRightNode;
}
};
namespace Tree {
TreeNode* CreateTree(int* tempData, int tempSize) {
TreeNode* root = nullptr;
for (int i = 0; i < tempSize; i++) {
TreeNode* newTreeNode = new TreeNode(tempData[i]);
TreeNode* previousTreeNode = new TreeNode(tempData[i]);
TreeNode* currentTreeNode = new TreeNode();
TreeNode* parentTreeNode = new TreeNode();
int pos;
if (root == nullptr) {
root = newTreeNode;
root->leftNode = root;
root->rightThread = 1;
continue;
}
currentTreeNode = root->rightNode;
if (currentTreeNode == nullptr) {
root->rightNode = newTreeNode;
newTreeNode->leftNode = root;
newTreeNode->rightNode = root;
continue;
}
parentTreeNode = root;
pos = 0;
while (currentTreeNode != nullptr) {
if (currentTreeNode->data > tempData[i]) {
if (pos != -1) {
pos = -1;
previousTreeNode = parentTreeNode;
}
parentTreeNode = currentTreeNode;
if (currentTreeNode->leftThread == 1)
currentTreeNode = currentTreeNode->leftNode;
else
currentTreeNode = nullptr;
}
else {
if (pos != 1) {
pos = 1;
previousTreeNode = parentTreeNode;
}
parentTreeNode = currentTreeNode;
if (currentTreeNode->rightThread == 1)
currentTreeNode = currentTreeNode->rightNode;
else
currentTreeNode = nullptr;
}
}
if (parentTreeNode->data > tempData[i]) {
parentTreeNode->leftThread = 1;
parentTreeNode->leftNode = newTreeNode;
newTreeNode->leftNode = previousTreeNode;
newTreeNode->rightNode = parentTreeNode;
}
else {
parentTreeNode->rightThread = 1;
parentTreeNode->rightNode = newTreeNode;
newTreeNode->rightNode = previousTreeNode;
newTreeNode->leftNode = parentTreeNode;
}
}
return root;
}
void Inorder(TreeNode* root) {
TreeNode* tempTreeNode = root;
do {
if (tempTreeNode->rightThread == 0)
tempTreeNode = tempTreeNode->rightNode;
else {
tempTreeNode = tempTreeNode->rightNode;
while (tempTreeNode->leftThread != 0)
tempTreeNode = tempTreeNode->leftNode;
}
if (tempTreeNode != root)
cout << tempTreeNode->data << " ";
} while (tempTreeNode != root);
cout << endl;
}
};
int main() {
int data[]{ 0, 6, 3, 5, 9, 7, 8, 4, 2 };
cout << "原始数据:" << endl;
for (int i = 1; i < 9; i++)
cout << data[i] << " ";
cout << endl;
TreeNode* treeNode = Tree::CreateTree(data,9);
cout << "排序结果:" << endl;
Tree::Inorder(treeNode);
return 0;
}
输出结果