在关于数据结构中,运用最多的树莫过于二叉树,当然,也有B树,B+树,红黑树...
虽然种类很多,但是基本的还是二叉查找树。这里我们就二叉树的一些基本特征作一些讨论,
然后给出一些基本的二叉查找树的常用操作代码。

实现二叉树的方法可以是在每个节点除数据外还要有一些指针,使得该节点的每一个儿子都有一个指针
指向它。二叉树的典型声明如下(为了方便起见,二叉数里的元素都是int型):

#include <stdio.h>
#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;
}

下面介绍一些简单的二叉树的操作代码:

/*1.递归计算二叉树中的节点数
 
*/

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

}


 

/*3.给定一个BST,返回最小的值,即最左端的值
 
*/

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

    }

}

 


/*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;
          }

      }

    }

}

 

/*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));
    }

}

 


/*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;
}

 

/*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;
    }

}

 

/*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));
}
posted on 2007-04-25 18:52  dayouluo(.Net学生)  阅读(1046)  评论(1编辑  收藏  举报