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\n",min);  
  180.     ptr = *root;  
  181.     while (ptr != NULL){  
  182.         max = ptr->data;  
  183.         ptr = ptr->rchild;  
  184.     }  
  185.     printf("the max is %d\n",max);  
  186.     int half = (min + max) >> 1;  
  187.     printf("half is %d\n",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;   
posted on 2015-05-06 17:55  s201307109  阅读(269)  评论(0编辑  收藏  举报