树
树的题目基本都是二叉树,但是面试官还没有说是不是二叉树的时候千万不要先把答案说出来,要是面试官说是多叉树,而你做的是二叉树就直接挂了!
一. 树的三种遍历。前序、中序、后序,如果直接考遍历,就肯定是让你写非递归代码的(递归版太弱智了),具体写法,要不你记下来,要不参考“递归”部分的,怎么递归转非递归,另一个就是给个中序+前序(后序),让你还原二叉树,中序必须给,不然还原不了(解不唯一),一般递归解决;
二. BST(Binary Search Tree)。这个考法多一点,怎么判断是不是BST(或者平衡树,或者完全树),有序数组(有序链表)转换成BST,在BST中找某个upper_bound的最大值(这个可以给root让你找符合要求的节点,可以给一个等于upper_bound的节点,有parent指针,让你找),然后还 有其他其他
三. LCA(Least Common Ancestor,最近公共祖先)。超高频题,主要考法是给两个指针和树的root,找LCA,如果节点有parent节点(这时候就不给root了),就相当于链表找第一个交点了,如果没有parent就要麻烦一点;
四. 序列化与发序列化。这个考法比较简单,就是写一个序列化和发序列化的方法,有思考过的话直接就可以秒了,一样的问题还有字符串数组的序列化。一般思路是加一个记录分段信息的head或者加一个不会出现的字符作为一种分割。有时候会说任何字符都可能出现,这时候可以用转义字符(想想C的字符串怎么记录\的吧)。
树的遍历:
遍历分为三种:前序中序后序。在三种遍历中,前序和中序遍历的非递归算法都很容易实现,非递归后序遍历实现起来相对来说要难一点。
前序遍历:按照“根结点-左孩子-右孩子”的顺序进行访问。
1 #include<iostream> 2 using namespace std; 3 4 void presearch1(BinTree *root){//递归前序 5 if(root!=NULL){ 6 cout<<root->data<<" "<<endl; 7 presearch1(root->leftchild); 8 presearch1(root->rightchild); 9 } 10 } 11 void presearch2(BinTree *root){//非递归前序:相当于直接到最左边最底部的地方,先是遍历根节点,然后最左边然后右边,然后在向上遍历。 12 /*根据前序遍历访问的顺序,优先访问根结点,然后再分别访问左孩子和右孩子。即对于任一结点,其可看做是根结点,因此可以直接访问,访问完之后,若其左孩子不为空,按相同规则访问它的左子树;当访问其左子树时,再访问它的右子树。因此其处理过程如下: 13 对于任一结点P: 14 1)访问结点P,并将结点P入栈; 15 2)判断结点P的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点P,循环至1);若不为空,则将P的左孩子置为当前的结点P; 16 3)直到P为NULL并且栈为空,则遍历结束。 17 */ 18 stack<BinTree *>s;//创建一个栈用来存储树的节点 19 BinTree *p=root; 20 while(p!=NULL || !s.empty()){//树不为空或者栈不为空 21 while(p!=NULL){//当根节点不为空,将更节点入栈 22 cout<<p->data<<" ,"; 23 s.push(root); 24 p=p->leftchild;//一直到最左边的孩子,跳出循环 25 } 26 if(!s.empty()){//看栈是否为空,不为空将当前的节点P出栈 27 p=s.top();//将P置为更节点 28 s.pop(); 29 p=p->rightchild;//右移 30 } 31 } 32 }