二叉树(2.二叉树的遍历和实现)

Posted 水澹澹兮生烟.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树(2.二叉树的遍历和实现)相关的知识,希望对你有一定的参考价值。

2.5二叉树的遍历

什么是遍历?按照某种特性规则,对二叉树中的结点进行某种相应的操作,并且每个结点只操作一次。

2.5.1前序遍历

又称先根遍历,访问根结点的操作发生在遍历其左右子树之前。

//前序遍历
void preorder(node* root){
	if(root){
		printf("%d" ,root->data);
		preorder(root->left);
		preorder(root->right);
	}
}

在这里插入图片描述

2.5.2中序遍历

又称中根遍历,访问根结点的操作发生在遍历其左右子树之间。

//中序遍历
void midorder(node* root){
	if(root){
		midorder(root->left);
		printf("%d",root->data);
		midorder(root->right);
	}
}

在这里插入图片描述

2.5.3后序遍历

又称后根遍历,访问根结点的操作发生在遍历其左右子树之后。
在这里插入图片描述

postorder(node* root){
  	if(root)
  		{
  			postorder(root->left);
  			postorder(root->right);
  			printf("%d" ,root->data);
  		}
  }

2.5.4层序遍历

堆二叉树的每一层进行遍历。
1.定义一个队列的结构并初始化,然后将根结点入队列
2.只要队列不空,循环进行以下操作:
从队列中取一个结点,遍历该结点,如果该节点测左孩子存在,将其入队列,若该结点的右孩子存在,入队列。然后将队头元素删掉。
3.删除队列
在这里插入图片描述
队列实现的代码
此时我们在这里需要的函数:

void QueueInit(queue* q);
//获取队头元素
DType QueueQhead(queue* q);
//出队列(将结点的孩子节点入队列)
void Queuepop(queue* q);
//入队列(将父结点出队列)
void Queuepush(queue* q, DType data);
//判空
int Queueempty(queue* q);
//销毁队列
void Queuedestroy(queue* q);

实现层序遍历:

 leveOrder(node* root){
  	if(NULL==root) return;
  //先定义一个队列
  queue* q;
  //初始化队列,将根节点入队列
  QueueInit(&q);
  Queuepush(&q,root);
  while(!Queueempty(&q)){
  	//队列不空,先得到队头元素
  	node* p=QueueQhead(&q);
  	//打印队头元素
  	printf("%d",p->data);
  	//然后判断结点是否存在左右孩子,并将其入队列
  	if(p->left){
  		//作孩子入队列
  		Queuepush(&q,p->left);
  	}
  	if(p->right){
  		Queuepush(&q,p->right);
  	}
  	//然后出队列
  	ququepop(&q);
  }
  //再将队列进行销毁
  void Queuedestroy(&q);
  }

2.6二叉树的中的方法

2.6.1.二叉树的销毁

以遍历的思想堆二叉树进行销毁,此时我们采用后序遍历来进行销毁,如果采用前序遍历或者中序遍历,我们会再销毁孩子节点之前将父结点销毁掉,这样会再成数据丢失。

void destoryBinary(node** root){
  	//再进行销毁时,我们在最后一部要对root进行修改,因此我们在传参时要传二级指针
  	if(*root){
  		//在不为空的情况下进行销毁
  		destoryBinary(&(*root)->left);
  		destoryBinary(&(*root)->right);
  		free(*root);
  		*root=NULL;
  	}
  }

2.6.2.二叉树的结点

再求的二叉树的结点的时候,我们首先要知道二叉树的他有空树和非空树。
当它为空树时,直接结点个数返回0;当它为非空时,他的结点个数为根结点+左子树节点个数+右子树结点个数。
在这里插入图片描述

//求二叉树中的结点
  int getrootBinary(node* root){
  	if(NULL==root) return 0;
  	return 1+getrootBinary(root->left)+getrootBinary(root->right);
  }

2.6.3.求二叉树的叶子结点

在这里插入图片描述

 //求二叉树中的叶子结点
  int getleaftroot(node* root){
  	if(NULL==root) return 0;
  	if(root->left==NULL&&root->right==NULL){
  		return 1;
  	}
  	return getleaftroot(root->left)+getleaftroot(root->right);
  }

2.6.4.求二叉树的第k层的结点数

在这里我们需要考虑三点:
1.当树为空或者k=0时,直接返回0;
2.当树不为空且k=1时,返回1;
3.排除以上两种情况,我们求他的第k层元素个数直接去求是不好得出的,因此我们可以在其root的左右子树上求的k-1层即可,最后将其求得的个数+1。
在这里插入图片描述

int getbinarytreek(node* root,int k){
  	if(root==NULL||k==0) return 0;
  	if(k==1) return 1;
  	return getbinarytreek(root->left,k-1)+getbinarytreek(root->right,k-1);
  	
  }

2.6.5求树的高度

在这个中我们可以考虑求出他的左子树高度,并且求出他的右子树高度,然后比较左右子树的高度,选取大的值+1就是二叉树的高度。
在这里插入图片描述

//计算二叉树的高度
  int getbinarytreehight(node* root){
  	if(NULL==root){
  		return 0;
  	}
  	int lefthight=getbinarytreehight(root->left);
  	int righthight=getbinarytreehight(root->right);
  	int hight=lefthight>righthight?lefthight+1:righthight+1;
  	return hight;
  }

2.6.6查找二叉树中x结点

和前面的原理相似,利用遍历查找。

node* binaryTreeFind(node* root,int x){
  	node* cur=NULL;
  	if(root==NULL) return NULL;
  	if(root->data==x){
  		return root;
  	}
  	if(cur=binaryTreeFind(root->left,x))
  		return cur;
  	if(cur=binaryTreeFind(root->right,x))
  		return cur;

  }

2.6.7二叉树的创建

创建二叉树时提供的序列中只包含了有效元素,如果遇到那个结点没有左孩子或者右孩子,是无法区分的,我们在序列中必须标记那些父结点有孩子,那些没有孩子,因此我们借助顺序表来进行标记。
在这里插入图片描述

//构建二叉树
BTnode* _creatBTree(int array[], int size, int* index, int invalid){
	 BTnode* root = NULL;
	 //index以值的方式进行传递当他在递归过程中修改之后,不会将修改会的值传到上一层中,因此我们此时要传地址
	 if (*index < size&&array[*index] != invalid){
		 root = getBTnode(array[*index]);
		//此时,先对index进行++,
		(*index)++;
		root->left=_creatBTree(array, size, index, invalid);
		(*index)++;
		root->right=_creatBTree(array, size, index, invalid);
		return root;
	 }
	 else{
		 return NULL;
	 }

}
BTnode* creatBTree(int* array, int size, int invalid){
	int index = 0;
	return _creatBTree(array, size, &index, invalid);
}

(附所有代码及运行结果):

BinaryTree.h

#pragma once
#include<stdio.h>

typedef int DType;
typedef struct BTnode{
	//孩子表示法,分别是左孩子,右孩子
	struct BTnode* left;
	struct BTnode* right;
	DType data;
}BTnode;

BTnode* getBTnode(DType data);
BTnode* _creatBTree(int* array, int size, int* index, int invalid);
BTnode* creatBTree(int* array, int size,int invalid);
void preorder(BTnode* root);
void midorder(BTnode* root);
void postorder(BTnode* root);
//二叉树的销毁
void destoryBinary(BTnode** root);
//求二叉树的结点
int getBinaryroot(BTnode* root);
//求二叉树的叶子结点个数
int getleafroot(BTnode* root);
//求二叉树第k层的结点数
int getbinarytreek(BTnode* root, int k);
//求树的高度
int getvinarytreehight(BTnode* root);
//查找二叉树中的x结点,如果找到返回其地址,若未找到返回0
BTnode* binaryTreefind(BTnode* root, DType x);

binaryTree.c

#include"BinaryTree.h"
#include<stdio.h>
#include<malloc.h>
#include<assert.h>
//构建结点
BTnode* getBTnode(DType data){
    struct BTnode* node = (struct BTnode*)malloc(sizeof(BTnode));
	if (node == NULL){
		assert(0);
		return NULL;
	}
	node->data = data;
	node->left = node->right = NULL;
	return node;
}
//构建二叉树
BTnode* _creatBTree(DType array[], int size, int* index, DType invalid){
	 BTnode* root = NULL;
	 //index以值的方式进行传递当他在递归过程中修改之后,不会将修改会的值传到上一层中,因此我们此时要传地址
	 if (*index < size&&array[*index] != invalid){
		 root = getBTnode(array[*index]);
		//此时,先对index进行++,
		(*index)++;
		root->left=_creatBTree(array, size, index, invalid);
		(*index)++;
		root->right=_creatBTree(array, size, index, invalid);
		return root;
	 }
	 else{
		 return NULL;
	 }

}
BTnode* creatBTree(DType array[] , int size, DType invalid){
	int index = 0;
	return _creatBTree(array, size, &index, invalid);
}
void preorder(BTnode* root){
	if (root == NULL){
		return;
	}
	//先输出根结点
	printf("%d\\t", root->data);
	//递归遍历左子树
	preorder(root->left);
	//递归遍历右子树
	preorder(root->right);
}

void midorder(BTnode* root){
	if (root == NULL) return;
	//递归遍历左子树
	midorder(root->left);
	//输出根结点
	printf("%d\\t", root->data);
	//递归遍历右子树
	midorder(root->right);
}

void postorder(BTnode* root){
	if (root == NULL) return;
	//递归遍历左子树
	postorder(root->left);
	//递归遍历右子树
	postorder(root->right);
	//输出根结点
	printf("%d\\t", root->data);
	
}


void destoryBinary(BTnode** root){
	if (*root == NULL) return;
	//在不为空的的情况下进行销毁
	destoryBinary(&(*root)->left);
	destoryBinary(&(*root)->right);
	free(*root);
	*root = NULL;
}

int getBinaryroot(BTnode* root){
	if (root == NULL) return 0;
	return 1 + getBinaryroot(root->left) + getBinaryroot(root->right);
}

int getleafroot(BTnode* root){
	if (root == NULL) return 0;
	if (root->left == NULL&&root->right == NULL){
		return 1;
	}
	return getleafroot(root->left) + getleafroot(root->right);

}

int getbinarytreek(BTnode* root, int k){
	if (root == NULL || k == 0) return 0;
	if (k == 1) return 1;
	return getbinarytreek(root->left, k - 1) + getbinarytreek(root->right, k - 1);
}


int getbinarytreehight(BTnode* root){
	if (root == NULL) return 0;
	//得到左子树的高度
	int lefthight = getbinarytreehight(root->left);
	int righthight = getbinarytreehight(root->right);
	int hight = lefthight > righthight ? lefthight + 1 : righthight + 1;
	return hight;
}

BTnode* binaryTreefind(BTnode* root, DType x){
	BTnode* cur = NULL;
	if (root == NULL) return NULL;
	if (root->data == x) return root;
	if (cur = binaryTreefind(root->left, x)){
		//如果在左子树中找到,返回
		return cur;
	}
	if (cur = binaryTreefind(root->right, x)){
		//在右子树中找打,返回
		return cur;
	}
}

test.c

#include<stdio.h>
#include"binaryTree.h"
int main(){
	int array[] = { 1, 2, 3, -1, -1, -1, 4, 5 ,-1,-1,6};
	int size = sizeof(array) / sizeof(array[0]);
	BTnode* root = creatBTree(array, size, -1);
	printf("先序遍历:");
	preorder(root);
	printf("\\n中序遍历:");
	midorder数据结构 二叉树的简单理解和代码实现

二叉树的前序中序和后续遍历及应用场景

数据结构-二叉树

最全二叉树的遍历方式总结

最全二叉树的遍历方式总结

Python数据结构系列☀️《树与二叉树-基础知识》——知识点讲解+代码实现☀️