0
点赞
收藏
分享

微信扫一扫

【二叉树基本操作总结1】

江南北 2022-05-01 阅读 55
//二叉树链表存储
#include<iostream>
#include<queue>
#include<algorithm>
const int N=1e5+10;
using namespace std;
struct BiNode{
	char data;
	BiNode *lchild,*rchild;
};
class BiTree{
	private:
		BiNode* root;
	public:
		BiTree(){root=create(root);}
		~BiTree(){release(root);}
		BiNode* getRoot(){return root;}
		BiNode* create(BiNode *bt);
		void preOrder(BiNode* bt);
		void inOrder(BiNode* bt);
		void postOrder(BiNode* bt);
		void levelOrder(BiNode* bt);
		void release(BiNode* bt);
		int getDepth(BiNode* bt);
		int getNum(BiNode* bt);
		int getArray(BiNode* bt,char *array,int i); 
		
}; 
BiNode* BiTree::create(BiNode *bt){
	char ch;
	cin>>ch;
	if(ch=='#') bt=NULL; 
	else{
		bt=new BiNode;
		bt->data=ch;
		bt->lchild=create(bt->lchild);
		bt->rchild=create(bt->rchild);
	}
	return bt;
}

void BiTree::preOrder(BiNode* bt){
	if(bt==NULL) return;
	else{
		cout<<bt->data<<" ";
		preOrder(bt->lchild);
		preOrder(bt->rchild);
	}
	return;
}

void BiTree::inOrder(BiNode* bt){
	if(bt==NULL) return;
	else{
		inOrder(bt->lchild);
		cout<<bt->data<<" ";
		inOrder(bt->rchild);
	}
	return;
	
}

void BiTree::postOrder(BiNode* bt){
	if(bt==NULL) return;
	else{
		postOrder(bt->lchild);
		postOrder(bt->rchild);
		cout<<bt->data<<" "; 
	}
	return;
}

void BiTree::levelOrder(BiNode* bt){
	if(bt==NULL) return;
	queue<BiNode*> Q;
	Q.push(bt);
	BiNode* p;
	while(!Q.empty()){
		p=Q.front();
		Q.pop();
		cout<<p->data<<" ";
		if(p->lchild!=NULL) Q.push(p->lchild);
		if(p->rchild!=NULL) Q.push(p->rchild);
	}
	return;
}
//后序遍历删除结点 
void BiTree::release(BiNode* bt){
	BiNode* p=bt;
	if(p->lchild==NULL&&p->rchild==NULL){
		cout<<"delete "<<p->data<<endl;
		delete p;
	}
	else{
		if(p->lchild!=NULL) release(bt->lchild);
		if(p->rchild!=NULL) release(bt->rchild);
		cout<<"delete "<<p->data<<endl;
		delete p;
	}
	return;
}

int BiTree::getDepth(BiNode* bt){
//	if(bt->lchild==NULL&&bt->rchild==NULL) return 1;
//	else{
//		int left=0,right=0;
//		if(bt->lchild!=NULL) left=getDepth(bt->lchild);
//		if(bt->rchild!=NULL) right=getDepth(bt->rchild);
//		return max(left,right)+1;
//	}
	if(bt==NULL) return 0;
	int left=getDepth(bt->lchild);
	int right=getDepth(bt->rchild);
	return max(left,right)+1;
} 

int BiTree::getNum(BiNode* bt){
	if(bt==NULL) return 0;
	int left=getNum(bt->lchild);
	int right=getNum(bt->rchild);
	return left+right+1;
}
int BiTree::getArray(BiNode* bt,char *array,int i){
	BiNode* p=bt;
	if(p==NULL) return i/2;
	array[i]=p->data;
	int left=getArray(p->lchild,array,i*2);
	int right=getArray(p->rchild,array,i*2+1);
	return max(left,right);
}


int main(){
	BiTree BT;
	BiNode* r=BT.getRoot();
	cout<<"前序遍历"<<endl;
	BT.preOrder(r);
	cout<<endl;
	cout<<"中序遍历"<<endl;
	BT.inOrder(r);
	cout<<endl;
	cout<<"后序遍历"<<endl;
	BT.postOrder(r);
	cout<<endl;
	cout<<"层序遍历"<<endl;
	BT.levelOrder(r);
	cout<<endl; 
	cout<<"深度:"<<endl;
	cout<<BT.getDepth(r)<<endl;
	cout<<"结点个数:"<<endl;
	cout<<BT.getNum(r)<<endl;
	cout<<"转化为一维数组的形式"<<endl;
	char array[N];
	int len=BT.getArray(r,array,1);
	for(int i=1;i<=len;i++){
		if(array[i]=='\0') cout<<'^';
		else cout<<array[i];
	} 
	cout<<"开始析构了!"<<endl;
	
	return 0;
	
} 

以该二叉树为例,试试效果

 打印效果图如下

下面我们把各个函数单拎出来浅讲一下

构造函数

BiTree(){root=create(root);}

BiNode* create(BiNode *bt);

这里在构造函数里面调用creat,因为需要使用递归调用函数且new 一个空间。这里切记root=create(root) 

是我容易错的

前、中、后序遍历

以    preOrder(BiNode* bt)为例

遍历也是递归的写法,没啥好讲的。

层序遍历

levelOrder(BiNode* bt)

层序遍历是这里使用了一个容器,STL里面的队列。

说明一下使用到的函数吧:

 

 因为之前自己写代码实现队列的时候,pop()是有返回值的。这里只可以通过front()访问,写的时候d了一下bug.

这里的思路就是,将根节点入队,在每次出队的时候就检查它是否有左右子树。如果有就入队(利用队列先进先出的特性)

析构函数

~BiNode(release(root));

release(BiNode* bt)

这里需要逐步回收刚才new的空间,众周知,二叉树是通过根节点来访问子节点的,如果你把根节点delete了,左右子树就没有办法回收了,所以我们这里采用后序访问的方法来delete.

如果已经是叶节点了(没有左右子树)就直接de

如果是分支结点,就需要先de左右子树,然后再de自己。

求深度

getDepth(BiNode* bt);

深度,众周知,就是一颗二叉树最大的深度。那么我们,先求出左边的深度和右边的深度,取最大的,再加上自己这一层的1,返回。然后递归调用。

求结点数

getNum(BiNode* bt);

结点数与深度可谓是异曲同工之妙。

我们就把“先求出左边的深度和右边的深度,取最大的,再加上自己这一层的1”换成“求左边个数和右边个数,相加,再加上自己的1”,递归调用即可。

转化为一维数组

getArray(BiNode* bt,char *array,int i);

这里与前序类似,但多了一个将遍历的结果储存(且按二叉树的性质储存)这一步。

性质:

一点坐标是i    (下标从1开始)

则左子树 (的根节点)==i*2

右子树(的根节点)==i*2+1

采取的策略是,只存储含有实际值的数据.

在遍历数组的时候,如果没有数据,我们就手动打印‘^’

我在写的是后遇到的问题:

不知道数组开多大------>策略:往大了开1e5+10

怎么判断结尾------>好问题,仔细看看下面代码

if(p==NULL) return i/2;


max(left,right);

一个是访问到叶节点后的回溯

一个数取得数组得最大下标

over!

举报

相关推荐

0 条评论