什么是二叉线索化:
当用二叉链表作为二叉树的存储结构时,因为每个结点中只有指向其左、右儿子结点的指针,所以从任一结点出发只能直接找到该结点的左、右儿子。在一般情况下靠它无法直接找到该结点在某种遍历序下的前驱和后继结点。如果在每个结点中增加指向其前驱和后继结点的指针,将降低存储空间的效率。
先用一张图来说明怎样对二叉树进行线索化
root表示二叉树子树的根节点,prev是上一个访问的节点,如果prev右子树为空,就将后继指向root,如果root左子树为空,就将root前驱指向prev。为了充分利用空指针域,可以使用标记来完成线索化,具体代码如下:
//BinTree.h
#pragma once
#include <stddef.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<stdio.h>
typedef enum Flag {
Child,
Thread,
}Flag;
typedef char ThreadType;
typedef struct ThreadNode {
ThreadType data;
struct ThreadNode* left;
struct ThreadNode* right;
Flag lflag; //引入两个flag来分别表示左右指针指向的是子树还是线索
Flag rflag; //不直接使用前驱、后继指针可以使用空指针域
}ThreadNode;
ThreadNode* ThreadTreeCreate(ThreadType array[], size_t size, ThreadType invalid);
void PreThreading(ThreadNode* root);//先序线索化
void InThreading(ThreadNode* root);//中序线索化
void PostThreading(ThreadNode* root); //后序线索化
void PreOrderbyThreading(ThreadNode* root);//先序线索化遍历
void InOrderbyThreading(ThreadNode* root); //中序线索化遍历
void PrintInder(ThreadNode* root); //中序遍历
//BinTree.c
#include "BinTree.h"
ThreadNode* CreateNode(ThreadType value)
{
ThreadNode* newnode = (ThreadNode*)malloc(sizeof(ThreadNode));
newnode->data = value;
newnode->left = NULL;
newnode->right = NULL;
newnode->lflag = Child;
newnode->rflag = Child;
return newnode;
}
ThreadNode* _ThreadTreeCreate(ThreadType array[], size_t size, size_t *index, ThreadType invalid)
{
if (index == NULL || *index >= size) {
return NULL;
}
if (array[*index] == invalid) {
return NULL;
}
ThreadNode* root = CreateNode(array[*index]);
++(*index);
root->left = _ThreadTreeCreate(array, size, index, invalid);
++(*index);
root->right = _ThreadTreeCreate(array, size, index, invalid);
return root;
}
//输入的array是二叉树的先序遍历结果
ThreadNode* ThreadTreeCreate(ThreadType array[], size_t size, ThreadType invalid)
{
size_t index = 0;
return _ThreadTreeCreate(array, size, &index, invalid);
}
void _PreThreading(ThreadNode* root, ThreadNode** prev)//先序线索化
{
if (root == NULL || prev == NULL)
{
return;
}
//处理根节点
//1.如果当前子树根节点的左子树为空,就把left指针指向前驱
if (root->left == NULL)
{
root->left = *prev;
root->lflag = Thread;
}
//2.如果当前子树根节点的前驱的右子树为空,就把前驱的right指针指向此根节点
if (*prev != NULL && (*prev)->right == NULL)
{
(*prev)->right = root;
(*prev)->rflag = Thread;
}
*prev = root;
//处理左子树
if (root->lflag == Child)
{
_PreThreading(root->left, prev);
}
//处理右子树
if (root->rflag == Child)
{
_PreThreading(root->right, prev);
}
}
void PreThreading(ThreadNode* root)//封装函数,使用户使用更加方便
{
ThreadNode *prev = NULL;
_PreThreading(root, &prev);
}
void PreOrderbyThreading(ThreadNode* root)//先序线索化遍历
{
assert(root);
ThreadNode *pcur = root;
while (pcur != NULL)
{
while (pcur->lflag == Child)
{
//找到最左边的节点
printf("%c ", pcur->data);
pcur = pcur->left;
}
//打印最左边的节点
printf("%c ", pcur->data);
//如果pcur->right是线索或者有右孩子,都向右走
pcur = pcur->right;
}
}
void _InThreading(ThreadNode* root, ThreadNode** prev)//中序线索化(只有处理根节点的位置与前序不同)
{
if (root == NULL || prev == NULL)
{
return;
}
if (root->lflag == Child)
{
_InThreading(root->left, prev);
}
if (root->left == NULL)
{
root->left = *prev;
root->lflag = Thread;
}
if (*prev != NULL && (*prev)->right == NULL)
{
(*prev)->right = root;
(*prev)->rflag = Thread;
}
*prev = root;
if (root->rflag== Child)
{
_InThreading(root->right, prev);
}
}
void InThreading(ThreadNode* root)//中序线索化
{
assert(root);
ThreadNode *prev = NULL;
_InThreading(root, &prev);
}
void InOrderbyThreading(ThreadNode* root) //中序线索化遍历
{
assert(root);
ThreadNode *pcur = root;
while (pcur != NULL)
{
while (pcur != NULL && pcur->lflag == Child)
{
//走到最左边节点
pcur = pcur->left;
}
while (pcur != NULL)
{
printf("%c ", pcur->data);//访问最左边节点
if (pcur->rflag == Thread)
{
//如果右孩子是线索,向右走
pcur = pcur->right;
}
else
{
//进入循环
pcur = pcur->right;
while (pcur != NULL && pcur->lflag == Child)
{
pcur = pcur->left;
}
}
}
}
}
void PrintInder(ThreadNode* root) //中序遍历
{
if (root == NULL)
return;
ThreadNode *pcur = root;
if (NULL != pcur)
{
PrintInder(pcur->left);
printf("%c ", pcur->data);
PrintInder(pcur->right);
}
}
void _PostThreading(ThreadNode* root, ThreadNode** prev)
{
if (NULL == root || NULL == prev)
return;
if (root->lflag == Child)
{
_PostThreading(root->left, prev);
}
if (root->rflag == Child)
{
_PostThreading(root->right, prev);
}
if (root->left == NULL)
{
root->left = *prev;
root->lflag = Thread;
}
if (NULL != *prev || (*prev)->right == NULL)
{
(*prev)->right = root;
(*prev)->rflag = Thread;
}
}
void PostThreading(ThreadNode* root) //后序线索化
{
ThreadNode* prev = NULL;
_PostThreading(root, &prev);
}
///////////////////////////////////////////////////////////////////////////
////测试代码
//////////////////////////////////////////////////////////////////////////
#if 1
#include <stdio.h>
#define TEST_HEADER printf("\n=================%s================\n", __FUNCTION__)
void TestPreOrderbyThread()
{
TEST_HEADER;
ThreadType array[] = "ABD##EG###C#F##";
ThreadNode* root = ThreadTreeCreate(array, strlen(array), '#');
PreThreading(root);
PreOrderbyThreading(root);
}
void TestInOrderbyThread()
{
TEST_HEADER;
ThreadType array[] = "ABD##EG###C#F##";
ThreadNode* root = ThreadTreeCreate(array, strlen(array), '#');
InThreading(root);
InOrderbyThreading(root);
}
int main()
{
TestInOrderbyThread();
system("pause");
return 0;
}
#endif