1.二叉排序树数据结构
1 typedef struct BSTNode{
2 int data;
3 struct BSTNode *lchild;
4 struct BSTNode *rchild;
5 }*BSTree,BSTNode;
- 按层次打印二叉树
- 如何判断一棵二叉树是否是平衡二叉树
- 如何判断一棵二叉树是否是平衡排序树
- 设计一个算法,找出二叉树上任意两个节点的最近共同父结点,复杂度如果是O(n2)则不得分。
- 将给定的二叉排序树转换成双链表,不得建立新结点
- 判断二叉树中是否有和为某一值的路径
- 打印二叉树中的所有路径(与题目5很相似)
- 怎样编写一个程序,把一个有序整数数组放到二叉树中?
- 判断整数序列是不是二叉搜索树的后序遍历结果
- 求二叉树的镜像
- 一棵排序二叉树(即二叉搜索树BST),令 f=(最大值+最小值)/2,设计一个算法,找出距离f值最近、大于f值的结点。复杂度如果是O(n2)则不得分
- 把二叉搜索树转变成排序的双向链表
解决思路:
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]); } }
先序遍历:访问根结点,先序遍历左子树,先序遍历右子树
中序遍历:中序遍历左子树,访问根结点,中序遍历右子树
后序遍历:后序遍历左子树,后序遍历右子树,访问根节点
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中了
以上程序如下:
- 解答2:
- //问题2:怎样从顶部开始逐层打印二叉树结点数据
- void PrintAtLevel(BSTree root){
- queue<BSTree> qu;
- BSTree p;
- qu.push(root);
- while(!qu.empty()){
- p = qu.front();
- if(p->lchild != NULL)
- qu.push(p->lchild);
- if (p->rchild != NULL)
- qu.push(p->rchild);
- cout << p->data << endl;
- vector.pop();
- }
- }
- //问题3:如何判断一棵二叉树是否是平衡二叉树
- int isBalencedTree(BSTree root){
- if (root == NULL)
- return 0;
- int depth1 = getDepth(root->lchild);
- int depth2 = getDepth(root->rchild);
- if (depth1 == depth2 || depth1 == depth2 + 1 || depth1 == depth2 - 1)
- return 1;
- else
- return 0;
- int flag1 = isBalencedTree(root->lchild);
- int flag2 = isBalencedTree(root->rchild);
- if (flag1 && flag2)
- return 1;
- else
- return 0;
- }
- //问题4:设计一个算法,找出二叉树上任意两个节点的最近共同父结点,复杂度如果是O(n2) 则不得分。
- int getPublicAncestors(treeNode* root,int key1,int key2){
- treeNode* ptr = root;
- int path1[1000];
- int pathLen1 = 0;
- while (ptr != NULL){
- if (key1 == ptr->data){
- path1[pathLen1] = ptr->data;
- pathLen1 ++;
- printArray(path1,pathLen1);
- break;
- }
- else
- if (ptr->data > key1){
- path1[pathLen1] = ptr->data;
- pathLen1 ++;
- ptr = ptr->lchild;
- }
- else
- if (ptr->data < key1){
- path1[pathLen1] = ptr->data;
- pathLen1 ++;
- ptr = ptr->rchild;
- }
- }
- ptr = root;
- int path2[1000];
- int pathLen2 = 0;
- while (ptr != NULL){
- if (key2 == ptr->data){
- path2[pathLen2] = ptr->data;
- pathLen2 ++;
- printArray(path2,pathLen2);
- break;
- }
- else
- if (ptr->data > key2){
- path2[pathLen2] = ptr->data;
- pathLen2 ++;
- ptr = ptr->lchild;
- }
- else
- if (ptr->data < key2){
- path2[pathLen2] = ptr->data;
- pathLen2 ++;
- ptr = ptr->rchild;
- }
- }
- int i = pathLen1 - 1;
- //key1和key2有序,
- if (key2 < key1){
- key2 = key2^key1;
- key1 = key2^key1;
- key2 = key2^key1;
- }
- for (; i > 0; i --){
- if (key1 < path1[i] && path1[i]< key2){
- int result = path1[i];
- return result;
- }
- }
- }
- //问题6:在二叉树中找出和为某一值的所有路径
- void FindPath(BSTree bt,int &cost,vector<BSTree> &v){
- if(bt != NULL){
- v.push_back(bt);
- cost -= bt->data;
- if(bt->lchild == NULL && bt->rchild == NULL && cost == 0){
- for(vector<BSTree>::iterator iter = v.begin(); iter != v.end(); iter++)
- cout << (*iter)->data << " ";
- cout << endl;
- }
- FindPath(bt->lchild, cost, v);
- FindPath(bt->rchild, cost, v);
- //恢复环境
- cost += bt->data;
- v.pop_back();
- }
- }
- //问题7:怎样编写一个程序,把一个有序整数数组放到二叉树中?
- void createTreeFromArray(int a[], int begin, int end, treeNode** root){
- if (begin > end)
- return;
- else{
- *root = (treeNode*) malloc(sizeof(treeNode));
- int mid = (begin + end) / 2;
- (*root)->data = a[mid];
- (*root)->rchild = NULL;
- (*root)->lchild = NULL;
- createTreeFromArray(a, begin ,mid - 1, &(*root)->lchild);
- createTreeFromArray(a, mid + 1 ,end, &(*root)->rchild);
- }
- }
- //问题8:判断整数序列是不是二叉搜索树的后//序遍历结果
- int isPostTraverse(int a[], int begin ,int end){
- if(begin >= end)
- return 1;
- else{
- int root = a[end];
- int lroot;
- int i;
- int location = begin;
- for (i = begin; i < end ; i ++){
- if(a[i] > root){
- location = i;
- lroot = a[i];
- break;
- }
- }
- for (i = location + 1; i < end; i++){
- if (a[i] < lroot){
- return 0;
- }
- }
- int flag1 = isPostTraverse(a,begin,location -1);
- int flag2 = isPostTraverse(a,location,end - 1);
- if (flag1 && flag2)
- return 1;
- else
- return 0;
- }
- }
- //问题9:求二叉树的镜像
- void changeMirror(BSTree &root){
- if ( root == NULL)
- return;
- else{
- BSTree temp = root->lchild;
- root->lchild = root->rchild;
- root->rchild = temp;
- changeMirror(&(*root)->lchild);
- changeMirror(&(*root)->rchild);
- }
- }
- //问题10:10.一棵排序二叉树(即二叉搜索树BST),令 f=(最大值+最小值)/2,设计一个算
- //法,找出距离f值最近、大于f值的结点。复杂度如果是O(n2)则不得分。
- int findNearMid(treeNode** root){
- treeNode* ptr = *root;
- int min, max;
- while (ptr != NULL){
- min = ptr->data;
- ptr = ptr->lchild;
- }
- printf("the min is %d\n",min);
- ptr = *root;
- while (ptr != NULL){
- max = ptr->data;
- ptr = ptr->rchild;
- }
- printf("the max is %d\n",max);
- int half = (min + max) >> 1;
- printf("half is %d\n",half);
- ptr = *root;
- while (1){
- if (ptr->data < half){
- ptr = ptr->rchild;
- }
- else
- if (ptr->data > half){
- int result = ptr->data;
- return result;
- }
- else
- {
- return (ptr->rchild)->data;
- }
- }
- }
- //问题12:打印二叉树中的所有路径(与题目5很相似)
- 程序1:
- void printPathsRecur(BSTree root, vector<BSTree> &v) {
- if (root == NULL)
- return;
- // append this node to the path array
- v.push_back(bt);
- // it's a leaf, so print the path that led to here
- if (root->lchild == NULL && root->rchild == NULL) {
- for(vector<BSTree>::iterator iter=v.begin(); iter != v.end(); iter++)
- cout << (*iter)->data << " ";
- cout << endl;
- }
- // otherwise try both subtrees
- printPathsRecur(root->lchild, v);
- printPathsRecur(root->rchild, v);
- //恢复环境
- v.pop_back();
- }
- 程序2
- void printPathsRecur(BSTree root, vector<BSTree> &v){
- if(root == NULL) return;
- if(root->lchild == NULL && root->rchild == NULL){
- for(vector<BSTree>::iterator iter=v.begin(); iter!=v.end(); iter++)
- cout << (*iter)->data << " ";
- cout << root->data << endl;
- }
- v.push_back(root);//移到这里来了,在if中需要打印出root的数据
- printPathsRecur(root->lchild, v);
- printPathsRecur(root->rchild, v);
- v.pop_back();
- }
- void printPaths(treeNode* node) {
- int path[1000];
- printPathsRecur(node, path, 0);
- }
- //用到的辅助函数:
- /**
- * 求二叉树的深度
- */
- int getDepth(BSTree root) {
- if (root == NULL)
- return 0;
- int left,right;
- left = getDepth(root->lchild) + 1;
- right = getDepth(root->rchild) + 1;
- return left > right ? left : right;
- }