#include<iostream>
#include<deque> // 层级遍历 用到 队列
using namespace std;
template <typename T>
struct TreeNode //树节点
{
T data;
TreeNode* lchild;
TreeNode* rchild;
TreeNode():data(0),lchild(NULL),rchild(NULL){}
};
//链式存储
template <typename T>
class LinkTree
{
TreeNode<T>* pRoot; //根节点
public:
LinkTree();
~LinkTree();
TreeNode<T>* initTree(T arr[],size_t len,int index=0);
//len 数组长度 index 初始化位置 默认从0开始初始化
private:
void clear(TreeNode<T>*& root); //清空树
void prePrint(TreeNode<T>*& root); //前序遍历
void inPrint(TreeNode<T>*& root); //中序遍历
void posPrint(TreeNode<T>*& root); //后序遍历
void levelPrint(); //层级遍历 不需要参数
public:
//类外不能访问私有成员,重载上述访问私有成员的方法,封装
void clear();
void prePrint();
void inPrint();
void posPrint();
};
/* 关键字 inline
在函数声明或定义中,函数返回类型前加上关键字inline,即可以把函数指定为内联函数。
(1)内联函数的作用
●对于内联函数,C++有可能直接用函数体代码来替代对函数的调用,这一过程称为函数体的内联展开。
●对于只有几条语句的小函数来说,与函数的调用、返回有关的准备和收尾工作的代码往往比函数体本身的代码要大得多。
因此,对于这类简单的、使用频繁的小函数,将之说明为内联函数可提高运行效率。
(2)慎用内联函数
内联是以代码膨胀复制为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。
如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。
另一方面,每一处内联函数的调用都要复制代码, 将使程序的总代码量增大,消耗更多的内存空间。
以下情况不宜使用内联:
1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。
2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。
*/
template <typename T>
inline LinkTree<T>::LinkTree()
{
pRoot = NULL;
}
template <typename T>
inline LinkTree<T>::~LinkTree()
{
clear(); //清空树
}
template <typename T>
inline void LinkTree<T>::clear()
{
clear(pRoot); //根据根 找到所有结点 释放内存
}
template <typename T>
inline void LinkTree<T>::clear(TreeNode<T>*& root)
{
if(root)
{
clear(root->lchild);
clear(root->rchild);
}
delete root;
root = NULL;
}
template <typename T>
inline TreeNode<T>* LinkTree<T>::initTree(T arr[], size_t len, int index) //初始化
{
if(index >= len)
{
return NULL;
}
TreeNode<T>* tempNode = new TreeNode<T>;
//递归
tempNode->data = arr[index]; //根
tempNode->lchild = initTree(arr,len,index*2+1); //左子树
tempNode->rchild = initTree(arr,len,index*2+2); //右子树
pRoot = tempNode;
return pRoot;
}
template <typename T>
inline void LinkTree<T>::prePrint() //前序遍历
{
prePrint(pRoot);
}
template <typename T>
inline void LinkTree<T>::prePrint(TreeNode<T>*& root)
{
if(root)
{
cout<< root->data <<" "; //根 左 右
prePrint(root->lchild);
prePrint(root->rchild);
}
}
template <typename T>
inline void LinkTree<T>::inPrint() //中序遍历
{
inPrint(pRoot);
}
template <typename T>
inline void LinkTree<T>::inPrint(TreeNode<T>*& root)
{
if(root)
{
inPrint(root->lchild); //左 根 右
cout<< root->data <<" ";
inPrint(root->rchild);
}
}
template <typename T>
inline void LinkTree<T>::posPrint() //后序遍历
{
posPrint(pRoot);
}
template <typename T>
inline void LinkTree<T>::posPrint(TreeNode<T>*& root)
{
if(root)
{
posPrint(root->lchild); //左 右 根
posPrint(root->rchild);
cout<< root->data <<" ";
}
}
//层级遍历 队列
template <typename T>
inline void LinkTree<T>::levelPrint()
{
deque<TreeNode<T>*>* deq = new deque<TreeNode<T>*>; // 双端队列 也可以用 queue
TreeNode<T>* root = pRoot; // 保存根 队列的头结点
deq->push_back(root); // 根结点入列
while(!deq->empty()) // 不是空列 一直循环
{
root = deq->front(); // 保存头结点
cout << root->data << " "; // 输出头结点
deq->pop_front(); // 头结点 出列
if (root->lchild) // 如果有左子树,则入列
{
deq->push_back(root->lchild);
}
if (root->rchild) // 如果有右子树,则入列
{
deq->push_back(root->rchild);
}
}
}
int main()
{
LinkTree<int>* MyTreeTwo = new LinkTree<int>();
int arr[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
int nSize = sizeof(arr) / sizeof(arr[0]);
MyTreeTwo->initTree(arr, nSize);
// 四种不同的遍历方式
cout << "前序遍历: ";
MyTreeTwo->prePrint();
cout << endl;
cout << "中序遍历: ";
MyTreeTwo->inPrint();
cout << endl;
cout << "后序遍历: ";
MyTreeTwo->posPrint();
cout << endl;
MyTreeTwo->clear();
delete MyTreeTwo;
MyTreeTwo = NULL;
}
LinkTree
最新推荐文章于 2021-11-30 15:54:44 发布