LinkTree

#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;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值