• 数据结构学习之二叉树小结


    在关于数据结构中,运用最多的树莫过于二叉树,当然,也有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));
    }
  • 相关阅读:
    js去重的es6做法和es5做法
    对npm的认识
    pandas_分类与聚合
    pandas_使用透视表与交叉表查看业绩汇总数据
    pandas_使用属性接口实现高级功能
    pandas_一维数组与常用操作
    pandas_DateFrame的创建
    python 连接 mysql 的三种驱动
    Django学习路6_修改数据库为 mysql ,创建mysql及进行迁徙
    Django学习路5_更新和删除数据库表中元素
  • 原文地址:https://www.cnblogs.com/dayouluo/p/727209.html
Copyright © 2020-2023  润新知