这篇文章主要保存下二叉树学习中的实现,实现了4类基本功能和一个扩展功能:
1、创建节点
2、插入节点
3、删除节点
4、二叉树销毁
5、遍历
6、按结构显示打印
扩展功能在下篇文章中显示
函数定义及头文件
#pragma once
#include <queue>
#include <iostream>
using namespace std;
typedef struct BinNodetag
{
BinNodetag* P; //父节点
BinNodetag* L; //左孩子节点
BinNodetag* R; //右孩子节点
unsigned int index; //节点索引
void * data; //节点数据
}BinNode;
/*****************************************************************
打印二叉树使用的数据结构,用于保存二叉树节点数据和位置信息,
depth:
表示深度位置信息,根节点为1,往下一层为2,按层+1增长
local:
标示x轴位置信息,根节点为单位1,
其左孩子为1-1/2,右孩子为1+1/2。
每层的loacl为其父节点的local +/- 0.5^depth
eg: node->L->local = node->local - (1 << depth)
*****************************************************************/
typedef struct PaintNodetag //
{
unsigned int depth; //Y轴信息
float local; //X轴信息
BinNode *node; //当前节点
}PaintNode;
BinNode *Creat(int index); //按照索引创建一个节点
void Insert(BinNode **head, BinNode *Insertnode); // 在树中插入一个节点
void Delete(BinNode *head, BinNode *node); //从树中删除一个节点
void Destory(BinNode *node); //消耗整个二叉树
void InWalkMid(BinNode *head); //中序遍历打印
void PaintTree(BinNode *head); //显示打印二叉树
具体实现
1、创建节点
BinNode *Creat(int index)
{
BinNode *node = new BinNode;
memset(node, 0, sizeof(*node));
node->index = index;
return node;
}
2、插入节点
void Insert(BinNode **head, BinNode *Insertnode)
{
BinNode *node = *head;
BinNode **child = NULL;
//头节点为空,成为头节点
if (*head == NULL)
{
*head = Insertnode;
Insertnode->P = NULL;
return;
}
//类似查找的逻辑,查到当前节点的子节点为空时,插入该处
while (node != NULL)
{
child = (Insertnode->index < node->index) ? &(node->L) : &(node->R);
if (*child == NULL)
{
*child = Insertnode;
Insertnode->P = node;
break;
}
node = *child;
}
return;
}
3、删除节点
删除节点比较麻烦,有两大类情况
1、当前节点没有,或只有一个子节点
2、当前节点有两个子节点
第一种情况下,比较好办,简单的把子节点替换为原节点就行。
第二种情况,核心思想是保证二叉树的结构不变。例如,
中序遍历为 1,2,3,4,5,6,删除3之后,遍历结果也该为1,2,4,5,6
删前2的后继为3,删后2的后继为4,即:
使用删除节点的后继取代原节点位置。
删除节点后继就是他孩子里面最小的数,如果:
1、右孩子没有左孩子那么就是右孩子为后继;
2、否则就一张沿着右孩子的左孩子找下去
a、实现如下,为了方便定义了个替代函数,用于src替代dst的位置:
用于处理一个节点替代另外一个节点的操作,仅仅处理dst->P 和 src 的关系,不处理src的孩子节点
void Replace(BinNode *head, BinNode *dst, BinNode *src)
{
if (dst == NULL )
{
return;
}
if (dst->P == NULL)
{
head = src;
}
else
{
((dst->P->L == dst) ? dst->P->L : dst->P->R) = src;
}
if (src != NULL && src->P != NULL)
{
src->P = dst->P;
}
return;
}
b、删除函数主体
void Delete(BinNode *head, BinNode *node)
{
//head node
BinNode *tmp_node;
if (node->L == NULL)
{
Replace(head, node, node->R);
}
else if (node->R == NULL)
{
Replace(head, node, node->L);
}
else
{
//two parent conditon!the node is replaced by succeeding node
if (node->R->L == NULL)
{
node->R->L = node->L;
Replace(head, node, node->R);
}
else
{
tmp_node = node->R->L;
while (tmp_node->L != NULL)
{
tmp_node = tmp_node->L;
}
//中继节点删除后,该位置值NULL
tmp_node->P->L = NULL;
//replace
tmp_node->L = node->L;
tmp_node->R = node->R;
Replace(head, node, tmp_node);
}
}
delete node;
}
4、二叉树销毁
后续遍历删除二叉树
void Destory(BinNode *node)
{
if (node == NULL)
{
return;
}
Destory(node->L);
Destory(node->R);
delete node;
return;
}
5、遍历
遍历较简单,这里实现中序遍历
void InWalkMid(BinNode *head)
{
if (head == NULL)
{
return;
}
InWalkMid(head->L);
printf("%4u", head->index);
InWalkMid(head->R);
return;
}