【算法学习】二叉树

一。递归定义

① 要么二叉树没有根结点,是一个空树

②要么二叉树由根结点、左子树、右子树组成,且左子树和右子树都是二叉树


二叉树的许多算法都需要直接用到这个递归的定义来实现算法。


二。存储结构

使用链表来定义,定义方式如下:

struct node{
	typename data;   //数据域
	node* lchild;    //指向左子树根结点的指针
	node* rchild;    //指向右子树根结点的指针 
};
由于二叉树建树前根结点不存在,因此其地址一般设为NULL

扫描二维码关注公众号,回复: 2505616 查看本文章
node* root = NULL;
如果需要新建结点(例如往二叉树中插入结点的时候),可以使用下面函数:

node* newNode(int v){
	node* Node = new node;    //申请一个node型变量的地址空间
	Node->data = v;           //结点权值为v
	Node->lchild = Node->rchild = NULL;    //初始状态下没有左右孩子
	return Node;              //返回新建结点的地址 
}

三。基本操作

1. 结点的查找修改

思路:先判断当前结点是否是需要查找的结点,如果是则对其进行修改操作,如果不是,则分别往该结点的左孩子和右孩子递归,直到当前结点为NULL为止

void search(node* root, int x, int newdata){
	if(root == NULL){
		return;   //空树(递归边界) 
	}
	if(root->data == x){     //找到数据域为x的结点,把它修改为newdata 
		root->data = newdata; 
	} 
	search(root->lchlid, x, newdata);   //往左子树搜索x(递归式) 
	search(root->rchild, x, newdata);   //往右子树搜索x(递归式) 
}

2. 结点的插入

注意,insert函数必须加引用,而前面的search函数不用加引用。因为search函数中修改的是指针root指向的内容,而不是root本身。





四。二叉树遍历

1. 先序遍历

根结点->左子树->右子树

void preorder(node* root){
	if(root == NULL){
		return;   //到达空树,递归边界 
	}
	printf("%d\n", root->data);   //访问根结点root,例如将其数据域输出
	preorder(root->lchild);       //访问左子树 
	preorder(root->rchild);       //访问右子树 
} 

2. 中序遍历

左子树->根结点->右子树

void inorder(node* root){
	if(root == NULL){
		return;   //到达空树,递归边界 
	}
	preorder(root->lchild);       //访问左子树 
	printf("%d\n", root->data);   //访问根结点root,例如将其数据域输出
	preorder(root->rchild);       //访问右子树 
} 

只要知道根结点,就可以根据根结点在中序遍历序列中的位置区分出左子树和右子树


3. 后序遍历

左子树->右子树->根结点

void postorder(node* root){
	if(root == NULL){
		return;   //到达空树,递归边界 
	}
	preorder(root->lchild);       //访问左子树 
	preorder(root->rchild);       //访问右子树 
	printf("%d\n", root->data);   //访问根结点root,例如将其数据域输出
} 

4. 层序遍历

层序遍历相当于对二叉树从根结点开始的广度优先搜索。

void LayerOrder(node* root){
	queue<node*> q;    //注意队列中是存地址
	q.push(root);      //将根结点地址入队
	while(!q.empty()){
		node* now = q.front();     //取出队首元素
		q.pop();
		printf("%d ", now->data);  //访问队首元素
		if(now->lchild != NULL)  q.push(now->lchild);   //左子树非空
		if(now->rchild != NULL)  q.push(now->rchild);   //右子树非空 
	} 
} 

5. 根据先序遍历序列和中序遍历序列构造二叉树

node* create(int prel, int preR, int inL, int inR){
	if(preL > preR){
		return NULL;  //先序序列长度小于等于0时,直接返回 
	}
	node* root = new node;  // 新建一个新的结点,用来存储当前二叉树的根结点
	root->data = pre[preL];  //新结点的数据域为根结点的值 
	int k;
	for(k == inL; k<=inR; k++){
		if(in[k] == pre[preL]){  //在中序序列中找到in[k] == pre[preL]结点 
			break; 
		}
	} 
	int numLeft = k - inL;     //左子树的结点个数
	
	//左子树的先序区间为[preL+1, preL+numLeft],中序区间为[inL,k-1]
	//返回左子树的根结点地址,赋值给root的左指针
	root->lchild = create(preL+1, preL+numLeft, inL, k-1);
	//右子树的先序区间为[preL+numLeft+1, preR],中序区间为[k+1,inR]
	//返回右子树的根结点地址,赋值给root的右指针
	root->rchild = create(preL+numLeft+1, preR, k+1, inR); 
	
	return root;  //返回根结点地址 
} 





猜你喜欢

转载自blog.csdn.net/u014322206/article/details/78634013