这几天尬在二叉表的实现了,发现删除节点是真的写的头疼,最后还是没有实现。迭代遍历也是,但是掌握了思想之后也还是能实现,大概就这样吧
1.二叉树类与二叉树节点类
template<typename T> class BinaryTreeNode
{
public:
T m_value;
int m_height;
BinaryTreeNode() {}
BinaryTreeNode(T value) : m_value(value) {}
BinaryTreeNode<T> *m_leftchild;
BinaryTreeNode<T> *m_rightchild;
BinaryTreeNode<T> *m_parent;
};
template<typename T> class BinaryTree
{
public:
BinaryTreeNode<T> *m_root;
void visit(BinaryTreeNode<T>* node) { cout << node->m_value << " "; }
//三种递归遍历方式,究极简单并且易于理解(均从根节点开始,按顺序递归即可)
void travPre_Recursion(BinaryTreeNode<T>* node);
void travMid_Recursion(BinaryTreeNode<T>* node);
void travPos_Recursion(BinaryTreeNode<T>* node);
void travPre_Circulate(BinaryTreeNode<T>* node);
void travMid_Circulate(BinaryTreeNode<T>* node);
void travPos_Circulate(BinaryTreeNode<T>* node);
int m_size;
void updateHeight(BinaryTreeNode<T>* node);
BinaryTree() : m_size(0), m_root(NULL) {};
BinaryTreeNode<T>* insertAsRoot(T const &value);
int remove(BinaryTreeNode<T>* node); //返回由于此节点被删除而导致删除的节点总数
int removeAt(BinaryTreeNode<T>* node);
BinaryTreeNode<T>* insertAsLeftChild(BinaryTreeNode<T>* parent, T const &value);
BinaryTreeNode<T>* insertAsRightChild(BinaryTreeNode<T>* parent, T const &value);
};
2.相关函数的实现代码
2.1 前序中序后序递归遍历
- 简单无脑,visit函数为数据处理函数
template<typename T> void BinaryTree<T>::travPre_Recursion(BinaryTreeNode<T>* node)
{
if (node == NULL)
return;
visit(node);
travPre_Recursion(node->m_leftchild);
travPre_Recursion(node->m_rightchild);
}
template<typename T> void BinaryTree<T>::travMid_Recursion(BinaryTreeNode<T>* node)
{
if (node == NULL)
return;
travMid_Recursion(node->m_leftchild);
visit(node);
travMid_Recursion(node->m_rightchild);
}
template<typename T> void BinaryTree<T>::travPos_Recursion(BinaryTreeNode<T>* node)
{
if (node == NULL)
return;
travPos_Recursion(node->m_leftchild);
travPos_Recursion(node->m_rightchild);
visit(node);
}
2.2 前序中序后序迭代遍历
- 迭代的实现主要是思想,本文中使用的为:确定起始点,根据起始点按照标准流程不断向前计算(核心思想是,对应不同顺序,对于栈中节点的操作,以及节点的存储方式均有所不同)
template<typename T> void BinaryTree<T>::travPre_Circulate(BinaryTreeNode<T>* node)
{
stack<BinaryTreeNode<T>*> sss;
list<BinaryTreeNode<T>*> slist;
//1.先序遍历,灵魂的根—左—右,按照所经过的顺序直接进行遍历
sss.push(node);
while (!sss.empty())
{
node = sss.top(); sss.pop();
slist.push_back(node);
if (node->m_rightchild != NULL)
{
sss.push(node->m_rightchild);
}
if (node->m_leftchild != NULL)
{
sss.push(node->m_leftchild);
}
}
for (auto &s : slist)
cout << s->m_value << " ";
}
template<typename T> void BinaryTree<T>::travMid_Circulate(BinaryTreeNode<T>* node)
{
stack<BinaryTreeNode<T>*> sss;
list<BinaryTreeNode<T>*> slist;
//2.中序遍历,独特的左—根—右,首先找到初始节点为最左边的值,然后根据左—根—右开始遍历
//do while的原因在于最开始栈一直为空
do
{
while (node != NULL)
{
sss.push(node);
node = node->m_leftchild;
}
if (!sss.empty())
{
node = sss.top(); sss.pop();
slist.push_back(node);
node = node->m_rightchild;
}
} while (!sss.empty() || node != NULL);
for (auto &s : slist)
cout << s->m_value << " ";
}
template<typename T> void BinaryTree<T>::travPos_Circulate(BinaryTreeNode<T>* node)
{
stack<BinaryTreeNode<T>*> sss;
list<BinaryTreeNode<T>*> slist;
//后序遍历为左—右—根,实现方式为反转后调整左右先后顺序
sss.push(node);
while (!sss.empty())
{
node = sss.top(); sss.pop();
slist.push_front(node);
if (node->m_leftchild != NULL)
{
sss.push(node->m_leftchild);
}
if (node->m_rightchild != NULL)
{
sss.push(node->m_rightchild);
}
}
for (auto &s : slist)
cout << s->m_value << " ";
}
2.3 节点高度更新函数
- 每当有节点插入/退出二叉树中时,调用高度更新,更新其所有父节点的高度数值(核心思想在于,父树高度为子树高度+1,而没有子树的节点高度为0(-1+1))
template<typename T> void BinaryTree<T>::updateHeight(BinaryTreeNode<T>* node)
{
if (node == NULL)
return;
int leftHeight = -1;
if (node->m_leftchild != NULL)
leftHeight = node->m_leftchild->m_height;
int rightHeight = -1;
if (node->m_rightchild != NULL)
rightHeight = node->m_rightchild->m_height;
node->m_height = 1 + ((leftHeight > rightHeight) ? (leftHeight) : (rightHeight));
updateHeight(node->m_parent);
}
2.4 根节点左节点右节点的插入
- 顾名思义的函数功能
template<typename T> BinaryTreeNode<T>* BinaryTree<T>::insertAsRoot(T const &value)
{
BinaryTreeNode<T>* node = new BinaryTreeNode<T>;
node->m_value = value;
if (m_root == NULL)
{
m_root = node;
}
else
{
m_root->m_parent = node;
node->m_leftchild = m_root;
m_root = node;
}
m_size++;
return node;
}
template<typename T> BinaryTreeNode<T>* BinaryTree<T>::insertAsLeftChild(BinaryTreeNode<T>* parent, T const &value)
{
BinaryTreeNode<T>* node = new BinaryTreeNode<T>;
node->m_value = value;
node->m_parent = parent;
parent->m_leftchild = node;
m_size++;
updateHeight(node->m_parent);
return node;
}
template<typename T> BinaryTreeNode<T>* BinaryTree<T>::insertAsRightChild(BinaryTreeNode<T>* parent, T const &value)
{
BinaryTreeNode<T>* node = new BinaryTreeNode<T>;
node->m_value = value;
node->m_parent = parent;
parent->m_rightchild = node;
m_size++;
updateHeight(node->m_parent);
return node;
}
3.测试用主函数
- remove函数终究还是没有实现,所以就只测试了插入、高度与遍历
int main()
{
BinaryTree<int>* tree = new BinaryTree<int>;
BinaryTreeNode<int>* node0 = tree->insertAsRoot(0);
BinaryTreeNode<int>* node1 = tree->insertAsLeftChild(node0, 1);
BinaryTreeNode<int>* node2 = tree->insertAsRightChild(node0, 2);
BinaryTreeNode<int>* node3 = tree->insertAsLeftChild(node1, 3);
BinaryTreeNode<int>* node4 = tree->insertAsRightChild(node1, 4);
BinaryTreeNode<int>* node5 = tree->insertAsLeftChild(node2, 5);
BinaryTreeNode<int>* node6 = tree->insertAsRightChild(node2, 6);
cout << "迭代前序遍历:";
tree->travPre_Recursion(tree->m_root);
cout << endl;
cout << "迭代中序遍历:";
tree->travMid_Recursion(tree->m_root);
cout << endl;
cout << "迭代后序遍历:";
tree->travPos_Recursion(tree->m_root);
cout << endl;
cout << "循环前序遍历:";
tree->travPre_Circulate(tree->m_root);
cout << endl;
cout << "循环中序遍历:";
tree->travMid_Circulate(tree->m_root);
cout << endl;
cout << "循环后序遍历:";
tree->travPos_Circulate(tree->m_root);
cout << endl;
cout << "node0 height:" << node0->m_height << endl;
cout << "node1 height:" << node1->m_height << endl;
cout << "node2 height:" << node2->m_height << endl;
cout << "node3 height:" << node3->m_height << endl;
//这里涉及到的delete,释放的时机应该是“谁申请,谁释放”;
//cout << "tree->remove(node1):" << tree->remove(node1) << endl;
//cout << "tree->remove(node2):" << tree->remove(node2) << endl;
//cout << "tree->remove(node3):" << tree->remove(node3) << endl;
//cout << "tree->remove(node0):" << tree->remove(node0) << endl;
delete node3;
delete node2;
delete node1;
delete node0;
return 0;
}