线索二叉树寻找前驱和后继
在线索二叉树中与普通二叉树最大的区别是可以更快的寻找到前驱和后继,普通二叉树每次寻找前驱和后继都需要从根结点开始依次遍历,而线索二叉树只需要从本身结点开始即可,时间复杂度大大的减少,下面我将展示如果实现线索二叉树寻找前驱和后继
代码展示:
//完全二叉树的链式存储 线索二叉树
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
//构建树
typedef struct TreeNode
{
int data;//数据域
struct TreeNode* lchild, * rchild;//指针域
int ltag, rtag;//线索标签
}ThreadNode,*ThreadTree;
//构建队列
typedef struct LinkNode
{
ThreadTree data;//数据域
struct LinkNode* next;//指针域
}LinkNode;
typedef struct SQueue
{
LinkNode* rear,* front;//首尾指针
}SQueue;
void InitTree(ThreadTree * T)//初始化树
{
(*T) = NULL;
return;
}
void InitQueue(SQueue* Q)//初始化队列
{
Q->front = Q->rear = (LinkNode*)malloc(sizeof(LinkNode));//创建带头结点的链表
if (Q->front == NULL)
return;//分配失败
Q->front->next = NULL;
return;
}
bool EnQueue(SQueue* Q, ThreadNode* T)//入队
{
//无需判断队满
LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
if (s == NULL)
return false;
s->data = T;
s->next = NULL;
Q->rear->next = s;
Q->rear = s;
return true;
}
bool DeQueue(SQueue* Q, ThreadNode** temp)//队列出队
{
if (Q->front == Q->rear)
return false;//空队无法出队
LinkNode* s = Q->front->next;
*temp = s->data;
Q->front->next = s->next;
if (s == Q->rear)//最后一个元素
Q->rear = Q->front;
free(s);
return true;
}
bool EmptyQueue(SQueue Q)//判空
{
if (Q.front != Q.rear)
return false;//非空
return true;
}
bool EnTree(ThreadTree* T)//插入树中的元素
{
//无需判断是否树满
int start = 1;
int end = 12;//从1到12
//插入根结点
if ((*T) == NULL && start <= end)
{
ThreadNode* root = (ThreadNode*)malloc(sizeof(ThreadNode));
if (root == NULL)
return true;//分配失败
root->data = start;
root->lchild = NULL;//左右孩子为空
root->rchild = NULL;
root->ltag = 0;//线索便签初始为0
root->rtag = 0;
start++;
(*T) = root;
}
//后续结点插入
SQueue Q;//定义队列
InitQueue(&Q);//初始化队列
EnQueue(&Q, (*T));//根结点入队
ThreadNode* temp = NULL;//创建临时结点
while (start <= end && !EmptyQueue(Q))
{
DeQueue(&Q, &temp);//队列出队
if (start <= end && temp->lchild == NULL)//创建左孩子
{
ThreadNode* lson = (ThreadNode*)malloc(sizeof(ThreadNode));
if (lson == NULL)
return false;//分配失败
temp->lchild = lson;
lson->data = start;
lson->lchild = lson->rchild = NULL;
lson->ltag = lson->rtag = 0;
start++;
EnQueue(&Q, lson);
}
if (start <= end && temp->rchild == NULL)//创建右孩子
{
ThreadNode* rson = (ThreadNode*)malloc(sizeof(ThreadNode));
if (rson == NULL)
return false;//分配失败
temp->rchild = rson;
rson->data = start;
rson->lchild = rson->rchild = NULL;
rson->ltag = rson->rtag = 0;
start++;
EnQueue(&Q, rson);
}
}
return true;
}
void visit(ThreadTree T)//访问根结点
{
if (T == NULL)
return;//空元素
printf("%d ", T->data);
return;
}
void PrintMiddle(ThreadTree T)//中序遍历
{
if (T != NULL)
{
PrintMiddle(T->lchild);
visit(T);
PrintMiddle(T->rchild);
}
}
ThreadNode* pre = NULL; //全局变量
void Invisit(ThreadNode* T)//访问该结点
{
if (T->lchild == NULL)
{
T->lchild = pre;
T->ltag = 1;
}
if (pre != NULL && pre->rchild == NULL)
{
pre->rchild = T;
pre->rtag = 1;
}
pre = T;
}
void InThread(ThreadTree T)//构建中序线索二叉树(递归)
{
if (T != NULL)
{
InThread(T->lchild);
Invisit(T);
InThread(T->rchild);
}
}
bool CreateThreadTree(ThreadTree T)//建立线索二叉树
{
if (T == NULL)
return false;//空树直接退出
pre = NULL; //先把pre赋值为空
InThread(T);
if (pre->rchild == NULL)//令最后一个孩子的右节点指向空
pre->rtag = 1;
return true;
}
ThreadNode* NewNode = NULL;
//用层次方式寻找后继
//注:此处不能用递归来遍历结点
void InfixVisit(ThreadTree T)//判断元素
{
if(T == NULL)
return;
if (T->data == 5)
{
NewNode = T;
}
}
void LevelErgodic(ThreadTree T)//层次遍历
{
SQueue Q;//创建队列
InitQueue(&Q);//初始化队列
ThreadTree p = NULL;//二叉树
EnQueue(&Q, T);//根结点入队
while (!EmptyQueue(Q))
{
DeQueue(&Q, &p);//根结点出队
InfixVisit(p);
if (p->ltag != 1)//左孩子非叶子结点
EnQueue(&Q, p->lchild);
if (p->rtag != 1)//右孩子非叶子结点
EnQueue(&Q, p->rchild);
}
}
ThreadNode* LastNode(ThreadNode* T)//查找前驱
{
while (T->rtag != 1)
T = T->rchild;
return T;
}
ThreadNode* FristNode(ThreadNode * T)//查找后继
{
while (T->ltag != 1)
T = T->lchild;
return T;
}
bool FrontAndBack(ThreadNode* T)//判断前驱和后继
{
if (T == NULL)
return false;//空树
LevelErgodic(T);
ThreadNode* Public = NewNode;//已知查找元素
//查找前驱
if (Public->lchild->ltag == 1)//证明左孩子为叶子结点
printf("5的前驱是%d\n", Public->lchild->data);
else//左孩子是分支结点
{
ThreadNode* N = LastNode(Public->lchild);//左孩子的最后一个节点为前驱
printf("5的前驱是%d\n", N->data);
}
//查找后继
if (T->rchild->rtag == 1)//证明右孩子是叶子结点
printf("5的后继为%d\n", Public->rchild->data);
else//右孩子不是叶子结点
{
ThreadNode* M = FristNode(Public->rchild);//如果右孩子是分支结点则第一个访问的结点为该元素的后继结点
printf("5的后继为%d\n", M->data);
}
return true;
}
int main()
{
ThreadTree T;//创建树
InitTree(&T);//初始化树
EnTree(&T);//插入树
PrintMiddle(T);//中序打印
CreateThreadTree(T);//建立线索二叉树
printf("\n");
FrontAndBack(T);//假设寻找结点元素为5的前驱和后继
return 0;
}