二叉查找树通俗说就是左孩子比父亲小,右孩子比父亲大。构造这么一个树,树嘛,递归即可。

  例如一棵树后序遍历是这样(下图的树):2 9 8 16 15 10 25 38 45 42 30 20。最后的20肯定是树根,这里要抓住一个规律:20是树根,那么2 9 8 16 15 10都是左子树,25 38 42 45 30在右子树,因为左边都小于根、右边都大于根嘛。然后递归即可。

  下面是树的样子和代码和src.txt(后序遍历的结果)以及运行结果:

 #include <iostream>
#include <vector>
#include <fstream> using std::cin;
using std::cout;
using std::endl;
using std::vector; #define MY_DEBUG struct Node
{
int data;
Node* pLC;
Node* pRC;
}; Node* creatBSTree(vector<int>& arr)
{
//数组里面没有元素
if (!arr.size())
return nullptr; Node* pNode = new Node;
int thisData = arr.back();
pNode->data = thisData; //只有一个元素就不要折腾了,它就是叶子节点,它没有左右孩子
if ( == arr.size())
{
pNode->pLC = pNode->pRC = nullptr;
return pNode;
} //下面找出左半边
vector<int> arrLeft;
for (int i = ; i < arr.size() - ; i++)
{
if (arr[i] < thisData)
arrLeft.push_back(arr[i]);
else
break;
} //下面找出右半边
vector<int> arrRight;
for (int i = arrLeft.size(); i < arr.size() - ; i++)
arrRight.push_back(arr[i]); #ifdef MY_DEBUG
for (int i = ; i < arrLeft.size(); i++)
cout << arrLeft[i] << " ";
cout << endl; for (int i = ; i < arrRight.size(); i++)
cout << arrRight[i] << " ";
cout << endl << endl;
#endif //递归处理左右孩子。arrLeft和arrRight可能为空,不要紧,在函数的开头处理了
pNode->pLC = creatBSTree(arrLeft);
pNode->pRC = creatBSTree(arrRight); return pNode;
} //中序遍历
void show(Node* pNode)
{
if (!pNode)
return; show(pNode->pLC);
cout << pNode->data << " ";
show(pNode->pRC);
} int main(void)
{
vector<int> arr;
std::ifstream fin("src.txt"); int temp;
while (fin >> temp)
arr.push_back(temp); Node* pHead = creatBSTree(arr);
show(pHead);
cout << endl;
cin.get();
}
           

  由其他的遍历方式得到树的道理类似。




题目:

  输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果。如果是返回true,否则返回false。

分析:

  这不是很简单了嘛,由最后的根把输入分成三份,第一份是左孩子,第二份是右孩子,最后是树根。7、4、6、5就不能构成了,因为5是根,那么7,4,6都是右子树里面的,但是里面有小于5的4,所以不行。递归即可。




题目:

  输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。要求不能创建任何新的结点,只调整指针的指向。

  例如如果树如上图,那么得到的链表是 2=8=9=……=42=45。

分析:

  树嘛,递归就是啦。

  如上树,先递归处理左子树(根为10的树),处理完左子树就成了一个链表了,并要能够返回左子树的最大节点16;然后递归处理右子树(根为30的树),处理完右子树也成了一个有序链表,并返回右子树的最小节点25,然后把16、20、25串起来,不就是链表了嘛?

  这里要注意一点:在处理根为20的树时,这是不是要递归处理根为10的左子树嘛,那么这个左子树怎么知道它要返回16节点呢?同样对于20的右子树,它怎么知道返回25以和20串起来呢?所以在处理子树的时候,要传给它一个标志,表明它是父亲的左子树还是右子树。我在这里纠结好久……

代码:

 #include <iostream>
#include <set>
#include <fstream>
#include <queue> using std::cin;
using std::cout;
using std::endl;
using std::set;
using std::vector; struct Node
{
int data;
Node* pLC;
Node* pRC;
}; Node* creatBSTree(vector<int>& arr)
{
//数组里面没有元素
if (!arr.size())
return nullptr; Node* pNode = new Node;
int thisData = arr.back();
pNode->data = thisData; //只有一个元素就不要折腾了,它就是叶子节点,它没有左右孩子
if ( == arr.size())
{
pNode->pLC = pNode->pRC = nullptr;
return pNode;
} //下面找出左半边
vector<int> arrLeft;
for (int i = ; i < arr.size() - ; i++)
{
if (arr[i] < thisData)
arrLeft.push_back(arr[i]);
else
break;
} //下面找出右半边
vector<int> arrRight;
for (int i = arrLeft.size(); i < arr.size() - ; i++)
arrRight.push_back(arr[i]); #ifdef MY_DEBUG
for (int i = ; i < arrLeft.size(); i++)
cout << arrLeft[i] << " ";
cout << endl; for (int i = ; i < arrRight.size(); i++)
cout << arrRight[i] << " ";
cout << endl << endl;
#endif //递归处理左右孩子。arrLeft和arrRight可能为空,不要紧,在函数的开头处理了
pNode->pLC = creatBSTree(arrLeft);
pNode->pRC = creatBSTree(arrRight); return pNode;
} //中序遍历
void show(Node* pNode)
{
if (!pNode)
return; show(pNode->pLC);
cout << pNode->data << " ";
show(pNode->pRC);
} //这个函数多传了一个参数 asLeft,表明树根是树根的左子树还是右子树
//因为如果是左子树的话,那么要返回左子树最大节点,右子树要返回最小节点
//不要这个标志的话 pNode 不知道指向的树到底是父亲的左子树还是右子树
Node* letStraight(Node* pNode, bool asLeft)
{
//如果是空树或者只是一个叶子节点,返回自身
if (!pNode || (!pNode->pLC && !pNode->pRC))
return pNode; //递归处理左右子树
Node* pLMax = nullptr;
if (pNode->pLC)
pLMax = letStraight(pNode->pLC, true); Node* pRMin = nullptr;
if (pNode->pRC)
pRMin = letStraight(pNode->pRC, false); //连接左子树、右子树、树根
if (pLMax)
{
pNode->pLC = pLMax;
pLMax->pRC = pNode;
}
if (pRMin)
{
pNode->pRC = pRMin;
pRMin->pLC = pNode;
} //返回值处理,注意 asLeft 表明这棵树是它父亲的左子树还是右子树,所以它要重新找到合适的返回节点
// pNode 的左孩子最大或右孩子最小并不是它要返回的值,它要返回的还是要看这整棵树,而不是单单看左右孩子
Node* pRetutnNode = pNode;
if (asLeft)
{
while (pRetutnNode->pRC)
pRetutnNode = pRetutnNode->pRC;
}
else
{
while (pRetutnNode->pLC)
pRetutnNode = pRetutnNode->pLC;
}
return pRetutnNode;
} int main(void)
{
vector<int> arr;
std::ifstream fin("src.txt"); int temp;
while (fin >> temp)
arr.push_back(temp); Node* pHead = creatBSTree(arr);
show(pHead);
cout << endl; //顺序链表化并返回第一个节点
pHead = letStraight(pHead, false);
while (pHead)
{
cout << pHead->data << " ";
pHead = pHead->pRC;
}
cout << endl; cin.get();
}

结果:

由后序遍历结果构造二叉查找树 && 二叉查找树链表化的更多相关文章

  1. lintcode: 中序遍历和后序遍历树构造二叉树

    题目 中序遍历和后序遍历树构造二叉树 根据中序遍历和后序遍历树构造二叉树 样例 给出树的中序遍历: [1,2,3] 和后序遍历: [1,3,2] 返回如下的树: 2 /  \ 1    3 注意 你可 ...

  2. 【2】【leetcode-105,106】 从前序与中序遍历序列构造二叉树,从中序与后序遍历序列构造二叉树

    105. 从前序与中序遍历序列构造二叉树 (没思路,典型记住思路好做) 根据一棵树的前序遍历与中序遍历构造二叉树. 注意:你可以假设树中没有重复的元素. 例如,给出 前序遍历 preorder = [ ...

  3. LintCode-72.中序遍历和后序遍历树构造二叉树

    中序遍历和后序遍历树构造二叉树 根据中序遍历和后序遍历树构造二叉树 注意事项 你可以假设树中不存在相同数值的节点 样例 给出树的中序遍历: [1,2,3] 和后序遍历: [1,3,2] 返回如下的树: ...

  4. LeetCode106. 从中序与后序遍历序列构造二叉树

    106. 从中序与后序遍历序列构造二叉树 描述 根据一棵树的中序遍历与后序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 示例 例如,给出 中序遍历 inorder = [9,3,15,20 ...

  5. Leetcode:105. 从前序与中序遍历序列构造二叉树&106. 从中序与后序遍历序列构造二叉树

    Leetcode:105. 从前序与中序遍历序列构造二叉树&106. 从中序与后序遍历序列构造二叉树 Leetcode:105. 从前序与中序遍历序列构造二叉树&106. 从中序与后序 ...

  6. Java实现 LeetCode 106 从中序与后序遍历序列构造二叉树

    106. 从中序与后序遍历序列构造二叉树 根据一棵树的中序遍历与后序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 例如,给出 中序遍历 inorder = [9,3,15,20,7] 后序 ...

  7. [Swift]LeetCode106. 从中序与后序遍历序列构造二叉树 | Construct Binary Tree from Inorder and Postorder Traversal

    Given inorder and postorder traversal of a tree, construct the binary tree. Note:You may assume that ...

  8. LeetCode(106):从中序与后序遍历序列构造二叉树

    Medium! 题目描述: 根据一棵树的中序遍历与后序遍历构造二叉树. 注意:你可以假设树中没有重复的元素. 例如,给出 中序遍历 inorder = [9,3,15,20,7] 后序遍历 posto ...

  9. [LeetCode系列] 从中序遍历和后序遍历序列构造二叉树(迭代解法)

    给定中序遍历inorder和后序遍历postorder, 请构造出二叉树. 算法思路: 设后序遍历为po, 中序遍历为io. 首先取出po的最后一个节点作为根节点, 同时将这个节点入stn栈; 随后比 ...

随机推荐

  1. HttpClient和WebService的区别和介绍

    1. HTTP 协议可能是现在 Internet 上使用得最多.最重要的协议了,越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源.  HttpClient用来调用服务,它是模拟 ...

  2. mysql 实现oracle start with connect by递归

    在Oracle 中我们知道有一个 Hierarchical Queries 通过CONNECT BY 我们可以方便的查了所有当前节点下的所有子节点.但很遗憾,在MySQL的目前版本中还没有对应的功能. ...

  3. CentOS7 备忘录

    //安装CentOS7 1.用LinuxLive USB Creator,LiveUSB Creator设置U盘安装不成功,UltraISO可以. 2.旧电脑(x8le)安装时报"/dev/ ...

  4. 编写一个go gRPC的服务

    前置条件: 获取 gRPC-go 源码 $ go get google.golang.org/grpc 简单例子的源码位置: $ cd $GOPATH/src/google.golang.org/gr ...

  5. Centos安装软件小结-20160325

    三种安装包 bin包 rpm包 源码包 1.bin包 1.先赋予权限: chmod 777 *.bin 2.开始安装: ./.bin 2.rpm包(以jdk为例)\ yum search jdk\ y ...

  6. python 如何找到某一目录下的文件类型(三种方法)

    #!/usr/bin/env python import glob import os os.chdir(“./”) for file in glob.glob(“*.py”): print file ...

  7. Android 定时器TimerTask 简单使用

    Android平台中需要反复按周期执行方法可以使用Java上自带的TimerTask类,TimerTask相对于Thread来说对于资源 消耗的更低,除了使用Android自带的AlarmManage ...

  8. python读取数据库数据,读取出的中文乱码问题

    conn = pymysql.connect( host='127.0.0.1', port=3302, user='username', passwd='password', db=database ...

  9. [Mongo] 简单的操作命令

    1. 连接服务器: mongo 2. 连接数据库 use dbname 3. 查询所有集合的名字 db.getCollectionNames() 4. 查询某集合的数据 db.collection.f ...

  10. Windows Azure - App Services

    1. 需要了解的概念:App Service Plan, Resource Group 2. Create an ASP.NET web app in Azure App Services 3. Cr ...