//Geeksun 2018.05.13 输入样例 AB#D##C## 详情见扩展二叉树
#include <iostream>
using namespace std;
enum flag{Child = 0,Thread = 1};//两种枚举类型,表示该节点的指针是指向下一个节点,还是作为线索。
struct node
{
char data;
struct node *leftChild, *rightChild;
flag ltag, rtag;
};
class Tree
{
public:
Tree()
{
this->root = treeCreat(getRoot());//此处需要在类里再定义一个创建树的函数,因为构造函数不能被递归调用。
pre = NULL;
threadTreeCreat(getRoot());
}
Tree(const Tree& tree)//复制构造函数
{
this->root = treeCopy(this->root,tree.root);
}
~Tree()
{
destroyTree(getRoot());
}
void destroyTree(struct node* node);//析构整个树
bool isCompleteBinaryTree(struct node* node);//判断是否为完全二叉树
void threadInorder_travelsal(struct node* node);//根据线索二叉树中序遍历
void deleteNodeTree(char data, struct node* node, struct node* pre);删除子树
bool searchNode(char data, struct node* node, struct node*& cur, bool &isFind);//查找某个节点
struct node** arrayReserve(struct node* node,int& count);//将树按中序保存在数组中
struct node* getRoot()
{
return root;
}
private:
struct node* root;
struct node* pre;
struct node* treeCreat(struct node* node);
struct node* treeCopy(struct node* son_node,struct node* father_node);
struct node* threadNext(struct node* p);//中序遍历时查找后继节点的位置
void threadTreeCreat(struct node* node);
};
bool Tree::isCompleteBinaryTree(struct node* node)
{
int head = 0, tail = 0;
struct node* queue[20];
if (!node)
{
return false;
}
queue[tail++] = node;
while (head != tail)
{
struct node* p;
p = queue[head++ % 20];
if (p->leftChild != NULL&&p->rightChild != NULL)//若左孩子,右孩子不为空则直接入队列
{
queue[tail++ % 20] = p->leftChild;
queue[tail++ % 20] = p->rightChild;
}
if (p->leftChild == NULL&&p->rightChild != NULL)//若有右孩子没有左孩子则不是完全二叉树
{
return false;
}
if (p->leftChild != NULL && p->rightChild == NULL|| p->leftChild == NULL && p->rightChild == NULL)//若左孩子和右孩子存在或左孩子和右孩子都不存在,则在此节点后的全是叶子结点
{
while (head != tail)
{
p = queue[head];
if (p->leftChild == NULL && p->rightChild == NULL)
{
head++;
}
else
{
return false;
}
}
return true;
}
}
return true;
}
struct node* Tree::treeCopy(struct node* son_node, struct node* father_node)
{
if (father_node)
{
son_node = new struct node;
son_node->data = father_node->data;
son_node->leftChild = treeCopy(son_node->leftChild, father_node->leftChild);//此处的struct node* son_node 可以用引用,因为要修改它的指向,也可以在修改后将它传出来,覆盖之前的指针。
son_node->rightChild = treeCopy(son_node->rightChild, father_node->rightChild);
}
else
{
son_node = NULL;//此处一定要加上新节点为空,不然它就是一个野指针了。
}
return son_node;
}
bool Tree::searchNode(char data, struct node* node, struct node*& cur,bool &isFind)//此处isFind传引用较为新颖,只要isFind被修改为True,那么就可以知道,在节点中有该数据。
{
if (!node)
{
return isFind;
}
if (node->data == data)
{
cur = node;
isFind = true;
return isFind;
}
searchNode(data, node->leftChild, cur, isFind);
searchNode(data, node->rightChild, cur, isFind);
return isFind;
}
void Tree::deleteNodeTree(char data,struct node* node,struct node* pre)
{
if (node != NULL)
{
if (node->data == data && node != getRoot())//如果删除的不是根节点
{
if (pre->leftChild == node) //防止删除节点的父节点的指针悬空
pre->leftChild = NULL;
else if (pre->rightChild == node)
pre->rightChild = NULL;
destroyTree(node);
return;
}
else if (node->data == data)
{
destroyTree(node);
return;
}
if(node->ltag == 0)
deleteNodeTree(data,node->leftChild,node);
if(node->rtag == 0)
deleteNodeTree(data,node->rightChild,node);
}
}
void Tree::threadInorder_travelsal(struct node* node)
{
struct node* p;
p = node;
if (!p)
{
return;
}
while (p->ltag == 0)
{
p = p->leftChild;//先找到树最左下方的节点。
}
cout << p->data;
while (p->rightChild != NULL)
{
p = threadNext(p);
cout << p->data;
}
}
struct node** Tree::arrayReserve(struct node* node,int &count)
{
int head = 0, tail = 0;
count = 0;
struct node** array = new struct node*[20];//这里需要在堆中创建数组,因为如果在栈中创建数组,当函数结束后array中的数据都会消失,而堆中数据需自己清空。
struct node* queue[20];
if (!node)
{
return NULL;
}
queue[tail++ % 20] = node;
while (head != tail)
{
struct node* q = queue[head++];
array[count++] = q;
if (q->leftChild != NULL) queue[tail++] = q->leftChild;
if (q->rightChild != NULL) queue[tail++] = q->rightChild;
}
return array;
}
struct node* Tree::threadNext(struct node* p)
{
struct node* q;
if (p->rtag == 1)
q = p->rightChild;
else
{
q = p->rightChild;//此处p的右孩子不可能为空,若为空则他的rtag一定为1
while (q->ltag == 0)
{
q = q->leftChild;
}
}
return q;
}
void Tree::threadTreeCreat(struct node* node)
{
if (node == NULL)
return;
threadTreeCreat(node->leftChild);
if (node->leftChild == NULL)
{
node->ltag = (flag)1;//这里要使用强转类型转换,不然会报错!
node->leftChild = pre;
}
if (node->rightChild == NULL)
node->rtag = (flag)1;//右孩子指针指向的是下一个中序结点的地址,但是暂时还不知道下一个是谁,因此只能在下一轮循环指向下一个结点。
if (pre != NULL&& pre->rtag == 1)//当pre为指向空的时候,当然不会有数据,所以要判断一下!
{
pre->rightChild = node;
}
pre = node;
threadTreeCreat(node->rightChild);
return;
}
struct node* Tree::treeCreat(struct node* node)
{
char ch;
cin >> ch;
if (ch == '#')
{
node = NULL;
}
else
{
node = new struct node;
node->data = ch;
//node->ltag = (flag)0; node->rtag = (flag)0;
node->leftChild = treeCreat(node->leftChild);
node->rightChild = treeCreat(node->rightChild);
}
return node;
}
void Tree::destroyTree(struct node* node)
{
if (node == NULL)
{
return;
}
if (node->leftChild != NULL&&node->ltag == 0)
{
destroyTree(node->leftChild);
}
if (node->rightChild != NULL&&node->rtag == 0)
{
destroyTree(node->rightChild);
}
delete node;
node = NULL;
return;
}