微软面试百题001——BST转化有序双向链表
来源:互联网 发布:清理数据库在哪里 编辑:程序博客网 时间:2024/06/07 15:08
001.微软面试百题之BST转双向链表
1.题意描述:
不允许开辟新的节点,只是改变指针的转向,将一颗标准的BST转化为一个双向链表,返回双向链表的头指针
测试用例描述:
7
5 9
-2 8 10
3 12
1
这棵二叉查找树转化为双向链表的操作结果是:-2 --1 --3 --5 --7 --8 --9 --10 --12
2.思维考虑:
BST:
本博主的BST总结详解
这里我们先考虑BST 的性质,BST作为一颗高效的二叉查找树,性质如下:
1.空树
2.非空树且左子树节点键值均小于根节点的键值,右子树所有的节点的键值均大于根节点的键值
左右子树均为一颗BST
那么再转化成双向链表的时候,我们根据题意只能通过改变指针来进行操作,当然操作的前提是比该节点的键值小的节点已经存在于有序的双向链表中,这样子进行递归的定义我们就会发现,我们要保证是有序的双向链表,那么我们根据BST 的性质完全可以通过所谓的中序遍历来实现,在中序遍历的时候我们队当前的根节点的指针域进行操作就可以了
指针域的操作如下:
准备操作
首先我们要开辟两个辅助的指针来帮助我们根号的控制目前已经有序的双向链表
1.head指针:作为整个双向链表的头结点(只有两种状态,空或者非空,空代表目前双向链表不存在任何一个有序的节点,非空代表目前的双向链表中至少有一个有序的节点)
2.listtail指针:顾名思义,listtail时终止向目前的双向链表中的最后一个元素(只有两个状态,空和非空,空代表目前双向链表不存在任意一个有序的节点,非空代表至少存在一个有序的节点),实际上我们发现listtail和head的状态实际上是同步的,那我们为什么要新引入一个listtail指针呢,其实这完全是为了节省时间,如果我们不引入这个指针内存空间,那么我们就必须环肥O(n)复杂度的使劲去遍历一遍整个目前有序的双向链表,所谓空间换时间,相对而言,这么做是非常划算的
指针变化
(p代表当期吗遍历到的节点,方便后续我们的被描述)
1.如果head为空,那么我们令head只想当前遍历到的节点,然后listtail同样指向这个节点
2.如果head不为空,说明listtail目前有确定指向,那么我们将listtail->right=p,p->left=listtail,listtail=p(最后一步的作用实际上是扩展我们的listtail,保证期时终止向最后一个节点);
3.C++代码实现,类封装
因为在博主上一期的数据结构专题中,已经讨论过BST并且封装了BST的代码,这次我就直接拿来调用了,强调一点,对于Cbst我是考虑了公有继承,所以之后要用到root成员,所以bst我们这里设定成保护类型(实际上C++代码中,一旦要被继承的对象中的成员我们都是设定成保护类型的)
具体的操作和解释在代码中进行注释
#include"iostream"#include"cstdio"#include"cstdlib"using namespace std;typedef struct node { int key; struct node* left; struct node* right; }point; class errorsame { }; class bst { public: bst() { root=NULL; num=0; } virtual ~bst() { clear(root); } void add(int); void del(int); point* find(int); void clear(point*); void preorder(point*); void midorder(point*); void aftorder(point*); void rankorder(); point* returnroot() { return root; } protected: point* root; int num; }; void bst::clear(point* p) { if(p==NULL) return ; else { clear(p->left); clear(p->right); free(p); } } void bst::add(int p) { if(num==0) { root=new point; root->right=root->left=NULL; root->key=p; num++; return ; } else { try { point *k=root; point* w=root; while(w!=NULL) { if(w->key==p) throw errorsame(); else { if(w->key>p) w=w->left; else w=w->right; } if(w!=NULL) k=w; } if(k->key>p) { point *a=new point(); a->left=a->right=NULL;a->key=p; k->left=a; } else { point *a=new point(); a->left=a->right=NULL;a->key=p; k->right=a; } num++; } catch(errorsame e) { cout<<"try to add the same point in the tree!"<<endl; } } } void bst::del(int p) { point* now=root; point* father=NULL; while(now->key!=p) { if(now->key>p) { father=now; now=now->left; } else { father=now; now=now->right; } if(now==NULL) { cout<<"can not find the point!"<<endl; return ; } } if(father==NULL) { point* help=root; if(root->right==NULL) root=root->left; else { if(root->right->left==NULL) { root->right->left=root->left; root=root->right; } else { point* z=NULL; point* k=root->right; point* w=root; while(k->left!=NULL) { if(k->left->left==NULL) z=k; k=k->left; } z->left=k->right; k->left=root->left; k->right=root->right; root=k; } } free(help); } else if(now->right==NULL) { point* help=now; if(father->left==now) father->left=now->left; else father->right=now->left; free(help); } else { if(now->right->left==NULL) { point* help=now; now->right->left=now->left; if(father->left==now) father->left=now->right; else father->right=now->right; free(help); } else { point* z; point* k=now->right; while(k->left!=NULL) { if(k->left->left==NULL) z=k; k=k->left; } if(father->left==now) { z->left=k->right; father->left=k; k->left=now->left; k->right=now->right; } else { z->left=k->right; father->right=k; k->left=now->left; k->right=now->right; } } } } point* bst::find(int p) { point* a=root; while(a!=NULL) { if(a->key==p) return a; if(a->key>p) a=a->left; else a=a->right; } } void bst::preorder(point* p) { if(p==NULL) return ; else { printf("%d ",p->key); preorder(p->left); preorder(p->right); } } void bst::midorder(point* p) { if(p==NULL) return ; else { midorder(p->left); printf("%d ",p->key); midorder(p->right); } } void bst::aftorder(point* p) { if(p==NULL) return ; else { aftorder(p->left); aftorder(p->right); printf("%d ",p->key); } } void bst::rankorder() { point* queue[100]; int head=1; int tail=2; queue[1]=root; while(head!=tail) { if(queue[head]->left!=NULL) queue[tail++]=queue[head]->left; if(queue[head]->right!=NULL) queue[tail++]=queue[head]->right; head++; } for(int i=1;i<=tail-1;i++) printf("%d ",queue[i]->key); } class Cbst:public bst{public:Cbst():bst(){head=listtail=NULL;}virtual ~Cbst() //这里就不再赘语为什么用虚析构函数了 {//强调一点,在这里我们必须要对bst进行变换,因为我懒得写那几行切换的代码了point* p=head;while(p!=NULL){point* w=p;p=p->right;free(w);} root=NULL; //很尴尬,我的虚析构函数知识点忘了,所以这里手工将root设定成NULL,防止指针玄关的错误发生,尴尬,继续去复习指针玄关的知识点去 }void visit(point*); //中序遍历 void change(point*); //中序遍历中对指针的进行的节点指针操作 void scan(); //程序正确性与否的测试代码段 private:point* head;point* listtail;};void Cbst::visit(point* p){if(p==NULL) return ;else{visit(p->left);change(p);visit(p->right);} }void Cbst::change(point* p){if(head==NULL){head=p;listtail=p;}else{p->left=listtail;listtail->right=p;listtail=p;return ;}}void Cbst::scan(){point* p=head;while(p!=NULL){cout<<p->key<<' ';p=p->right;}cout<<endl;}int main(){Cbst my;my.add(7);my.add(5);my.add(9);my.add(-2);my.add(10);my.add(3);my.add(1);my.add(8);my.add(12);my.visit(my.returnroot());my.scan();return 0;}
1 0
- 微软面试百题001——BST转化有序双向链表
- 微软面试100题---将 二叉搜索树 转化成 有序的双向链表
- [微软面试100题] 二元查找数变成有序的双向链表
- 二叉排序树转化为有序双向链表
- 将BST转换为有序的双向链表!
- BST树转换为有序双向循环链表
- 将单向有序链表转化为BST
- 1. BST树转化为双向链表
- 微软面试百题004——指定BST路径和
- 微软面试百题008——后序遍历找BST
- 微软面试百题015——镜像翻转BST
- 微软面试百题016——BST层序遍历
- 二叉搜索树转化为有序双向链表
- 二叉搜索树转化为有序双向链表
- 二叉查找树转换为有序双向链表---微软
- 微软100题 第一题(查找树转换为有序双向链表)
- 剑指offer面试题27BST转换为有序双向链表
- 数据结构面试之二——双向链表表、循环链表、有序链表的常见操作
- HDU1017——A Mathematical Curiosity
- 6.shell编程(6) --- 特殊文件
- ffmpeg命令
- 建议锁
- 数据结构实验之二叉树二:遍历二叉树
- 微软面试百题001——BST转化有序双向链表
- 【HDOJ1536】S-Nim(博弈)
- Java检测字符串中是否有中文
- 位操作符的口诀
- 1596 - Bug Hunt
- ThreadLocal
- USB设备枚举过程
- 面试总结之操作系统篇
- 在终端输入多行信息,找出包含“ould”的行,并打印改行。