zoukankan      html  css  js  c++  java
  • 二叉树的一些操作

    1.二叉排序树数据结构

    1 typedef struct BSTNode{
    2   int data;
    3   struct BSTNode *lchild;
    4   struct BSTNode *rchild;
    5 }*BSTree,BSTNode;

     2.二叉树的问

    1. 用给定序列创建二叉排序树  
    1. 二叉树三种遍历(traverse)方式(递归与非递归):  
    1. 按层次打印二叉树 
    2. 如何判断一棵二叉树是否是平衡二叉树  
    3. 如何判断一棵二叉树是否是平衡排序树
    4. 设计一个算法,找出二叉树上任意两个节点的最近共同父结点,复杂度如果是O(n2)则不得分。
    5. 将给定的二叉排序树转换成双链表,不得建立新结点
    6. 判断二叉树中是否有和为某一值的路径
    7. 打印二叉树中的所有路径(与题目5很相似)
    8. 怎样编写一个程序,把一个有序整数数组放到二叉树中?
    9. 判断整数序列是不是二叉搜索树的后序遍历结果
    10. 求二叉树的镜像
    11. 一棵排序二叉树(即二叉搜索树BST),令 f=(最大值+最小值)/2,设计一个算法,找出距离f值最近、大于f值的结点。复杂度如果是O(n2)则不得分
    12. 把二叉搜索树转变成排序的双向链表  

    解决思路:

    1.二叉排序树建立:

    void BST_insert(BSTree &bt,int data){
    
       if( bt == NULL ){
    
          BSTree p = (BSTree)malloc(sizeof(BSTNode));
    
          p->data = data;
    
          p->lchild = NULL;
    
          p->rchild = NULL;
    
          bt = p;
    
        }else if(bt->data >data){
    
          BST_insert(bt->lchild,data);
    
        }else if(bt->data <data){
    
          BST_insert(bt->rchild,data);
    
        }else{
    
          return;
    
       }
    
    }
    void creteBST(BSTree &bt,int data[],int length){
       for(int i=0; i<length; i++){
          BST_insert(bt,data[i]);
       }
    }  
    2.二叉树三种遍历方式(递归与非递归)

    先序遍历:访问根结点,先序遍历左子树,先序遍历右子树

    中序遍历:中序遍历左子树,访问根结点,中序遍历右子树

    后序遍历:后序遍历左子树,后序遍历右子树,访问根节点

    1)递归程序

    void preorder(BSTree bt){
        if(bt != NULL){
            cout << bt->data << " ";
            preorder(bt->lchild);
            preorder(bt->rchild);
        }
    }
    
    void inorder(BSTree bt){
        if(bt != NULL){
            inorder(bt->lchild);
            cout << bt->data << " ";
            inorder(bt->rchild);
        }
    }
    
    void postorder(BSTree bt){
        if(bt != NULL){
            postorder(bt->lchild);
            postorser(bt->rchild);
            cout << bt->data << " ";
        }
    }
    2)非递归
    /** 前序非递归
    *    1)访问(输出)根结点,并将其入栈,直到访问完最左端的子树
    *    2)如果栈非空,取栈顶元素的右结点,删除栈顶元素
    *    栈顶的右子树不为空时,循环上面两步
    *    栈顶的右子树为空,需要继续进行退栈操作
    *    所以最外层while循环判断语句为!st.empty() || root != NULL
    */
    void preorder(BSTree root){
        if(root == NULL){
            cout << "空树" << endl;
            return;
        }
        stack<BSTree> st;
        while(!st.empty() || root != NULL){        
            //访问结点并将结点压栈
            while(root != NULL){
                cout << root->data << " ";
                st.push(root);
                root = root->lchild;
            }
            //取栈顶元素的右子树,删除相应结点
            if(!st.empty()){
                root = st.top();
                root = root->rchild;
                st.pop();
            }
        }
    }
    /** 中序非递归
    *    1)如果当前结点有左子树,将当前结点入栈,并令当前结点指向左子树根节点,直到走到最左端;
    *       如果当前结点无左子树,当前结点入栈
    *    2)如果栈非空,取栈顶元素并访问,当前结点指向栈顶元素的右子树,删除栈顶元素
    *    栈顶的右子树不为空时,循环上面两步
    *    栈顶的右子树为空,需要继续进行退栈操作
    *    所以最外层while循环判断语句为!st.empty() || root != NULL
    */
    void inorder(BSTree root){
        if(root == NULL){
            cout << "空树" << endl;
            return;
        }
        stack<BSTree> st;
        while(!st.empty() || root != NULL){        
            //走到最左端
            while(root != NULL){
                st.push(root);
                root = root->lchild;
            }
            //取栈顶元素并访问,root指向所取元素的右子树
            if(!st.empty()){
                root = st.top();
                cout << root->data << " ";
                root = root->rchild;
                st.pop();
            }
        }
    }
    
    /** 后序非递归
    *    正常模拟后序遍历的操作比较麻烦,有个取巧的办法,即按根右左的方式遍历,
    *    总是将元素插入到vector的头部
    */
    void preorder(BSTree root){
        if(root == NULL){
            cout << "空树" << endl;
            return;
        }
        stack<BSTree> st;
        vector<int> result;
        while(!st.empty() || root != NULL){    
            //访问结点并将结点压栈
            while(root != NULL){
                result.insert(result.begin(), root.val);
                st.push(root);
                root = root->rchild;
            }
            //取栈顶元素的左子树,删除相应结点
            if(!st.empty()){
                root = st.top();
                root = root->lchild;
                st.pop();
            }
        }
        for(vector<int>::iterator it = result.begin(); it!=result.end(); it++){
            cout << *it << " ";    
        }
        cout << endl;
    }



    2.怎样从顶部开始逐层打印二叉树结点数据?

    设置一个队列,然后只要队列不为空,将对首元素的左右孩子加入队列(如果左右孩子不为空),然后将队列的首元素出对即可,如下图所示:

    二叉树如下图所示:

    那么,整个过程如下:

    自然,就输出了a,b,c,d,e,f

    3.如何判断一个二叉树是否是平衡的?

    太简单了,利用递归就可以了:判断根节点的左右子树深度之差是否小于等于1(这里需要用到求深度的方法),如果是,根节点就是平衡的;然后,在判断根节点的左孩子和右孩子是否是平衡的。如此继续下去,直到遇见叶子节点。一旦不是,立刻返回false;

    计一个算法,找出二叉树上任意两个节点的最近共同父结点,复杂度如果是O(n2)则不得分

    首先找到这两个点key1和key2,并且记录下找到这两个点的路径Path1和Path2。然后,找到第一个点k满足,key1<k<key2就可以了。

    如图:

    假设key1 = 5,key2 = 7,那么显然,Path1{8,6,5}, Path2{8,6,7}。满足第一个key1<k<key2的k为6。故k = 6。

    至于怎么求出Path1和Path2,可以看问题12。

    5.如何不用递归实现二叉树的前序/后序/中序遍历?利用栈模拟递归。

    6.在二叉树中找出和为某一值的所有路径?

    还是先解决12题目,访问二叉树到叶子节点的任意路径。这个问题解决了,自然求和看是否满足条件就可以了。

    7.怎样编写一个程序,把一个有序整数数组放到二叉树中?

    递归,还是利用递归:

    设有int array[begin,end],首先将array[(begin + end)/2]加入二叉树,然后递归去做array[begin,(begin + end)/2 - 1]和array[(begin + end)/2 + 1, end]。注意写好函数的形式就可以了。一切都很自然。

    8.判断整数序列是不是二叉搜索树的后序遍历结果?

    看看吧,后续遍历是这样做的:左右根,所以访问的最有一个节点实际上就是整棵二叉树的根节点root:然后,找到第一个大于该节点值的根节点b,b就是root右子树最左边的节点(大于根节点的最小节点)。那么b前面的就是root的左子树。既然是二叉搜索树的遍历结果,那么在b和root之间的遍历结果,都应该大于b。去拿这个作为判断的条件。

    9.求二叉树的镜像(前序遍历的考察)?

    利用递归:只要节点不为空,交换左右子树的指针,然后在分别求左子树的镜像,再求右子树的镜像,直到节点为NULL。

    10.一棵排序二叉树(即二叉搜索树BST),令 f=(最大值+最小值)/2,设计一个算法,找出距离f值最近、大于f值的结点。复杂度如果是O(n2)则不得分。

    首先,在BST中,最小值就是最左边的节点,最大值就是最右边的节点。
    在分别求出min和max后,求出f。然后利用查找,找出一个大于f的节点就可以了。
    复杂度为logN。

    11.把二叉搜索树转变成排序的双向链表

    12..打印二叉树中的所有路径(前序遍历的考察)

    路径的定义就是从根节点到叶子节点的点的集合。

    前序遍历的变形,利用递归,利用vector<BSTree> v保存遍历过的路径。如果已经是叶子节点了,那么打印v的所有内容;如果不是,分别遍历左子树和右子树的路径。注意在打印完一条路径之后需要恢复环境即把放入的结点删除,因为程序开始的时候把父节点添加到v中了

    以上程序如下:

    [cpp] view plaincopy
     
     
    1. 解答2:  
    2. //问题2:怎样从顶部开始逐层打印二叉树结点数据  
    3. void PrintAtLevel(BSTree root){  
    4.     queue<BSTree> qu;
    5.     BSTree p;  
    6.     qu.push(root);  
    7.     while(!qu.empty()){  
    8.         p = qu.front();  
    9.         if(p->lchild != NULL)  
    10.             qu.push(p->lchild);  
    11.         if (p->rchild != NULL)  
    12.             qu.push(p->rchild);  
    13.         cout << p->data << endl;  
    14.         vector.pop();  
    15.     }  
    16. }  
    17. //问题3:如何判断一棵二叉树是否是平衡二叉树  
    18. int isBalencedTree(BSTree root){  
    19.     if (root == NULL)  
    20.         return 0;  
    21.     int depth1 = getDepth(root->lchild);  
    22.     int depth2 = getDepth(root->rchild);  
    23.     if (depth1 == depth2 || depth1 == depth2 + 1 || depth1 == depth2 - 1)  
    24.         return 1;  
    25.     else  
    26.         return 0;  
    27.     int flag1 = isBalencedTree(root->lchild);  
    28.     int flag2 = isBalencedTree(root->rchild);  
    29.     if (flag1 && flag2)  
    30.         return 1;  
    31.     else  
    32.         return 0;  
    33. }  
    34. //问题4:设计一个算法,找出二叉树上任意两个节点的最近共同父结点,复杂度如果是O(n2) 则不得分。  
    35. int getPublicAncestors(treeNode* root,int key1,int key2){  
    36.     treeNode* ptr = root;  
    37.     int path1[1000];  
    38.     int pathLen1 = 0;  
    39.     while (ptr != NULL){  
    40.         if (key1 == ptr->data){  
    41.             path1[pathLen1] = ptr->data;  
    42.             pathLen1 ++;  
    43.             printArray(path1,pathLen1);  
    44.             break;  
    45.         }  
    46.         else  
    47.             if (ptr->data > key1){  
    48.                 path1[pathLen1] = ptr->data;  
    49.                 pathLen1 ++;  
    50.                 ptr = ptr->lchild;  
    51.             }  
    52.             else  
    53.                 if (ptr->data < key1){  
    54.                     path1[pathLen1] = ptr->data;  
    55.                     pathLen1 ++;  
    56.                     ptr = ptr->rchild;  
    57.                 }  
    58.     }  
    59.     ptr = root;  
    60.         int path2[1000];  
    61.         int pathLen2 = 0;  
    62.         while (ptr != NULL){  
    63.             if (key2 == ptr->data){  
    64.                 path2[pathLen2] = ptr->data;  
    65.                 pathLen2 ++;  
    66.                 printArray(path2,pathLen2);  
    67.                 break;  
    68.             }  
    69.             else  
    70.                 if (ptr->data > key2){  
    71.                     path2[pathLen2] = ptr->data;  
    72.                     pathLen2 ++;  
    73.                     ptr = ptr->lchild;  
    74.                 }  
    75.                 else  
    76.                     if (ptr->data < key2){  
    77.                         path2[pathLen2] = ptr->data;  
    78.                         pathLen2 ++;  
    79.                         ptr = ptr->rchild;  
    80.                     }  
    81.         }  
    82.     int i = pathLen1 - 1;  
    83.     //key1和key2有序,  
    84.     if (key2 < key1){  
    85.         key2 = key2^key1;  
    86.         key1 = key2^key1;  
    87.         key2 = key2^key1;  
    88.     }  
    89.     for (; i > 0; i --){  
    90.         if (key1 < path1[i] && path1[i]< key2){  
    91.             int result = path1[i];  
    92.             return result;  
    93.         }  
    94.     }  
    95. }  
    96. //问题6:在二叉树中找出和为某一值的所有路径  
    97. void FindPath(BSTree bt,int &cost,vector<BSTree> &v){
    98.     if(bt != NULL){
    99.       v.push_back(bt);
    100.       cost -= bt->data; 
    101.       if(bt->lchild == NULL && bt->rchild == NULL && cost == 0){
    102.          for(vector<BSTree>::iterator iter = v.begin(); iter != v.end(); iter++)
    103.             cout << (*iter)->data << " ";
    104.          cout << endl;
    105.       }
    106.       FindPath(bt->lchild, cost, v);
    107.       FindPath(bt->rchild, cost, v);
    108.      //恢复环境
    109.      cost += bt->data;
    110.      v.pop_back();
    111.    }  
    112. }  
    113.   
    114. //问题7:怎样编写一个程序,把一个有序整数数组放到二叉树中?  
    115. void createTreeFromArray(int a[], int begin, int end, treeNode** root){  
    116.     if (begin > end)  
    117.         return;  
    118.     else{  
    119.         *root = (treeNode*) malloc(sizeof(treeNode));  
    120.         int mid = (begin + end) / 2;  
    121.         (*root)->data = a[mid];  
    122.         (*root)->rchild = NULL;  
    123.         (*root)->lchild = NULL;  
    124.         createTreeFromArray(a, begin ,mid - 1, &(*root)->lchild);  
    125.         createTreeFromArray(a, mid + 1 ,end, &(*root)->rchild);  
    126.     }  
    127. }  
    128. //问题8:判断整数序列是不是二叉搜索树的后//序遍历结果  
    129. int isPostTraverse(int a[], int begin ,int end){  
    130.     if(begin >= end)  
    131.         return 1;  
    132.     else{  
    133.         int root = a[end];  
    134.         int lroot;  
    135.         int i;  
    136.         int location = begin;  
    137.         for (i = begin; i < end ; i ++){  
    138.             if(a[i] > root){  
    139.                 location = i;  
    140.                 lroot = a[i];  
    141.                 break;  
    142.             }  
    143.         }  
    144.         for (i = location + 1; i < end; i++){  
    145.             if (a[i] < lroot){  
    146.                 return 0;  
    147.             }  
    148.         }  
    149.         int flag1 = isPostTraverse(a,begin,location -1);  
    150.         int flag2 = isPostTraverse(a,location,end - 1);  
    151.         if (flag1 && flag2)  
    152.             return 1;  
    153.         else  
    154.             return 0;  
    155.     }  
    156. }  
    157. //问题9:求二叉树的镜像  
    158. void changeMirror(BSTree &root){  
    159.     if ( root == NULL)  
    160.         return;  
    161.     else{  
    162.         BSTree temp = root->lchild;  
    163.         root->lchild = root->rchild;  
    164.         root->rchild = temp;  
    165.         changeMirror(&(*root)->lchild);  
    166.         changeMirror(&(*root)->rchild);  
    167.     }  
    168. }  
    169. //问题10:10.一棵排序二叉树(即二叉搜索树BST),令 f=(最大值+最小值)/2,设计一个算  
    170.   
    171. //法,找出距离f值最近、大于f值的结点。复杂度如果是O(n2)则不得分。  
    172. int findNearMid(treeNode** root){  
    173.     treeNode* ptr = *root;  
    174.     int min, max;  
    175.     while (ptr != NULL){  
    176.         min = ptr->data;  
    177.         ptr = ptr->lchild;  
    178.     }  
    179.     printf("the min is %d ",min);  
    180.     ptr = *root;  
    181.     while (ptr != NULL){  
    182.         max = ptr->data;  
    183.         ptr = ptr->rchild;  
    184.     }  
    185.     printf("the max is %d ",max);  
    186.     int half = (min + max) >> 1;  
    187.     printf("half is %d ",half);  
    188.     ptr = *root;  
    189.     while (1){  
    190.         if (ptr->data < half){  
    191.             ptr = ptr->rchild;  
    192.         }  
    193.         else  
    194.             if (ptr->data > half){  
    195.                 int result = ptr->data;  
    196.                 return result;  
    197.             }  
    198.             else  
    199.             {  
    200.                 return (ptr->rchild)->data;  
    201.             }  
    202.     }  
    203. }  
    204. //问题12:打印二叉树中的所有路径(与题目5很相似)
    205. 程序1:  
    206. void printPathsRecur(BSTree root, vector<BSTree> &v) {  
    207.     if (root == NULL)  
    208.         return;  
    209.     // append this node to the path array  
    210.     v.push_back(bt);
    211.     // it's a leaf, so print the path that led to here  
    212.     if (root->lchild == NULL && root->rchild == NULL) {  
    213.         for(vector<BSTree>::iterator iter=v.begin(); iter != v.end(); iter++)
    214.            cout << (*iter)->data << " ";
    215.         cout << endl;  
    216.     } 
    217.     // otherwise try both subtrees  
    218.      printPathsRecur(root->lchild, v);  
    219.      printPathsRecur(root->rchild, v);  
    220.      //恢复环境
    221.      v.pop_back(); 
    222. }  
    223. 程序2
    224. void printPathsRecur(BSTree root, vector<BSTree> &v){
    225.     if(root == NULL) return;
    226.     if(root->lchild == NULL && root->rchild == NULL){
    227.        for(vector<BSTree>::iterator iter=v.begin(); iter!=v.end(); iter++)
    228.           cout << (*iter)->data << " ";
    229. cout << root->data << endl;
    230.     }
    231.      v.push_back(root);//移到这里来了,在if中需要打印出root的数据
    232.      printPathsRecur(root->lchild, v);
    233.      printPathsRecur(root->rchild, v);
    234.      v.pop_back();
    235. }
    236. void printPaths(treeNode* node) {  
    237.     int path[1000];  
    238.     printPathsRecur(node, path, 0);  
    239. }  
    240. //用到的辅助函数:  
    241. /** 
    242.  * 求二叉树的深度 
    243.  */  
    244. int getDepth(BSTree root) {  
    245.     if (root == NULL)  
    246.         return 0;   
    247.     int left,right;
    248.     left = getDepth(root->lchild) + 1;
    249.     right = getDepth(root->rchild) + 1;
    250.     return left > right ? left : right;   
  • 相关阅读:
    P2802 【回家】
    P1706 【全排列问题】
    P1936 【水晶灯火灵】
    P1319 【压缩技术】
    P2670 【扫雷游戏】
    P1097 【统计数字】
    P1820 【寻找AP数】
    P1020 【导弹拦截】
    链表反转
    队列:队列在有限线程池中的应用
  • 原文地址:https://www.cnblogs.com/whelk/p/4482759.html
Copyright © 2011-2022 走看看