敲代码中遇到的最大的一个坑是:如果原来有一个指针ptr1,指向的地址为0X,然后新声明一个指针ptr2,也让ptr2指向的地址为0X,对ptr2进行操作能够影响到0X地址,间接地影响指针ptr1,但本质上ptr1和ptr2是两个指针,因为发生的是拷贝,拷贝的对象当然是两个!一个具体的例子:执行“delete ptr2;ptr2=nullptr;”,ptr1指向的地址已经被销毁,但ptr1不会被置为nullptr,而依然指向原地址。也正是因为这个坑,代码里才有如此多的引用“&”,引用的本质是别名,而不是一个新的指针。
第二个坑是模板的嵌套。我想将struct TNode作为class BinTree的成员以提高封装性,这导致了模板类型的嵌套,具体的可以参考这篇博文:
C++模版中的typename关键字和嵌套依赖类型(依赖名称)
后续会继续补全树的相关操作,比如平衡树的调整~~~
更新~~平衡二叉树的基本实现请参考我的这一篇PAT Root of AVL Tree(C++实现)
#pragma once
#include<iostream>
using std::cout;
using std::cin;
using std::endl;
template<typename T>
class BinTree
{
public:
struct TNode {
T Data;//结点数据
TNode* Left;//指向左子树
TNode* Right;//指向右子树
};
using Root = TNode*;
using Position = TNode*;
private:
Root BT;//二叉树的根结点的地址
public:
BinTree();
~BinTree();
void Destroy(Position& BT);
const bool& IsEmpty();
Position& GetRoot();
void PreorderTraversal(Position BT);
void InorderTraversal(Position BT);
int GetHeight(Position BT);
Position& Find(Position& BT, const T& X);
Position& FindMax(Position& BT);
Position& FindMin(Position& BT);
Position Insert(Position& BT, const T& X);
const bool& Delete(Position& BT, const T& X);
};
template<typename T>
BinTree<T>::BinTree() :BT{ nullptr }
{}
//销毁树
template<typename T>
void BinTree<T>::Destroy(Position& BT)
{
if (!BT)
;
else {
Destroy(BT->Left);
Destroy(BT->Right);
delete BT;
BT = nullptr;
}
}
template<typename T>
BinTree<T>::~BinTree()
{
Destroy(this->GetRoot());
}
//判断是否为空树
template<typename T>
const bool& BinTree<T>::IsEmpty()
{
if (BT)
return false;
else
return true;
}
//返回根结点
template<typename T>
typename BinTree<T>::Position& BinTree<T>::GetRoot()
{
return BT;
}
//递归求树的高度
template<typename T>
int BinTree<T>::GetHeight(Position BT)
{
int HL{ 0 }, HR{ 0 };
if (!BT)
return 0;
else {
HL = GetHeight(BT->Left);
HR = GetHeight(BT->Right);
return (HL > HR ? HL : HR) + 1;
}
}
//先序遍历
template<typename T>
void BinTree<T>::PreorderTraversal(Position BT)
{
if (BT) {
cout << BT->Data << ' ';
PreorderTraversal(BT->Left);
PreorderTraversal(BT->Right);
}
}
//中序遍历
template<typename T>
void BinTree<T>::InorderTraversal(Position BT)
{
if (BT) {
InorderTraversal(BT->Left);
cout << BT->Data << ' ';
InorderTraversal(BT->Right);
}
}
//递归查找元素
template<typename T>
typename BinTree<T>::Position& BinTree<T>::Find(Position& BT, const T& X)
{
if (!BT)
return BT;
else {
if (BT->Data > X)
return Find(BT->Left, X);
else if (BT->Data < X)
return Find(BT->Right, X);
else
return BT;
}
}
//递归查找最大元素
template<typename T>
typename BinTree<T>::Position& BinTree<T>::FindMax(Position& BT)
{
if (!BT)
return BT;
else if (!BT->Right)
return BT;
else
return FindMax(BT->Right);
}
//递归查找最小元素
template<typename T>
typename BinTree<T>::Position& BinTree<T>::FindMin(Position& BT)
{
if (!BT)
return BT;
else if (!BT->Left)
return BT;
else
return FindMin(BT->Left);
}
//插入元素
template<typename T>
typename BinTree<T>::Position BinTree<T>::Insert(Position& BT, const T& X)
{
if (!BT) {
BT = new TNode;
BT->Data = X;
BT->Left = nullptr;
BT->Right = nullptr;
return BT;
}
else if (X > BT->Data) {
return Insert(BT->Right, X);
}
else if (X < BT->Data) {
return Insert(BT->Left, X);
}
else
return BT;
}
//删除结点
template<typename T>
const bool& BinTree<T>::Delete(Position& BT, const T& X)
{
Position& removeBT = Find(BT, X);//找到要删除的元素
if (!removeBT)
return false;
else {
if (removeBT->Left && removeBT->Right) {//待删结点有两个孩子
Position temp;
temp = FindMin(removeBT->Right);//找到该结点右子树的最小结点
removeBT->Data = temp->Data;
delete temp;
temp = nullptr;
return true;
}
else if (removeBT->Left && !removeBT->Right) {//待删结点只有左孩子
Position temp{ removeBT };
removeBT = removeBT->Left;
delete temp;
temp = nullptr;
return true;
}
else if (!removeBT->Left && removeBT->Right) {//待删结点只有右孩子
Position temp{ removeBT };
removeBT = removeBT->Right;
delete temp;
temp = nullptr;
return true;
}
else {//待删结点没有孩子
delete removeBT;
removeBT = nullptr;
return true;
}
}
}
#include<iostream>
#include"BinTree.h"
using namespace std;
int GetRandom(int X)//返回0到X-1之间的随机数
{
return rand() % X;
}
int main()
{
BinTree<int> BT1{};
BT1.Insert(BT1.GetRoot(), 41);
BT1.Insert(BT1.GetRoot(), 34);
BT1.Insert(BT1.GetRoot(), 0);
BT1.Insert(BT1.GetRoot(), 24);
BT1.Insert(BT1.GetRoot(), 67);
BT1.Insert(BT1.GetRoot(), 58);
BT1.Insert(BT1.GetRoot(), 62);
BT1.Insert(BT1.GetRoot(), 64);
BT1.Insert(BT1.GetRoot(), 69);
BT1.Insert(BT1.GetRoot(), 78);
cout << BT1.GetHeight(BT1.GetRoot()) << '\n';
BT1.PreorderTraversal(BT1.GetRoot());
cout << '\n';
BT1.InorderTraversal(BT1.GetRoot());
BT1.Delete(BT1.GetRoot(), 64);
cout << '\n';
BT1.PreorderTraversal(BT1.GetRoot());
cout<< '\n';
cout << BT1.GetHeight(BT1.GetRoot()) << '\n';
return 0;
}