12.1-1 对于关键字集合 { 1 , 4 , 5 , 10 , 16 , 17 , 21 } \{1,4,5,10,16,17,21\} {1,4,5,10,16,17,21},分别画出高度为2、3、4、5和6的二叉搜索树。
这里说明一下:算法导论中定义的高度是根节点到叶节点的最大距离
高度为2: 高度为3: 高度为4:
10 10 5
/ \ / \ / \
4 17 4 16 4 10
/ \ /\ / \ \ / \
1 5 16 21 1 5 17 1 16
\ \
21 17
\
21
高度为5: 高度为6:
4 1
/ \ \
1 5 4
\ \
10 5
\ \
16 10
\ \
17 16
\ \
21 17
\
21
12.1-2 二叉搜索树的性质与最小堆性质之间有什么不同?能使用最小堆性质在 O ( n ) O(n) O(n)时间内按序输出一颗n个结点树的关键字吗?可以的话,说明如何做,否则解释理由。
最小堆是一棵近似的完全二叉树(Perfect Binary Tree),满足堆中每个结点小于等于子结点。但是左右孩子之间的没有确定的大小关系。要想按序输出最小堆,需要使用堆排序的时间复杂度为 Ω ( n l g n ) \Omega(nlgn) Ω(nlgn)。
12.1-3 设计一个执行中序遍历的非递归算法。(提示:一个容易的方法是使用栈作为辅助数组结构;另一种较复杂但比较简介的做法是不使用栈,但要假设能测试两个指针是否相等)。
这个问题和算法导论练习10.4-3和10.4-5的题目一致。我在另外一篇博客已经讲过,大家可以看下。
算法导论10.4-5题解
12.1-4 对于一棵有n个结点的树,请设计在 Θ ( n ) \Theta(n) Θ(n)时间内完成的先序遍历算法和后序遍历算法。
下面是我的实现代码,分别给出了先序和后序遍历的递归和非递归实现。
#include<iostream>
#include<stack>
#define NIL -1
using namespace std;
struct Tree
{
Tree *left;
Tree *right;
int key;
};
//创建二叉树
void createTree(Tree *&t)
{
int key;
cin >> key;
if(key==NIL){
t=nullptr;
return;
}
t=new Tree();
t->key=key;
createTree(t->left);
createTree(t->right);
}
void print(const Tree* x)
{
cout << x->key << " ";
}
void preOrder_recursion(Tree* x)
{
if(x)
{
print(x);
preOrder_recursion(x->left);
preOrder_recursion(x->right);
}
}
void preOrder_byStack(Tree *x)
{
stack<Tree*> sta;
Tree *p=x;
while(p||!sta.empty())
{
while(p)
{
print(p);
sta.push(p);
p=p->left;
}
p=sta.top();
sta.pop();
p=p->right;
}
}
void postOrder_recursion(Tree *x)
{
if(x)
{
postOrder_recursion(x->left);
postOrder_recursion(x->right);
print(x);
}
}
void postOrder_byStack(Tree *x)
{
Tree *pre=nullptr;
stack<Tree*> sta;
while(x||!sta.empty())
{
while(x)//达到左子树
{
sta.push(x);
x=x->left;
}
x=sta.top();
//没有右子树或右子树已访问
if(!x->right||x->right==pre){
sta.pop();
print(x);
pre=x;
x=nullptr;
}
else
{
x=x->right;
}
}
}
int main()
{
Tree *head;
createTree(head);
cout << "先序遍历递归版:\n";
preOrder_recursion(head);
cout << "\n先序遍历非递归版:\n";
preOrder_byStack(head);
cout << "\n后序遍历递归版:\n";
postOrder_recursion(head);
cout << "\n后序遍历非递归版:\n";
postOrder_byStack(head);
}
这有两组测试数据,分别是题目12.1-1高度为2和6的二叉树。
数据1:
10 4 1 -1 -1 5 -1 -1 17 16 -1 -1 21 -1 -1
结果:
先序: 10 4 1 5 17 16 21
后序: 1 5 4 16 21 17 10
数据2:
1 -1 4 -1 5 -1 10 -1 16 -1 17 -1 21 -1 -1
结果:
先序:1 4 5 10 16 17 21
后序:21 17 16 10 5 4 1
12.1-5 因为在基于比较排序模型中,完成n个元素的排序,其最坏情况下需要 Ω ( n l g n ) \Omega(nlgn) Ω(nlgn)时间。证明:任何基于比较的算法从n个元素的任意序列中构造一棵二叉搜索树,其最坏情况需要 Ω ( n l g n ) \Omega(nlgn) Ω(nlgn)的时间。
证明:反证法,假设我们我可以在最坏情况 ο ( n l g n ) \omicron(nlgn) ο(nlgn)下完成BST的建立。那么对于排序来说,我们可以通过构造BST树,然后遍历BST来实现。
根据定理12.1
,我们可以在
Θ
(
n
)
\Theta(n)
Θ(n)的时间内完成对BST的遍历。那么意味着我们在
ο
(
n
l
g
n
)
\omicron(nlgn)
ο(nlgn)的时间内完成对
n
n
n个元素的排序算法。这与Chapter 8的基于比较的排序算法的下界为
Ω
(
n
l
g
n
)
\Omega(nlgn)
Ω(nlgn)相矛盾。
因此,假设不成立。