一、树的基本概念
1.树的结构
三指针描述一颗树、无序二叉树、有序二叉树、二叉搜索树、完全二叉树、堆、平衡二叉树、23树 、B B+、红黑二叉树
2.树的基础概念.
树 子树 节点
父节点 孩子节点 爷爷节点 叔叔节点 兄弟节点
根: 树的第一个节点 树根
叶子:没有孩子的节点 树叶
枝干:不是根也不是叶子 枝干二叉树 三叉树 四叉树 八叉树
叉:允许的最大分支数量
放开三胎之前 二叉树高度 层数:几代(最短路径+1)
链表:
next prev
二叉树:
left right
三:
p1 p2 p3
四:
p1 p2 p3 p4族谱:N叉树
二、设计:每个结点3个指针实现无序N叉树的增删改查
3个指针,一个指针指向父节点,一个指针指向兄弟节点,一个指针指向第一个孩子节点。 其中兄弟节点指针 便是这个设计的关键,它描述清楚了同层关系。
如上图所示,具有3个指针的节点 便描述清楚了 一颗任意叉树的所有关系。
#include <iostream>
using namespace std;
//三个指针描述一颗N查树
template<class T>
class MyTree
{
//树的节点类型
struct Node
{
T data;
Node* pParent;
Node* pBrother;
Node* pChild;
};
private:
Node* pRoot;//树的成员 指向根节点的指针
public:
MyTree();
~MyTree();
//创建节点并返回
Node* createNode(const T& data);
/*
插入节点到树中
insertData:要插入的节点的数据
findData: 要插入的节点想要成为 findData节点的孩子或者兄弟
isBrother: true 成为兄弟 false 成为孩子
*/
bool insertNode(const T& findData, const T& insertData, bool isBrother = true);
//从树中查找数据为findData的节点 找到了返回节点地址,否则返回NULL
Node* findNode(const T& findData);
//从树中删除第一个数据为delData的节点
bool deleteNode(const T& delData);
};
template<class T>
MyTree<T>::MyTree()
{pRoot = NULL;}
template<class T>
MyTree<T>::~MyTree()
{}
三、具体代码实现:
1.createNode(memset初始化)
typename MyTree<T>::Node* MyTree<T>::createNode(const T& data)
{
Node* pNew = new Node;
if (NULL == pNew) return NULL;//防呆
memset(pNew, 0, sizeof(Node));
pNew->data = data;
return pNew;
}
/*
2.findNode
遍历思路:首先设置两个箭头,一个箭头用来向下遍历,一个箭头用来向右遍历,先向右遍历完一层,然后向下遍历一个。
template<class T>
//从树中查找数据为findData的节点 找到了返回节点地址,否则返回NULL
typename MyTree<T>::Node* MyTree<T>::findNode(const T& findData)
{
if (NULL == pRoot) return NULL;
Node* pCurrent = pRoot;//当前层
Node* pTemp = NULL;//当前层的当前节点
while (pCurrent)
{//层之间切换
pTemp = pCurrent;//
while (pTemp)
{//当前层往右
if (findData == pTemp->data)return pTemp;
pTemp = pTemp->pBrother;
}
pCurrent = pCurrent->pChild;//层之间切换
}
return NULL;
}
3.insertNode
自己定规则:(此处仅大儿子有child)
/*Args: 说明
插入节点到树中
insertData:要插入的节点的数据
findData: 要插入的节点想要成为 findData节点的孩子或者兄弟
isBrother: true 成为兄弟 false 成为孩子*/如果树为空: 直接成为根节点
如果树不为空:
-成为兄弟(is_brother):
--找到了:
---本来有兄弟:成为最小兄弟
---本来没兄弟:成为兄弟--没找到:成为根节点的最小兄弟
-成为孩子(is_child):
--找到了:
---本来有孩子:成为最小孩子
---本来没孩子:成为孩子
--没找到:成为根节点的最小孩子
template<class T>
bool MyTree<T>::insertNode(const T& findData, const T& insertData, bool isBrother)
{
Node* pNew = createNode(insertData);
if (NULL == pNew) return false;
if (NULL == pRoot){//如果树为空: 直接成为根节点
pRoot = pNew;
return true;
}
Node* pInsert = findNode(findData);
Node* pTemp = NULL;
if (isBrother)
{//成为兄弟:
if (pInsert)
{//找到了:
cout << "找到了" << endl;
//找到pInsert的最小兄弟
pTemp = pInsert;
while (pTemp->pBrother)
{//pTemp指向根节点的最后一个兄弟
pTemp = pTemp->pBrother;
}
//插入
pTemp->pBrother = pNew;
pNew->pParent = pTemp->pParent;
}
else
{//没找到//成为根节点的最小兄弟
pTemp = pRoot;//让pTemp指向根节点
while (pTemp->pBrother)
{//pTemp指向根节点的最后一个兄弟
pTemp = pTemp->pBrother;
}
//新节点给pTemp的pBrother赋值
pTemp->pBrother = pNew;
}
}
else
{//成为孩子:
if (pInsert)
{//找到了:
cout << "找到了" << endl;
//找到pInsert的最小孩子
pTemp = pInsert;
while (pTemp->pChild)
{
pTemp = pTemp->pChild;
}
//插入
pTemp->pChild = pNew;
pNew->pParent = pTemp;
}
else
{//没找到
//成为根节点的最小孩子
pTemp = pRoot;//让pTemp指向根节点
while (pTemp->pChild)
{//pTemp指向根节点的最后一个孩子
pTemp = pTemp->pChild;
}
//新节点给pTemp的pChild赋值
pTemp->pChild = pNew;
}
}
return true;
}
4.deleteNode
函数功能:删除树中某个节点,删除成功,返回true,否则返回false
实现思路(规则):先findNode找结点,找不到false
若结点是pRoot:
若pRoot有兄弟:
①兄弟成为pRoot+②原来的大儿子pchild给兄弟领养+③循环重置大儿子及其 兄弟的pParent结点至新父节点(更新pParent)
若pRoot没有兄弟:
①大儿子pChild成为根节点+②循环重置大儿子及其兄弟的pParent的指针 (更新pParent)
若结点不是pRoot(删枝干or叶子):
若delNode不是大儿子:
得到delNode的父节点->得大儿子结点并循环遍历本层至delNode的前一结点 ->删除delete即可。
若delNode是大儿子:
若delNode还有兄弟:
①让其第一个兄弟成为大儿子(pChild)+②delNode的儿子给兄弟领养+
③领养完之后,重置儿子们的pParent指针。
若delNode没有兄弟:
①delNode的孩子全部给父节点pParent领养+②循环重置孩子的pParent 结点
template<class T>
//从树中删除第一个数据为delData的节点
bool MyTree<T>::deleteNode(const T& delData)
{
Node* pDel = findNode(delData);
if (NULL == pDel)
{
return false;
}
Node* pTemp = NULL;
if (pDel == pRoot)
{//要删的节点是根节点
if (pDel->pBrother)
{//有兄弟
//兄弟成为根
pRoot = pDel->pBrother;
//pDel的孩子成为新的根节点的孩子
pTemp = pDel->pChild;
pRoot->pChild = pTemp;//上指向下
while (pTemp)
{//下指向上
pTemp->pParent = pRoot;
pTemp = pTemp->pBrother;
}
}
else
{//没有兄弟
pRoot = pDel->pChild;
pTemp = pDel->pChild;
while (pTemp)
{//下指向上
pTemp->pParent = NULL;//parent置为NULL
pTemp = pTemp->pBrother;
}
}
delete pDel;
return true;
}
//删枝干或者叶子
Node* pFather = pDel->pParent;
if (pDel != pFather->pChild)
{//要删的节点不是其父节点的孩子
//找到pDel的前一个节点
pTemp = pFather->pChild;
while (pTemp->pBrother != pDel)//让pTemp指向pDel的前一个节点
pTemp = pTemp->pBrother;
pTemp->pBrother = pDel->pBrother;
delete pDel;
return true;
}
//要删的节点是其父节点的孩子
if (pDel->pBrother)
{//有兄弟
//pDel的第一个兄弟成为它的父节点的孩子
pFather->pChild = pDel->pBrother;
pDel->pBrother->pChild = pDel->pChild;
//pDel的孩子成为 pDel->pBrother 的孩子
pTemp = pDel->pChild;
while (pTemp)
{//把自己的孩子全部给兄弟进行领养
pTemp->pParent = pDel->pBrother;
pTemp = pTemp->pBrother;
}
}
else
{//没有兄弟
//pDel的孩子成为它的父节点的孩子(由父亲领养)
pFather->pChild = pDel->pChild;
//pDel的孩子们成为 pFather 的孩子
pTemp = pDel->pChild;
while (pTemp)
{
pTemp->pParent = pFather;
pTemp = pTemp->pBrother;
}
}
delete pDel;
return true;
}