数据结构-树和二叉树(三)二叉树线索化
思维导图
1、基本概念
普通二叉树只能找到结点的左右孩子信息,而该结点的直接前驱和直接后继只能在遍历过程中获得,
若将遍历后对应的有关前驱和后继预存起来,则从第一个结点开始就能很快“顺藤摸瓜”而遍历整个树。
思路:
若结点有左子树,则lchild指向其左孩子;否则,lchild指向其直接前驱(即线索);
若结点有右子树,则rchild指向其右孩子;否则,rchild指向其直接后继(即线索) 。
LTag: 若 LTag=0, lchild域指向左孩子;
若 LTag=1, lchild域指向其前驱。
RTag: 若 RTag=0, rchild域指向右孩子;
若 RTag=1, rchild域指向其后继。
线索二叉树的遍历
2、中序线索二叉树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
| #include <iostream> #include <string> using namespace std;
typedef struct ThreadNode { int value; struct ThreadNode *lChild, *rChild; int lTag, rTag; }ThreadNode, *ThreadTree; ThreadNode *pre = nullptr;
void CreateBinaryTree(ThreadTree &root) { auto *node1 = (ThreadNode *)malloc(sizeof(ThreadNode)); auto *node2 = (ThreadNode *)malloc(sizeof(ThreadNode)); auto *node3 = (ThreadNode *)malloc(sizeof(ThreadNode)); auto *node4 = (ThreadNode *)malloc(sizeof(ThreadNode)); auto *node5 = (ThreadNode *)malloc(sizeof(ThreadNode)); auto *node6 = (ThreadNode *)malloc(sizeof(ThreadNode)); root->rTag = 0; root->lTag = 0; node1->rTag = 0; node1->lTag = 0; node2->rTag = 0; node2->lTag = 0; node3->rTag = 0; node3->lTag = 0; node4->rTag = 0; node4->lTag = 0; node5->rTag = 0; node5->lTag = 0; node6->rTag = 0; node6->lTag = 0; root->value = 15; node1->value = 10; node2->value = 23; node3->value = 8; node4->value = 12; node5->value = 21; node6->value = 9; root->lChild = node1; root->rChild = node2; node1->lChild = node3; node1->rChild = node4; node2->lChild = node5; node2->rChild = nullptr; node3->lChild = nullptr; node3->rChild = node6; node4->lChild = nullptr; node4->rChild = nullptr; node5->rChild = nullptr; node5->lChild = nullptr; node6->lChild = nullptr; node6->rChild = nullptr; }
void visit(ThreadNode *p) { if (p->lChild == nullptr) { p->lChild = pre; p->lTag = 1; } if (pre != nullptr && pre->rChild == nullptr) { pre->rChild = p; pre->rTag = 1; } pre = p; }
void InThread(ThreadTree &p) { if (p == nullptr) { return; } InThread(p->lChild); visit(p); InThread(p->rChild); }
bool CreatInThread(ThreadTree &root) { if (root != nullptr) { InThread(root); if (pre->rChild == nullptr) pre->rTag = 1; } }
ThreadNode *FirstInNode(ThreadNode *p) { while (p->lTag == 0) { p = p->lChild; } return p; }
ThreadNode *NextInNode(ThreadNode *p) { if (p->rTag == 0) { return FirstInNode(p->rChild); }else { return p->rChild; } }
void InOrder(ThreadNode *root) { for (ThreadNode *p = FirstInNode(root); p != nullptr ; p = NextInNode(p)) { cout << p->value << "->"; } }
int main() { ThreadTree root; root = (ThreadNode *)malloc(sizeof(ThreadNode)); cout << "初始化创建二叉树" << endl; CreateBinaryTree(root); cout << "中序遍历线索化" << endl; CreatInThread(root); cout << "中序线索化二叉树的中序遍历" << endl; InOrder(root); return 0; }
|
1 2 3 4
| 初始化创建二叉树 中序遍历线索化 中序线索化二叉树的中序遍历 8->9->10->12->15->21->23->
|
3、先序线索二叉树
思路: 找后继遍历先序线索二叉树
若p->rTag == 1,则next = p->rChild
若p->rTag == 0
① 若有左孩子,则先序后继为左孩子
② 若没有左孩子,则先序后继为右孩子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
|
void visit(ThreadNode *p) { if (p->lChild == nullptr) { p->lChild = pre; p->lTag = 1; } if (pre != nullptr && pre->rChild == nullptr) { pre->rChild = p; pre->rTag = 1; } pre = p; }
void PreThread(ThreadTree &p) { if (p != nullptr) { visit(p); if (p->lTag == 0) PreThread(p->lChild); if (p->rTag == 0) PreThread(p->rChild); } }
bool CreatPreThread(ThreadTree &root) { if (root != nullptr) { PreThread(root); if (pre->rChild == nullptr) pre->rTag = 1; } }
ThreadNode *NextPreNode(ThreadNode *p) { if (p->rTag == 1) { return p->rChild; }else { if (p->lTag == 0) { return p->lChild; }else { return p->rChild; } } }
void PreOrder(ThreadNode *root) { for (ThreadNode *p = root; p != nullptr; p = NextPreNode(p)) { cout << p->value << "->"; } }
|
1 2 3 4
| 初始化创建二叉树 先序遍历线索化 先序线索化二叉树的先序遍历 15->10->8->9->12->23->21->
|
4、后序线索二叉树
思路: 找前驱遍历后序线索二叉树
若p->rLag == 1,则pre = p->lChild
若p->lTag == 0
① 若有右孩子,则后序前驱为右孩子
② 若有左孩子,则后序前驱为左孩子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
|
void visit(ThreadNode *p) { if (p->lChild == nullptr) { p->lChild = pre; p->lTag = 1; } if (pre != nullptr && pre->rChild == nullptr) { pre->rChild = p; pre->rTag = 1; } pre = p; }
void PostThread(ThreadTree &p) { if (p == nullptr) { return; } PostThread(p->lChild); PostThread(p->rChild); visit(p); }
bool CreatPostThread(ThreadTree &root) { if (root != nullptr) { PostThread(root); if (pre->rChild == nullptr) pre->rTag = 1; } }
ThreadNode *LastPostNode(ThreadNode *p) { return p; }
ThreadNode *PrePostNode(ThreadNode *p) { if (p->lTag == 1) { return p->lChild; }else { if (p->rChild != nullptr && p->rTag == 0) { return LastPostNode(p->rChild); }else if (p->lChild != nullptr && p->lTag == 0) { return LastPostNode(p->lChild); } } }
void PostOrder(ThreadNode *root) { for (ThreadNode *p = LastPostNode(root); p != nullptr ; p = PrePostNode(p)) { cout << p->value << "->"; } }
int main() { ThreadTree root; root = (ThreadNode *)malloc(sizeof(ThreadNode)); cout << "初始化创建二叉树" << endl; CreateBinaryTree(root); cout << "后序遍历线索化" << endl; CreatPostThread(root); cout << "后序线索化二叉树的先序遍历" << endl; PostOrder(root); return 0; }
|
1 2 3 4
| 初始化创建二叉树 后序遍历线索化 后序线索化二叉树的先序遍历 15->23->21->10->12->8->9->
|