通用树结构工程量比较大,我没时间把每一个点扩展开,详细的附上说明与过程。我浓缩了下步骤,过程全部体现在代码与注释里了。所以希望阅读的小伙伴可以按一个目录为一章的心态,根据目录的顺序与讲解,对照代码一点点的去理解。
其中因为继承,也涉及了Tree与TreeNode中的成员变量,所以对照抽象父类来阅读会更加方便。(https://blog.csdn.net/Es_Study_Yu/article/details/105268522)
通用树的存储结构与实现
通用树整体的继承结构:
设计要点:
GTree的每个结点可以存在多个后继结点
GTreeNode能够包含任意多指向后继结点的指针
实现树形结构中的接口(增,删,查,等)
树是递归定义的,所以树中的函数也大都用递归实现!
GTreeNode的设计与实现:
继承自TreeNode(继承关系),引用单链表实现(组合关系)
GTree的设计与实现:
继承自Tree(继承关系),引用通用树节点实现(组合关系)
通用树的实现架构:
设计时,为什么每个树节点需要包含指向前驱结点的指针?
因为:根节点→叶节点是非线性的数据结构
叶结点→根节点是线性的数据结构(链表)
通用树中的查找操作
1、通过树中的元素的值查找
定义功能:find(node,value)
在node为根节点的树中查找value所在的结点
2、通过树中的结点的值查找
定义功能:find(node,obj)
在node为根节点的树中查找是否存在obj结点
通用树中的插入操作
如何指定树中的结点插入在什么位置?
树是非线性的,无法使用下标来定位数据元素
每一个结点都有唯一的前驱结点(父节点)
因此,必须找到(指明)前驱结点,才可以插入新结点
通用树中的清除操作
定义清除操作功能:free(node)
清除node为根节点的树
释放树中的每一个结点(内存中的释放)
树中的结点可能来源与不同的存储空间,如何判断堆空间中的结点并释放?(PS:单凭内存地址很难判断是否为堆空间创建的)
使用工厂模式
在TreeNode中增加包含成员变量m_flag
将TreeNode中的operator new重载为包含成员函数(无法外部new出新对象)
提供工厂方法GTreeNode* NewNode()
在工厂方法中,new出新结点时,将m_flag设置为true
无参构造的时候,m_flag设置为false
只有这两种方式可以产生结点,所以可以通过m_flag判断是否为堆对象。
通用树中的删除操作
删除操作成员函数的设计要点
将删除结点所代表的子树一并删除
如果删除中的结点所代表的子树中,有扔需要的数据怎么办?
删除后,返回为一棵独立的堆空间中的树
如果没有需要的数据呢?
返回为指向该子树的智能指针对象
不需要的话,因为生命周期原因,会直接析构
需要的话,使用智能指针对象指向即可继续使用
通用树中的属性操作
1、树中结点的数目
定义功能:count(node)
在node为根节点的树中统计结点数目
2、树的高度
定义功能:height(node)
获取node为根结点的树的高度
3、树的度数
定义功能:degree(node)
获取node为根结点的树的度数
通用树中的层次遍历
树是非线性的数据结构,没有固定的编号方式,只能通过查找访问结点,需要遍历时效率太低,怎样快速遍历呢?
设计思路:
使用游标的方式,利用LinkQueue实现
提供一组遍历相关函数:begin() current() next() end()
函数实现方式:
begin() → 将根节点压入队列
current() → 返回队头结点指向的数据元素
next() → 将队头结点弹出,将队头结点的孩子压入队列中
end() → 判断队列是否为空
GTree
GTree.h
#ifndef __GTREE_H_
#define __GTREE_H_
#include "include/Tree.h"
#include "include/GTreeNode.h"
#include "include/Exception.h"
#include "include/SharedPointer.h"
#include "include/LinkQueue.h"
namespace JYlib
{
/* 通用树结构
* 通用树里插入的对象的生命周期必须要比树的生命周期长
* 不然在调用或者析构时都会有问题(尽量不用局部变量)
* begin next current end 调用时,需要先begin,
* 让队列里有元素,才可以使用current
*/
template < typename T >
class GTree : public Tree<T>
{
protected:
//用链式队包含GTreeNode的指针,提供队列的遍历方式
LinkQueue<GTreeNode<T>*> m_queue;
GTreeNode<T>* find(GTreeNode<T>* node,const T& value)const//按值查找
{
GTreeNode<T>* ret = NULL;
if(node != NULL)
{
if(node->value == value)//递归出口
{
return node;
}
else
{
for(node->child.move(0);(!node->child.end())&&(ret == NULL);node->child.next())//查找到直接跳出遍历
{
ret = find(node->child.current(),value);//递归调用
}
}
}
return ret;
}
GTreeNode<T>* find(GTreeNode<T>* node,GTreeNode<T>* obj)const//按结点查找
{
GTreeNode<T>* ret = NULL;
if(node == obj)//递归出口
{
return node;
}
else
{
if(node != NULL)
{
for(node->child.move(0);(!node->child.end())&&(ret == NULL);node->child.next())//查找到直接跳出遍历
{
ret = find(node->child.current(),obj);//递归调用
}
}
}
return ret;
}
void free(GTreeNode<T>* node)//工厂模式,堆对象会被析构,其余的不会
{
if(node != NULL)
{
for(node->child.move(0);!node->child.end();node->child.next())//递归调用
{
free(node->child.current());
}
if(node->flag())//堆对象才会被析构
{
//std::cout << "delete " << node->value << std::endl;
delete node;
}
}
}
void remove(GTreeNode<T>* node,GTree<T>*& ret)
{
ret = new GTree();
if(ret != NULL)
{
if(node != root())//是否为根节点
{
//找到这个孩子(Noed)的父结点(GTreeNode),在父结点的孩子们(child链表)中移除(remove)该孩子
LinkList<GTreeNode<T>*>& child = dynamic_cast<GTreeNode<T>*>(node->parent)->child;
child.remove(child.find(node));
node->parent = NULL;
}
else
{
this->m_root = NULL;
}
ret->m_root = node;//将移除的结点作为一颗树返回
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException,"No enough memory to creat Tree ...");
}
}
int count(GTreeNode<T>* node)const
{
int ret = 0;
if(node != NULL)
{
ret = 1;
for(node->child.move(0);!node->child.end();node->child.next())
{
ret += count(node->child.current());
}
}
return ret;
}
/*自己写的递归height高度
int height(GTreeNode<T>* node,int n_height=0)const
{
int ret = 0;
if(node != NULL)
{
n_height++;
for(node->child.move(0);!node->child.end();node->child.next())
{
ret = height(node->child.current());
ret = n_height+1 > ret ? n_height+1 : ret;
}
}
return ret;
}
*/
int height(GTreeNode<T>* node)const
{
int ret = 0;
if(node != NULL)
{
for(node->child.move(0);!node->child.end();node->child.next())
{
int h = height(node->child.current());
ret = h > ret ? h : ret;
}
ret++;
}
return ret;
}
int degree(GTreeNode<T>* node)const
{
int ret = 0;
if(node != NULL)
{
ret = node->child.length();
for(node->child.move(0);!node->child.end();node->child.next())
{
int d = degree(node->child.current());
ret = d > ret ? d : ret;
}
}
return ret;
}
public:
bool insert(TreeNode<T>* node)//以结点插入,结点的父对象需要指明,即指明插入哪里
{
bool ret = true;
if(node != NULL)
{
if(this->m_root == NULL)//是否为空树
{
this->m_root = node;
node->parent = NULL;//根节点没有直接前驱
}
else
{
GTreeNode<T>* node_parent = find(node->parent);
if(node_parent != NULL)
{
GTreeNode<T>* n = dynamic_cast<GTreeNode<T>*>(node);
if(node_parent->child.find(n) < 0)//查找是否存在该子节点(防止重复插入)
{
node_parent->child.insert(n);
}
}
else
{
THROW_EXCEPTION(InvalidParameterException,"Invalid parrent tree node ...");
}
}
}
else
{
THROW_EXCEPTION(InvalidParameterException,"Parameter node cannot be NULL ...");
}
return ret;
}
bool insert(const T& value,TreeNode<T>* parent)//以值插入,结点的父对象需要指明,即指明插入哪里
{
bool ret = false;
GTreeNode<T>* new_node = GTreeNode<T>::NewNode();
if(new_node != NULL)
{
new_node->value = value;
new_node->parent = parent;
ret = insert(new_node);//代码复用
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException,"No memory to create new_node ...");
}
return ret;
}
//返回智能指针类型,函数返回值生命周期只有一条语句,如果没有智能指针接手,就会析构
SharedPointer< Tree<T> > remove(const T& value)
{
GTree<T>* ret = NULL;
GTreeNode<T>* del_node = find(value);
if(del_node != NULL)
{
remove(del_node,ret);
m_queue.clear();
}
else
{
THROW_EXCEPTION(InvalidParameterException,"Can not find the node via parameter value ...");
}
return ret;
}
SharedPointer< Tree<T> > remove(TreeNode<T>* node)
{
GTree<T>* ret = NULL;
GTreeNode<T>* del_node = find(node);
if(del_node != NULL)//树中是否存在该结点
{
remove(del_node,ret);
m_queue.clear();
}
else
{
THROW_EXCEPTION(InvalidParameterException,"Parameter node is invalid ...");
}
return ret;
}
GTreeNode<T>* find(const T& value)const
{
return find(root(),value);
}
GTreeNode<T>* find(TreeNode<T>* node)const
{
return find(root(),dynamic_cast<GTreeNode<T>*>(node));
}
GTreeNode<T>* root()const
{
return dynamic_cast<GTreeNode<T>*>(this->m_root);
}
int degree()const
{
return degree(root());
}
int count()const
{
return count(root());
}
int height()const
{
return height(root());
}
bool begin()
{
bool ret = (root() != NULL);
if(ret)
{
m_queue.clear();//清空队列,防止有上一次树剩余的子项
m_queue.add(root());//根节点加入队列
}
return ret;
}
bool next()//弹出队首,并插入child,next后
{
bool ret = (m_queue.length() > 0);
if(ret)
{
GTreeNode<T>* node = m_queue.front();//弹出首结点
m_queue.remove();
for(node->child.move(0);!node->child.end();node->child.next())//将该结点的孩子们加入队列
{
m_queue.add(node->child.current());
}
}
return ret;
}
T current()
{
if(!end())
{
return m_queue.front()->value;
}
else
{
THROW_EXCEPTION(InvalidOperationException,"No value at current queue ...");
}
}
bool end()
{
return (m_queue.length() == 0);
}
void clear()
{
free(root());
this->m_root = NULL;
m_queue.clear();
}
~GTree()
{
clear();
}
};
}
#endif
GTreeNode
GTreeNode.h
#ifndef __GTREENODE_H_
#define __GTREENODE_H_
#include "include/Object.h"
#include "include/LinkList.h"
namespace JYlib
{
/*
通用树节点
封装new,使得只能调用提供的静态成员函数NewNode,生成堆对象
在NewNode和构造函数中将堆对象做标记,区分是否为堆对象
*/
template < typename T >
class GTreeNode : public TreeNode<T>
{
public:
//链表的指向仍为指针,所以删除链表后,链表指向的内存仍然存在
LinkList<GTreeNode<T>*> child;//用链表完成指向任意多个后继的子节点
//创建堆对象并做标记,仅能通过该方式创建堆对象
static GTreeNode<T>* NewNode()
{
GTreeNode<T>* ret = new GTreeNode();
if(ret)
{
ret->m_flag = true;
}
return ret;
}
};
}
#endif