查找树,也许是高级货,因为满足的性质蛮有型的,即left<root<right,其实算起来,和堆挺像的,只是堆是root > left(right),而且堆对左右就不怎么管了,如果效果好点,直接建个排序树,排序什么的,岂不直接就搞定了?
说到这个,扯一下,上次看到一人说快速排序,虽说表面上核心算是划分,实际在背后有一颗二叉排序树。从这个观点来看,的确,每次划分,都是找到了子树的一个root节点,且大方向是left<right,其实这说法是很有道理的。而且从这个角度看,快排快于堆排序,也许是因为对左右孩子的大小限制了,而不像堆,只管root最大。
不过二叉查找树的定义不是很严格,虽然比起堆来好了不少,只是限制left<root<right,这样的话,同样的数字组合,形成的排序树,高度会差很多,如下所示:
不过也许是因为这个原因,才有了更平衡的红黑树的引入啊,多和谐。
习题12.1-3可参考: http://www.cnblogs.com/shuaiwhu/archive/2011/04/20/2065055.html用C++写的,哎,发现现在自己写的都特么C,哎。对于12.1-4,前序和后续遍历的递归,貌似就一种方式吧?以先序为例。额,这个莫非真能Θ(n)时间内搞定?
void PrintTree(BiTree T)
{ // 初始条件: 二叉树T存在;操作结果: 先序输出T的元素
if(T) // T不空
{
cout << T->data<<" " ; // 输出根结点
PrintTree(T->lchild); // 遍历左子树
PrintTree(T->rchild); // 遍历右子树
}
}
这边的一些对二叉树的基本操作,都蛮简单的,除了TREE-INSERT是个不错的过程外,伪代码如下:
TREE-INSERT(T, z)
1 y ← NIL
2 x ← root[T]
3 while x ≠ NIL
4 do y ← x
5 if key[z] < key[x]
6 then x ← left[x]
7 else x ← right[x]
8 p[z] ← y
9 if y = NIL
10 then root[T] ← z //Tree T was empty
11 else if key[z] < key[y]
12 then left[y] ← z
13 else right[y]
比如12.3-2和12.3-3提到,我们可以用反复插入的方式构造而查抄找树;也可以不断的插入构造二叉查找树,然后中序遍历输出,排序就好了,伪代码如下:
for i = 1 to n
TREE-INSERT(T,A[i])
INORDER-TREE-WALK(T.root)
这样的排序,最坏情况下必然是O(n^2),在整个二叉树为一条线形的时候,其实这情况看起来跟偏瘫没什么两样。(虽然这种事情出现的概率很低,不过科学就是TMD的要注重严谨,所以啊,哎),TREE-INSERT为O(n)则整个就O(n2),最好情况为O(nlgn),当二叉树比较均衡,高度为lgn时。看到了吧, 跟快排的多么相似啊,最坏情况是二叉树线性时,最好就是二叉树均衡时,二叉树思想果然是快排提速的关键呢么?
最后是本次实现的很粗糙的代码:(main函数上为测试序列:10 4 1 0 0 5 0 0 17 16 0 0 21 0 0)
#include <iostream>
using namespace std;
const int NIL=0;
//二叉查找树结构体
typedef struct BiTNode
{
int data;
struct BiTNode *lchild,*rchild ,*parent; //左右孩子,父指针
}BiTNode,*BiTree;
//基本操作
int InitBiTree(BiTree &T)
{ //构造空二叉树T
T=NULL;
return 1;
}
void DestroyBiTree(BiTree &T)
{ // 初始条件: 二叉树T存在。操作结果: 销毁二叉树T
if(T) // 非空树
{
if(T->lchild) // 有左孩子
DestroyBiTree(T->lchild); // 销毁左孩子子树
if(T->rchild) // 有右孩子
DestroyBiTree(T->rchild); // 销毁右孩子子树
delete T;
//free(T); // 释放根结点
T=NULL; // 空指针赋0
}
}
void CreateBiTree(BiTree &T)
{ // 按先序次序输入二叉树中结点的值构造二叉链表表示的二叉树T。变量NIL表示空(子)树
int key;
cin >> key;
if(key==NIL) // 空
T=NULL;
else
{
T = new BiTNode;
T->data=key; //* 生成根结点
// T->parent = NULL;
// if (T->rchild)
// T->rchild->parent = T;
// if (T->lchild)
// T->lchild->parent = T;
CreateBiTree(T->lchild); //* 构造左子树
CreateBiTree(T->rchild); //* 构造右子树
}
}
int BiTreeEmpty(BiTree T)
{// 初始条件: 二叉树T存在
// 操作结果: 若T为空二叉树,则返回TRUE,否则FALSE
if(T)
return 0;
else
return 1;
}
int BiTreeDepth(BiTree T)
{ // 初始条件: 二叉树T存在。操作结果: 返回T的深度
int i,j;
if(!T)
return 0;
if(T->lchild)
i=BiTreeDepth(T->lchild);
else
i=0;
if(T->rchild)
j=BiTreeDepth(T->rchild);
else
j=0;
return i>j ? i+1:j+1;
}
int Root(BiTree T)
{ // 初始条件: 二叉树T存在。操作结果: 返回T的根
if(BiTreeEmpty(T))
return NIL;
else
return T->data;
}
int InsertChild(BiTree p,int LR,BiTree c) // 形参T无用
{ // 初始条件: 二叉树T存在,p指向T中某个结点,LR为0或1,非空二叉树c与T
// 不相交且右子树为空
// 操作结果: 根据LR为0或1,插入c为T中p所指结点的左或右子树。p所指结点的
// 原有左或右子树则成为c的右子树
if(p) // p不空
{
if(LR==0)
{
c->rchild=p->lchild;
p->lchild=c;
}
else // LR==1
{
c->rchild=p->rchild;
p->rchild=c;
}
return 1;
}
return -1; // p空
}
int DeleteChild(BiTree p,int LR) // 形参T无用
{ // 初始条件: 二叉树T存在,p指向T中某个结点,LR为0或1
// 操作结果: 根据LR为0或1,删除T中p所指结点的左或右子树
if(p) // p不空
{
if(LR==0) // 删除左子树
DestroyBiTree(p->lchild);
else // 删除右子树
DestroyBiTree(p->rchild);
return 1;
}
return -1; // p空
}
void PrintTree(BiTree T)
{ // 初始条件: 二叉树T存在
// 操作结果: 先序输出T的元素
if(T) // T不空
{
cout << T->data<<" " ; // 访问根结点
PrintTree(T->lchild); // 遍历左子树
PrintTree(T->rchild); // 遍历右子树
}
}
int TreeSearch(BiTree x , int k)
{//在查找树x中查找关键字k
if (x)
{
if ( (x->data == NIL) || (k == x->data) )
return x->data ;
if ( k < x->data )
return TreeSearch( x->lchild , k ) ;
else
return TreeSearch( x->rchild , k ) ;
}
else
return NIL;
}
int TreeMininum(BiTree x)
{//返回树T中的最小元素
while (x->lchild != NIL)
x = x->lchild;
return x->data;
}
int TreeMaximum(BiTree x)
{//返回树T中的最大元素
while (x->rchild != NIL)
x = x->rchild ;
return x->data;
}
//10 4 1 0 0 5 0 0 17 16 0 0 21 0 0
int main(int argc,char **argv)
{
BiTree T;
CreateBiTree(T);
PrintTree(T);
cout << endl;
cout << "Max = " << TreeMaximum(T) << endl;
cout << "Min = " << TreeMininum(T) << endl;
cout << TreeSearch(T,11) << endl;
DestroyBiTree(T);
PrintTree(T);
return 0;
}
就没有实现TREE-INSERT和TREE-DELETE过程,TankyWoo的实现不错,还蛮详细,参考:http://www.wutianqi.com/?p=2430。本章搞定,下面红黑树了,哎呀,高级货~~
菜鸟goes on ~~~