《算法导论》学习总结——第三部分3二叉查找树

        查找树,也许是高级货,因为满足的性质蛮有型的,即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 ~~~


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值