数据结构面试之六——二叉树的常见操作2(非递归遍历&二叉排序树)

数据结构面试之六——二叉树的常见操作2(非递归遍历&二叉排序树)

题注:《面试宝典》有相关习题,但思路相对不清晰,排版有错误,作者对此参考相关书籍和自己观点进行了重写,供大家参考。

六、二叉树的基本操作(非递归遍历)&二叉排序树的操作

       接上一节第五部分,主要分析二叉树的非递归遍历和二叉排序树的操作。

1.      非递归中序遍历

//1.依次将根节点root的左子树入栈,直到lchild=NULL,执行2

//2.将栈的元素出栈、访问;将当前指针指向节点的rchild,循环遍历。直到栈空为止!

      

[cpp]  view plain copy
  1. template<typenameelemType>  
  2.       voidbinaryTreeType<elemType>::noRecursionInorderTraversal()                      //非递归中序遍历  
  3.       {  
  4.              cout<< "noRecursionInorderTraversal--------------------------->"<< endl;  
  5.              linkedStackType<nodeType<elemType>* > stack;  
  6.              nodeType<elemType>*current = root;  
  7.              while(current!= NULL || !stack.isEmptyStack())  //或者||  
  8.              {  
  9.                     if(current!= NULL)  
  10.                     {  
  11.                            stack.push(current);  
  12.                            current= current->llink;  
  13.                     }  
  14.                     else  
  15.                     {  
  16.                            stack.pop(current);  
  17.                            cout<< current->info << "\t"//出栈的时候访问节点  
  18.                            current= current->rlink;  
  19.                     }  
  20.              }  
  21.              cout<< endl;  
  22.              cout<< "<------------------------noRecursionInorderTraversal"<< endl;  
  23.       }  

2.      非递归先序遍历

       //在中序遍历的基础上,访问次序发生变化;

       //先序遍历,需要先逐个遍历根节点,然后依次处理其左、右孩子节点。

     

[cpp]  view plain copy
  1. template<typenameelemType>  
  2.      voidbinaryTreeType<elemType>::noRecursionPreorderTraversal()                     //非递归前序遍历  
  3.      {  
  4.             cout<<"noRecursionPreorderTraversal--------------------------->"<< endl;  
  5.             linkedStackType<nodeType<elemType>* > stack;  
  6.             nodeType<elemType>*current = root;  
  7.             while(current!= NULL || !stack.isEmptyStack())  //或者||  
  8.             {  
  9.                    if(current!= NULL)  
  10.                    {  
  11.                           cout<< current->info << "\t";   //先访问节点后入栈  
  12.                           stack.push(current);  
  13.                           current= current->llink;  
  14.                    }  
  15.                    else  
  16.                    {  
  17.                           stack.pop(current);  
  18.                           current= current->rlink;  
  19.                    }  
  20.             }  
  21.             cout<< endl;  
  22.             cout<< "<------------------------noRecursionPreorderTraversal"<< endl;  
  23.      }  

3.      非递归后序遍历

由于访问的顺序为先左子树、然后右子树,最后根节点。并且对于每一个节点都是上述操作,所以,对于遍历来讲,需要识别当前节点类型是根(相对)、左孩子节点 、右孩子节点。故,我们设定了flag标记变量flag=0初始标记,节点尚未入栈;在访问左孩子之前将flag置为1;在访问右孩子之前将flag置为2;并且在访问右孩子之后,将flag置为0。

       //后序非递归遍历比较复杂..

     

[cpp]  view plain copy
  1. template<typenameelemType>  
  2. idbinaryTreeType<elemType>::noRecursionPostorderTraversal()                    //非递归后序遍历  
  3.      {  
  4.             cout<<"noRecursionPostorderTraversal--------------------------->"<< endl;  
  5.             linkedStackType<nodeType<elemType>* > stack;  
  6.             linkedStackType<int>intStack;                       //标记位同步栈.  
  7.             nodeType<elemType>*current = root;  
  8.             intnflag = 0;                                      //初始标记为0.  
  9.             if(current== NULL)  
  10.             {  
  11.                    cout<< "The Stack is Empty!" << endl;  
  12.             }  
  13.             else  
  14.             {  
  15.                    //1.将头节点先入栈,  
  16.                    stack.push(current);  
  17.                    intStack.push(1);  
  18.              current = current->llink;        //注意此处需要调整指向******  
  19.                    while(!stack.isEmptyStack()&& !intStack.isEmptyStack())           
  20.                    {  
  21.                           if(current!= NULL && nflag == 0)                                       
  22.                           {  
  23.                              stack.push(current);  
  24.                                  intStack.push(1);   //标记位为1,[在访问左孩子之前,将其值置为1]。  
  25.                              current = current->llink;  
  26.                           }  
  27.                           else  
  28.                           {  
  29.                                  stack.pop(current);  
  30.                                  intStack.pop(nflag);    //此时的标记位为返回值,需要根据其做判断  
  31.                                  if(nflag== 1)         //说明下一步需要入栈的为右孩子.  
  32.                                  {  
  33.                                         stack.push(current);   //继续将该节点入栈,                                                                
  34.                                        intStack.push(2);      //但[在访问右孩子之前,将其置为2]。  
  35.                                         current= current->rlink;           //访问右节点,  
  36.                                         nflag= 0;                                  //置标记位为0  
  37.                                  }  
  38.                                  else  
  39.                                  {  
  40.                                         cout<< current->info << " ";  //待左右子树都为空再访问节点。  
  41.                                  }  
  42.                           }  
  43.                    }  
  44.                    cout<< endl;  
  45.                    cout<< "<------------------------noRecursionPostorderTraversal"<< endl;  
  46.             }      
  47.      }  

 

4.      二叉排序树的搜索操作

明确概念,国内、国外的著作里提及的下三个概念等价,二叉搜索树=二叉查找树=二叉排序树。

//二叉排序树的查找存在以下几种情况:

//1.链表为空,提示并返回;

//2.链表非空,需要循环查找直到指针为空,若存在,则bfound=true;否则查找至最后bfound=缺省false。

[cpp]  view plain copy
  1. template <class elemType>  
  2. boolbSearchTreeType<elemType>::search(const elemType& searchItem)  
  3. {  
  4.        nodeType<elemType>*current = new nodeType<elemType>;  
  5.        boolbFound = false;  
  6.    
  7.        if(root== NULL)  
  8.        {  
  9.               cout<< "The bSearchTree is NULL\n";       //case1: 链表为空!  
  10.               returnfalse;  
  11.        }  
  12.        else  
  13.        {  
  14.               current= root;  
  15.               while(current!= NULL && !bFound) //case2:在链表中查找,根据大小锁定左、右子树.  
  16.               {  
  17.                      if(current->info== searchItem)  
  18.                      {  
  19.                             bFound= true;  
  20.                      }  
  21.                      elseif(current->info > searchItem)  
  22.                      {  
  23.                             current= current->llink;              //左子树  
  24.                      }  
  25.                      elseif(current->info < searchItem)  
  26.                      {  
  27.                             current= current->rlink;             //右子树  
  28.                      }  
  29.               }  
  30.        }  
  31.    
  32.        returnbFound;  
  33. }  

5.      二叉排序树的插入存在以下几种情况:

//1.链表为空,插入元素即为根节点;

//2.链表非空,需要寻找插入位置后插入。

//2.1插入元素已经存在,则提示出错。

//2.2总能找到大于或小于某节点的位置,记录trailcurrent完成插入操作。

[cpp]  view plain copy
  1. template <class elemType>  
  2. voidbSearchTreeType<elemType>::insert(const elemType& insertItem)  
  3. {  
  4.        nodeType<elemType>*newNode = new nodeType<elemType>;  
  5.        nodeType<elemType>*current;  
  6.        nodeType<elemType>*trailCurrent;  
  7.    
  8.        newNode->info= insertItem;  
  9.        newNode->llink= NULL;  
  10.        newNode->rlink= NULL;  
  11.    
  12.        if(root== NULL)  
  13.        {  
  14.               root= newNode;                                //case1:树为空.  
  15.        }  
  16.        else  
  17.        {  
  18.               current= root;  
  19.               while(current!= NULL)                          //case2,3,4搜索才知道!  
  20.               {  
  21.                      trailCurrent= current;  
  22.                      if(current->info== insertItem)  
  23.                      {  
  24.                             cout<< "the elem is already exist!\n";  //case2:元素已经存在  
  25.                             return;  
  26.                      }  
  27.                      else  
  28.                      {  
  29.                             if(current->info> insertItem)  
  30.                             {  
  31.                                    current= current->llink;           //case3:锁定左侧位置...  
  32.                             }  
  33.                             else  
  34.                             {  
  35.                                    current= current->rlink;           //case4:锁定右侧位置...  
  36.                             }  
  37.                      }  
  38.               }//endwhile  
  39.    
  40.               //case3,4根据大小进行链接  
  41.               if(trailCurrent->info< insertItem)             
  42.               {  
  43.                      trailCurrent->rlink= newNode;  
  44.               }  
  45.               else  
  46.               {  
  47.                      trailCurrent->llink= newNode;  
  48.               }  
  49.    
  50.        }//end else  
  51. }  

6.       二叉排序树的删除存在以下几种情况【此处可能复杂些】:

//删除一个节点,要首先判断元素值在二叉排序树中是否存在,

//若不存在则返回;

//若存在则需要锁定其对应位置为1根节点;2叶节点;3其余节点。

//根据要删除的节点是否含有左右子树的不同,分为4种情况考虑,

//见deleteFromTree()函数。

[cpp]  view plain copy
  1. template <class elemType>  
  2. voidbSearchTreeType<elemType>::deleteNode(const elemType& deleteItem)  
  3. {  
  4.        //1.查找节点  
  5.        //2.1找不到,不存在;  
  6.        //2.2找到,删除,调用函数  
  7.        nodeType<elemType>*current;  
  8.        nodeType<elemType>*trailCurrent;  
  9.        boolbFound = false;  
  10.    
  11.        if(root== NULL)  
  12.        {  
  13.               cout<< "Can't delete an Empty BST" << endl;  
  14.               return;  
  15.        }  
  16.        else  
  17.        {  
  18.               current= root;  
  19.               trailCurrent= root;  
  20.               while(current != NULL && !bFound)  
  21.               {  
  22.                      if(current->info== deleteItem)  
  23.                      {  
  24.                             bFound= true;  
  25.                      }  
  26.                      elseif(current->info > deleteItem)  
  27.                      {  
  28.                             trailCurrent= current;  
  29.                             current= current->llink;    //左  
  30.                      }  
  31.                      else  
  32.                      {  
  33.                             trailCurrent= current;  
  34.                             current= current->rlink;   //右  
  35.                      }  
  36.               }//endwhile  
  37.    
  38.               if(current== NULL)  
  39.               {  
  40.                      cout<< deleteItem << " is not Exist in the BST!\n" <<endl;  
  41.               }  
  42.               elseif(bFound)  
  43.               {  
  44.                      if(current== root)  
  45.                      {  
  46.                             deleteFromTree(root);                  //可能是根节点  
  47.                      }  
  48.                      elseif(trailCurrent->info > deleteItem)  
  49.                      {  
  50.                             deleteFromTree(trailCurrent->llink);//左半分支,调整trailCurrent的指向  
  51.                      }  
  52.                      elseif(trailCurrent->info < deleteItem)  
  53.                      {  
  54.                             deleteFromTree(trailCurrent->rlink);  //右半分支,调整trailCurrent的指向  
  55.                      }  
  56.               }//endif bFound  
  57.          }//end else  
  58. }  


//[原理]:某节点的前驱是该节点左子树的最右端的节点(中序遍历的结果)

[cpp]  view plain copy
  1. template <class elemType>  
  2. voidbSearchTreeType<elemType>::deleteFromTree(nodeType<elemType>*&p)  
  3. {  
  4.        nodeType<elemType>*temp;  
  5.        nodeType<elemType>*current;  
  6.        nodeType<elemType>*trailCurrent;  
  7.    
  8.        if(p== NULL)  
  9.        {  
  10.               cout<< "The BST is NULL!" << endl;  
  11.               return;  
  12.        }  
  13.        if(p->llink== NULL && p->rlink == NULL)      //情况1,左右节点都为空(叶节点)  
  14.        {  
  15.               temp= p;  
  16.               p= NULL;  
  17.               deletetemp;  
  18.        }  
  19.        elseif( p->rlink == NULL)                     //情况2,右子树为空,左非空  
  20.        {  
  21.               temp= p;  
  22.               p= temp->llink;  
  23.               deletetemp;  
  24.        }  
  25.        elseif(p->llink == NULL)                      //情况3,左子树为空,右非空  
  26.        {  
  27.               temp= p;  
  28.               p= temp->rlink;  
  29.               deletetemp;  
  30.        }  
  31.        else                           //情况4,左右都非空[用中序遍历的前一个节点替换]  
  32.        {  
  33.               current= p->llink;  
  34.               trailCurrent= NULL;  
  35.    
  36.               while(current->rlink!= NULL)  
  37.               {  
  38.                      trailCurrent= current;   //trailCurrent最终指向准备删除节点的前一个节点  
  39.                      current= current->rlink;  
  40.               }  
  41.    
  42.               p->info= current->info;                //信息赋值  
  43.    
  44.               if(trailCurrent== NULL)              //仅一个左孩子节点  
  45.               {  
  46.                      p->rlink = current->llink;           
  47.               }  
  48.               else  
  49.               {  
  50.                      trailCurrent->rlink= current->llink; //给删除前点的前面一个节点调整指针指向  
  51.               }  
  52.               deletecurrent;  
  53.        }  
  54.    
  55. }  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值