(十一)二叉查找树

一颗忧伤的二叉查找树
在网上找了好久,也没有找到自己想要的二叉查找树实现。根据算法导论上的思路方法,写了一个c语言版的二叉查找树实现。
/*******************************************
二叉查找树,支持的操作包括:SERACH、MINIMUM、
MAXIMUM、PREDECESSOR、SUCCESSOR、INSERT、DELETE。
定理:对于一个高度为h的二叉查找树,操作SERACH、MINIMUM、
MAXIMUM、PREDECESSOR、SUCCESSOR的运行时间均为O(h)
*******************************************/

/*================JJ日记=====================
作者: JJDiaries(阿呆) 
邮箱:JJDiaries@gmail.com
日期: 2013-11-13
============================================*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORDLEN 16
//定义一个节点,除了存放key值外,还包含了一个data字符数组用于存放一个单词
struct node{
	int key;
	char data[WORDLEN];
	struct node *parent;
	struct node *left;
	struct node *right;
};
typedef struct node * tree;

/*============================================
树的中序遍历
INORDER_TREE_WALK(x)
	if x!=NIL
		then INORDER_TREE_WALK(left[x])
			 print key[x]
			 INORDER_TREE_WALK(left[x])
============================================*/	
void inorder_tree_walk(tree T)
{
	if(T!=NULL){
		inorder_tree_walk(T->left);
		printf("key:%d   words:%s\n",T->key,T->data);
		inorder_tree_walk(T->right);
	}
}


/*============================================
树的搜索,返回含有关键字k的结点
TREE_SEARCH(x,k) //递归版本
	if x=NIL or k =key[x]
		then return x
	if k<key[x]
		then return TREE_SEARCH(left[x],k)
		else return TREE_SEARCH(right[x],k)

TREE_SEARCH(x,k) //非递归版本
	while x!=NIL and k!= key[x]
		do if k<key[x]
			then x <—— left[x]
			else x <—— right[x]
	return x
============================================*/
//递归版本
struct node* tree_search(tree T,int k)
{
	if(T==NULL || k == T->key)
		return T;
	if(k < T->key)
		return tree_search(T->left,k);
	else 
		return tree_search(T->right,k);
}
//非递归版本
struct node* tree_search1(tree T,int k)
{
	while(T!=NULL && T->key!=k)
		if(k < T->key)
			T=T->left;
		else 
			T=T->right;
	return T;
}

/*============================================
返回key值最小的结点
TREE_MINIMUM(x)
	while left[x]!=NIL
		do x <—— left[x]
	return x
============================================*/	
struct node* tree_minimum(tree T)
{
	while(T->left != NULL)
		T=T->left;
	return T;
}

/*============================================
返回key值最大的结点
TREE_MAXMUM(x)
	while right[x]!=NIL
		do x <—— right[x]
	return x
============================================*/
struct node* tree_maxmum(tree T)
{
	while(T->right != NULL)
		T=T->right;
	return T;
}
/*============================================	
中序遍历下,返回某一结点的后继结点
1)如果结点x有右子结点,则其后继结点为右子树中最小结点。
2)如果结点x没有右子树,且x有一个后继y,则y是x的最低祖先结点
且y的左儿子也是x的祖先。
TREE_SUCCESSOR(x)
	if right[x] != NIL
		return TREE_MINIMUM(right[x])
	y=p[x]
	while y!=NIL and x=right[y] //如果x=left[y],那么x的后继就是y,跳出while循环,直接返回y即可
		do x <—— y
		   y <—— p[y]
	return y
============================================*/	
struct node * tree_successor(struct node *T)
{
	if(T->right!=NULL)
		return tree_minimum(T->right);
	struct node *y=T->parent;
	while(y!=NULL && T == y->right){
		T=y;
		y=y->parent;
	}
	return y;
}


/*===========================================
插入操作
思路:从根节点一路往下寻找插入位置,用指针x跟踪这条寻找路径,并用指针y指向x的父结点
TREE_INSERT(T,z)
	y=NIL
	x=root[T]
	while x!= NIL //直到x为空,这个空位置即为需要插入的位置
		do y<—— x
			if key[z]<key[x]
				then x <—— left[x]
				else x <—— right[x]
	p[z]=y
	if y=NIL
		then root[T]=z //树T为空时的情况
		else if key[z] < key[y]
			then left[y]=z //小于y的插在左边,大于的插在右边
			else right[y]=z
============================================*/	
void tree_insert(tree *PT,struct node *z)
{
	if(*PT==NULL){//树为空,则将z作为根结点返回
		*PT=z;
		return;
	}
	struct node *y=NULL;
	struct node *x=*PT;
	while(x!=NULL){
		y=x;
		if(z->key < x->key)
			x=x->left;
		else
			x=x->right;
	}
	z->parent=y;
	if(z->key < y->key)
		y->left=z;
	else
		y->right=z;
}

/*===============================================
删除操作
删除操作分为三类情况:
1)若要删除的节点z没有子女,则只需修改z的父节点的该子女为NIL即可
2)若要删除的节点z只有一个子女,则只需将z的这个子女与z的父节点连接起来即可
3)若要删除的节点z有两个子女,则需要先删除z的后继y,再用y的内容替换z的内容。
TREE_DELETE(T,z)
	if left[z]=NIL || right[z]=NIL  //把要删除的节点先保存在y中
		then y <—— z  
		else y <—— TREE_SUCCESSOR(z)
	if left[y]!=NIL             	//将y的非空子女存放在x中
		then X <—— left[y]
		else x <—— right[y]
	if x!=NIL 
		then p[x]=p[y]    //将要删除节点的子女连接到要删除节点的父节点上
	if p[y]=NIL     //如果要删除的节点为根节点
		then root[T] <—— x
		else if y=left[p[y]]//
			then left[p[y]] <—— x
			else right[p[y]] <—— x
	if y!=z  //第三种情况,需要用y的内容替换z的内容
		then key[z] <—— key[y]
			copy y's other data to z
	return y
==============================================*/
struct node * tree_delete(tree *PT,struct node *z)
{
	struct node *delnode,*sonnode;
	if(z->left==NULL || z->right == NULL)//有一个子女或无子女,则要删除的结点结尾z本身
		delnode=z;
	else                                 //有两个子女,则要删除的结点为z的后继结点
		delnode=tree_successor(z);

	if(delnode->left!=NULL)
		sonnode=delnode->left;
	else
		sonnode=delnode->right;
	
	if(sonnode!=NULL)
		sonnode->parent=delnode->parent;
	if(delnode->parent==NULL)
		*PT=sonnode;
	else if(delnode->parent->left==delnode)
		delnode->parent->left=sonnode;
	else
		delnode->parent->right=sonnode;
	if(delnode!=z){
		z->key=delnode->key;
		strcpy(z->data,delnode->data);
	}
	return delnode;
}
//初始化一棵树
tree init_tree(int key)
{	
	struct node * t;
	t=(tree)malloc(sizeof(struct node));
	if(t==NULL)
		return NULL;
	t->key=key;
	t->parent=t->left=t->right=NULL;
	return t;
}
//释放资源
void fini_tree(tree T)
{
	if(T!=NULL){
		fini_tree(T->left);
		fini_tree(T->right);
		printf("free node(%d,%s) now\n",T->key,T->data);
		free(T);
		
	}
}
//测试程序
int main()
{
	tree myTree=init_tree(256);
	if(myTree==NULL)
		return 1;
	strcpy(myTree->data,"JJDiaries");
	struct record{
	int key;
	char word[WORDLEN];
	};
	struct record records[]={ {2,"Viidiot"},
					 {4,"linux-code"},
					 {123,"google"},
					 {345,"baidu"},
					 {543,"nsfocus"}
					};
	int i;
	struct node *tmp;
	for(i=0;i<5;++i){
		tmp=(tree)malloc(sizeof(struct node));
		if(tmp==NULL)
			continue;
		tmp->key=records[i].key;
		strcpy(tmp->data,records[i].word);
		tmp->left=tmp->right=tmp->parent=NULL;
		tree_insert(&myTree,tmp);
	}
	inorder_tree_walk(myTree);
	struct node *del;
	del=tree_delete(&myTree,tree_search(myTree,345));
	printf("Delete node(%d,%s)\n",del->key,del->data);
	free(del);
	inorder_tree_walk(myTree);
	fini_tree(myTree);
}
==================================================
//程序运行结果:
jjdiaries@ubuntu>./search_tree
key:2   words:Viidiot
key:4   words:linux-code
key:123   words:google
key:256   words:JJDiaries
key:345   words:baidu
key:543   words:nsfocus
Delete node(345,baidu)
key:2   words:Viidiot
key:4   words:linux-code
key:123   words:google
key:256   words:JJDiaries
key:543   words:nsfocus
free node(123,google) now
free node(4,linux-code) now
free node(2,Viidiot) now
free node(543,nsfocus) now
free node(256,JJDiaries) now
===================================================


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值