在关于数据结构中,运用最多的树莫过于二叉树,当然,也有B树,B+树,红黑树...
虽然种类很多,但是基本的还是二叉查找树。这里我们就二叉树的一些基本特征作一些讨论,
然后给出一些基本的二叉查找树的常用操作代码。
实现二叉树的方法可以是在每个节点除数据外还要有一些指针,使得该节点的每一个儿子都有一个指针
指向它。二叉树的典型声明如下(为了方便起见,二叉数里的元素都是int型):
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *left;
struct node *right;
};
typedef struct node* Node;
#include <stdlib.h>
struct node
{
int data;
struct node *left;
struct node *right;
};
typedef struct node* Node;
给一个数据,返回一个二叉树的节点
Node newNode(int data)
{
Node node=(Node)malloc(sizeof(struct node));
if(node==NULL)
return NULL;
node->data=data;
node->left=NULL;
node->right=NULL;
return node;
}
{
Node node=(Node)malloc(sizeof(struct node));
if(node==NULL)
return NULL;
node->data=data;
node->left=NULL;
node->right=NULL;
return node;
}
下面介绍一些简单的二叉树的操作代码:
/*1.递归计算二叉树中的节点数
*/
int size(Node root)
{
Node node=root;
if (node==NULL)
return 0;
else
return (size(node->left)+1+size(node->right));
}
*/
int size(Node root)
{
Node node=root;
if (node==NULL)
return 0;
else
return (size(node->left)+1+size(node->right));
}
/*2.计算二叉树的深度
*/
int maxDepth(Node root)
{
Node node=root;
if (node==NULL)
return 0;
else
{
int depleft=maxDepth(node->left);
int depright=maxDepth(node->right);
return (depleft>depright)?(depleft+1):(depright+1);
}
}
*/
int maxDepth(Node root)
{
Node node=root;
if (node==NULL)
return 0;
else
{
int depleft=maxDepth(node->left);
int depright=maxDepth(node->right);
return (depleft>depright)?(depleft+1):(depright+1);
}
}
/*3.给定一个BST,返回最小的值,即最左端的值
*/
int minValue(Node root)
{
Node current=root;
/*循环,直到找到最左端的那个值,即为最小值,并返回*/
while (current->left != NULL)
{
current=current->left;
}
return current->data;
}
*/
int minValue(Node root)
{
Node current=root;
/*循环,直到找到最左端的那个值,即为最小值,并返回*/
while (current->left != NULL)
{
current=current->left;
}
return current->data;
}
/*4.1 BST的查找操作,递归操作
*/
Node SearchBST(Node root, int num)
{
Node node=root;
if (node==NULL || node->data == num)
return node;
else if(node->data <num)
return SearchBST(node->left,num);
else
return SearchBST(node->right,num);
}
/*4.2 BST的查找操作,非递归算法
*/
Node SearchBSTNoRec(Node root, int num)
{
Node node=root;
while (node != NULL)
{
if (node->data==num)
return node;
else if(node->data > num)
node=node->left;
else
node=node->right;
}
return node;
}
/*5.1 BST的插入操作,递归算法
*/
Node Insert(Node root, int num)
{
Node node=root;
if(node==NULL)
return newNode(num);
else{
if(node->data > num)
node->left=Insert(node->left,num);
else if(node->data <num)
node->right=Insert(node->right,num);
return node;
}
}
/*5.2 BST的插入操作,非递归算法
*/
Node InsertNoRec(Node root, int num)
{
Node node=root;
Node parent;
if(node==NULL)//如果头节点为空,将该数据插入头节点
node=newNode(num);
else{
while(node!=NULL){//寻找插入的位置
if(node->data==num)//如果存在该节点,直接返回
return node;
else{
parent=node; //记录父节点位置,用于在该节点后插入数据
if(node->data >num)
node=node->left;
else
node=node->right;
}
}
node=newNode(num);
if(parent->data>num) //根据父节点的值,确定插在其左节点或右节点
parent->left=node;
else
parent->right=node;
}
return node;
}
/*6.BST的删除操作,递归处理,该代码来自数据结构与算法分析
*/
Node Delete(Node root, int num)
{
Node node=root;
Node pTemp;
if(node==NULL)
fprintf(stderr,"Error!Try to delete a NULL tree ");
else if(node->data > num)
node->left=Delete(node->left,num);
else if(node->data < num)
node->right=Delete(node->right,num);
else if (node->left!=NULL && node->right !=NULL){//要删除的节点有两个子节点
pTemp=Findmin(node->right);//找到该节点右子树的最小的那个节点,来代替这个被删除的节点
node->data=pTemp->data;
node->right=Delete(node->data,node->right);
}
else{//有一个子节点或者是叶子节点
pTemp=node;
if(node->left==NULL)
node=node->right;
else if(node->right==NULL)
node=node->left;
free(pTemp);
}
return node;
}
/*辅助函数,用于查找二叉树的最小值节点,并返回
*/
Node Findmin(Node node)
{
Node current=node;
/*循环,直到找到最左端的那个值,即为最小值,并返回*/
while (current->left != NULL)
current=current->left;
return current;
}
/*6.1 BST的删除操作,非递归处理
*/
void DeleteNoRec(Node root, int num)
{
Node parent;
Node node=root;
Node node1,parent1;
while(node!=NULL && node->data!=num){//寻找需要删除的节点
parent=node;
if (num<node->data)node=node->left;
else node=node->right;
}
if (node==NULL) {//如果没有找到该节点,返回错误
printf("num is not in the tree ");
return;
}
if(node!=root){
if (node->left==NULL){//左节点为空,则将右节点代替原来的位置(包含叶子节点的情况)
if(num<=parent->num) parent->left=node->right;
else parent->right=node->right;
free(node);
}
else if(node->right==NULL){//右节点为空,则将左节点代替原来的位置
if (num<=parent->num) parent->left=node->left;
else parent->right=node->left;
free(node);
}
else{//如果两个节点都不为空
node1=node->right; //寻找右子树最小的那个节点代替被删除的那个
while(node1->left!=NULL){
parent1=node1;
node1=node1->left;
}
parent1->left=node1->left;
node->data=node1->data;
free(node1);
}
*/
Node Delete(Node root, int num)
{
Node node=root;
Node pTemp;
if(node==NULL)
fprintf(stderr,"Error!Try to delete a NULL tree ");
else if(node->data > num)
node->left=Delete(node->left,num);
else if(node->data < num)
node->right=Delete(node->right,num);
else if (node->left!=NULL && node->right !=NULL){//要删除的节点有两个子节点
pTemp=Findmin(node->right);//找到该节点右子树的最小的那个节点,来代替这个被删除的节点
node->data=pTemp->data;
node->right=Delete(node->data,node->right);
}
else{//有一个子节点或者是叶子节点
pTemp=node;
if(node->left==NULL)
node=node->right;
else if(node->right==NULL)
node=node->left;
free(pTemp);
}
return node;
}
/*辅助函数,用于查找二叉树的最小值节点,并返回
*/
Node Findmin(Node node)
{
Node current=node;
/*循环,直到找到最左端的那个值,即为最小值,并返回*/
while (current->left != NULL)
current=current->left;
return current;
}
/*6.1 BST的删除操作,非递归处理
*/
void DeleteNoRec(Node root, int num)
{
Node parent;
Node node=root;
Node node1,parent1;
while(node!=NULL && node->data!=num){//寻找需要删除的节点
parent=node;
if (num<node->data)node=node->left;
else node=node->right;
}
if (node==NULL) {//如果没有找到该节点,返回错误
printf("num is not in the tree ");
return;
}
if(node!=root){
if (node->left==NULL){//左节点为空,则将右节点代替原来的位置(包含叶子节点的情况)
if(num<=parent->num) parent->left=node->right;
else parent->right=node->right;
free(node);
}
else if(node->right==NULL){//右节点为空,则将左节点代替原来的位置
if (num<=parent->num) parent->left=node->left;
else parent->right=node->left;
free(node);
}
else{//如果两个节点都不为空
node1=node->right; //寻找右子树最小的那个节点代替被删除的那个
while(node1->left!=NULL){
parent1=node1;
node1=node1->left;
}
parent1->left=node1->left;
node->data=node1->data;
free(node1);
}
}
else
free(root);
}
else
free(root);
}
/*7.1二叉树前序遍历,递归算法
*/
void preOrderT(Node root)
{
Node node=root;
if (node==NULL)
return;
printf("%d ",node->data);
preOrderT(node->left);
preOrderT(node->right);
}
/*7.2 二叉树前序遍历,非递归算法
*/
void preOrderTNoRec(Node root)
{
Node node=root;
stack<Node> s;//利用堆栈
//当节点不为空或者堆栈不为空进入循环体
while ((NULL != node) || !s.empty()){
if (NULL != node){
printf("%d ", node->data);//打印节点,并压入堆栈
s.push(node);
node = node->left;
}
else {
node = s.top(); //如果node为空,指向堆栈的顶端,并弹出该节点
s.pop();
node = node->right;
}
}
}
*/
void preOrderT(Node root)
{
Node node=root;
if (node==NULL)
return;
printf("%d ",node->data);
preOrderT(node->left);
preOrderT(node->right);
}
/*7.2 二叉树前序遍历,非递归算法
*/
void preOrderTNoRec(Node root)
{
Node node=root;
stack<Node> s;//利用堆栈
//当节点不为空或者堆栈不为空进入循环体
while ((NULL != node) || !s.empty()){
if (NULL != node){
printf("%d ", node->data);//打印节点,并压入堆栈
s.push(node);
node = node->left;
}
else {
node = s.top(); //如果node为空,指向堆栈的顶端,并弹出该节点
s.pop();
node = node->right;
}
}
}
/*8.1 二叉树中序遍历,递归算法
*/
void InOrderT(Node root)
{
Node node=root;
if (node==NULL)
return;
InOrderT(node->left);
printf("%d ", node->data);
InOrderT(node->right);
}
/*8.2 二叉树中序遍历,非递归算法
*/
void InOrderTNoRec(Node root)
{
Node node=root;
stack<Node> s; //创建堆栈
//当节点不为空或堆栈不为空,进入循环体
while ((NULL != node) || !s.empty()){
if (NULL != node){
s.push(node);//压入节点,直到最左端的节点
node = node->left;
}
else{
node = s.top();//指向堆栈的顶端节点
printf("%d ", node->data);//输出该节点,并弹出,指向其右节点
s.pop();
node = node->right;
}
}
}
/*9.1 二叉树的后序遍历,递归算法
*/
void PostOrderT(Node root)
{
Node node=root;
if (node==NULL)
return;
PostOrderT(node->left);
PostOrderT(node->right);
printf("%d ",node->data);
}
/*9.2 二叉树的后序遍历,非递归算法
*/
void PostOrderTNoRec(Node root)
{
Node node=root;
stack<Node> s;
Node pre=NULL;
//如果节点不为空或堆栈不为空,进入循环体
while ((NULL != node) || !s.empty()){
if (NULL != node){//压入节点,直到最左端的非空节点
s.push(node);
node = node->left;
}
else {
node = s.top();//得到一个非空节点
if (node->right!=NULL && pre!=node->right){ //防止节点重复被遍历
node = node->right;
}
else{
node=pre=s.top();//得到一个节点,并输出,pre保存这个节点
printf("%d ", node->data);
s.pop(); //弹出节点
node=NULL;
}
}
}
}
*/
void PostOrderT(Node root)
{
Node node=root;
if (node==NULL)
return;
PostOrderT(node->left);
PostOrderT(node->right);
printf("%d ",node->data);
}
/*9.2 二叉树的后序遍历,非递归算法
*/
void PostOrderTNoRec(Node root)
{
Node node=root;
stack<Node> s;
Node pre=NULL;
//如果节点不为空或堆栈不为空,进入循环体
while ((NULL != node) || !s.empty()){
if (NULL != node){//压入节点,直到最左端的非空节点
s.push(node);
node = node->left;
}
else {
node = s.top();//得到一个非空节点
if (node->right!=NULL && pre!=node->right){ //防止节点重复被遍历
node = node->right;
}
else{
node=pre=s.top();//得到一个节点,并输出,pre保存这个节点
printf("%d ", node->data);
s.pop(); //弹出节点
node=NULL;
}
}
}
}
/*10. 给定一个BST和一个数,检查是否存在一条路径,从叶子到根节点,使得每个节点的数据之和为这个数
*算法的思想:减去一个节点的值,然后递归求解
*/
int hasPathSum(Node root, int sum)
{
Node node=root;
//如果把树遍历完得到sum==0,返回true
if (node==NULL){
return sum==0;
}
else{//对两个子树递归求解
int subSum=sum-node->data;
return (hasPathSum(node->left) || hasPathSum(node->right));
}
}
*算法的思想:减去一个节点的值,然后递归求解
*/
int hasPathSum(Node root, int sum)
{
Node node=root;
//如果把树遍历完得到sum==0,返回true
if (node==NULL){
return sum==0;
}
else{//对两个子树递归求解
int subSum=sum-node->data;
return (hasPathSum(node->left) || hasPathSum(node->right));
}
}
/*11.给定一棵二叉树,打印所有根节点到叶子节点的路径
*/
void printPaths(Node root)
{
int path[100];
printPathsRec(root,path,0);
}
/*
*递归调用,打印出每条路径
*/
void printPathsRec(Node node, int path[],len)
{
if (node==NULL) return;
//将该节点加入路径中
path[len]=node->data;
len++;
//如果该节点是叶子节点,就输出路径
if (node->left==NULL && node->right==NULL){
printArray(path,len);
}
else{//否则,对左右节点递归调用
printPathsRec(node->left,path,len);
printPathsRec(node->right,path,len);
}
}
/*打印出一条路径*/
void printArray(int path[],int len)
{
int i;
for (i=0;i<len;i++)
printf("%d ",path[i]);
printf(" ");
}
/*
*12.对一棵二叉树交换其左右节点,使其看起来像以前的镜像,例如:
4 4
/ \ / \
2 5 is changed to 5 2
/ \ / \
1 3 3 1
*/
void mirror(Node root)
{
Node node=root;
if (node==NULL){
return;
}
else{
Node tmp;
mirror(node->left);
mirror(node->right);
//交换左右节点
tmp=node->left;
node->left=node->right;
node->right=tmp;
}
}
/*13.给定两个二叉树,看其是否完全相同
*/
int sameTree(Node a,Node b)
{
if(a==NULL && b=NULL)
return true;
else if(a!=NULL && b!=NULL){
return (a->data==b->data &&
sameTree(a->left,b->left) &&
sameTree(a->right,b->right));
}
else
return false;
}
*/
int sameTree(Node a,Node b)
{
if(a==NULL && b=NULL)
return true;
else if(a!=NULL && b!=NULL){
return (a->data==b->data &&
sameTree(a->left,b->left) &&
sameTree(a->right,b->right));
}
else
return false;
}
/*14.给定numKeys个不同的节点,计算能够构成多少棵BST
*算法:考虑每个节点都可以作为根节点,递归计算其左右子树的个数
*/
int countTrees(int numKeys)
{
if (numKeys<=1)
return 1;
else{
int sum=0,root,left,right;
for (root=1;root<=numKeys;root++){
left=countTrees(root-1);
right=countTrees(numKeys-root);
//根据左右子树组合的可能,肯能的树的个数为left*right
sum+=left*right;
}
return sum;
}
}
*算法:考虑每个节点都可以作为根节点,递归计算其左右子树的个数
*/
int countTrees(int numKeys)
{
if (numKeys<=1)
return 1;
else{
int sum=0,root,left,right;
for (root=1;root<=numKeys;root++){
left=countTrees(root-1);
right=countTrees(numKeys-root);
//根据左右子树组合的可能,肯能的树的个数为left*right
sum+=left*right;
}
return sum;
}
}
/*15.1 isBST1(),检验一棵二叉树是不是BST
*/
int isBST1(Node node)
{
if (node==NULL) return true;
//如果左子树的最小值大于当前的值,返回false
if (node->left!=NULL && minValue(node->left) >node->data) return false;
//如果右子树的最大值小于当前的值,返回false
if (node->right !=NULL && maxValue(node->right) <=node->data) return false;
//对左右子树递归调用
if (!isBST1(node->left) || !isBST1(node->right)) return false;
return true;
}
/*15.2 isBST2(),检验一棵二叉树是不是BST(效率更高的版本)
*/
int isBST2(Node node)
{
return isBSTUtil(node,INT_MIN,INT_MAX);
}
int isBSTUtil(Node node, int min, int max)
{
if (node==NULL) return true;
//如果这个节点不是在要求的范围之类,则返回false
if (node->data < min || node->data > max)
return false;
else //对左右子树进行递归检查
return (isBSTUtil(node->left,min,node->data)&&
isBSTUtil(node->right,node->data+1,max));
}
*/
int isBST1(Node node)
{
if (node==NULL) return true;
//如果左子树的最小值大于当前的值,返回false
if (node->left!=NULL && minValue(node->left) >node->data) return false;
//如果右子树的最大值小于当前的值,返回false
if (node->right !=NULL && maxValue(node->right) <=node->data) return false;
//对左右子树递归调用
if (!isBST1(node->left) || !isBST1(node->right)) return false;
return true;
}
/*15.2 isBST2(),检验一棵二叉树是不是BST(效率更高的版本)
*/
int isBST2(Node node)
{
return isBSTUtil(node,INT_MIN,INT_MAX);
}
int isBSTUtil(Node node, int min, int max)
{
if (node==NULL) return true;
//如果这个节点不是在要求的范围之类,则返回false
if (node->data < min || node->data > max)
return false;
else //对左右子树进行递归检查
return (isBSTUtil(node->left,min,node->data)&&
isBSTUtil(node->right,node->data+1,max));
}