算法导论--第十二章:二叉搜索树

本文详细介绍了二叉搜索树的基本操作实现,包括插入、查找、删除等,并提供了递归版本的插入方法及一种处理重复关键字的方法。此外,还探讨了二叉树的数组表示和随机构建。

在写二叉搜索树的时候,<C和指针>一书提供了一个思想就是:把根节点的地址传递进去,即Tree **tree这样的写法.这样才可以保证书被修改(在插入和删除的时候),但是这种写法让程序变得异常的难懂(我当时花了很多的时间,就是为了写这一个指向指针的指针的二叉树).在看算法导论的时候,发现了一种方法是:你可以用一个节点指向根节点,然后把这个节点初始化后传递进去即可.初次实现如下:

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>

//二叉搜索树
typedef struct TREE{
	struct TREE *lchild;
	struct TREE *rchild;
	int			data;
} Tree;

//用来指向搜索树的根节点
typedef struct NODE{
	struct TREE *next;
} Node;

//此二叉树不允许重复节点,因为如何进行重复,那么进行删除的时候,则会造成混乱
void insert_tree( Node *node, int value )
{
	Tree *tree = ( Tree * )malloc( sizeof( Tree ) );
	tree->lchild = NULL;
	tree->rchild = NULL;
	tree->data = value;
	if ( NULL == node->next ){
		node->next = tree;
	}
	else{
		Tree *root = ( Tree * )malloc( sizeof( Tree ) );
		Tree *parent = ( Tree * )malloc( sizeof( Tree ) );
		root = node->next;
		while ( NULL != root ){
			parent = root;
			if ( value == root->data ){
				printf("the value has in the tree.\n");
				return;
			}
			else if ( value < root->data ){
				root = root->lchild;
			}
			else{
				root = root->rchild;
			}
		}
		if ( value < parent->data ){
			parent->lchild = tree;
		}
		else{
			parent->rchild = tree;
		}
	}
}

int search_tree( Node *node, int value )
{
	if ( NULL == node->next ){
		printf("empty tree\n");
	}
	else{
		Tree *root = ( Tree * )malloc( sizeof( Tree ) );
		root = node->next;
		while ( NULL != root ){
			if ( value == root->data ){
				return 1;
			}
			else if ( value < root->data ){
				root = root->lchild;
			}
			else{
				root = root->rchild;
			}
		}
	}

	return 0;
}

//前序打印
void pre_print( Tree *tree )
{
	if ( NULL != tree ){
		printf("%d-->", tree->data );
		pre_print( tree->lchild );
		pre_print( tree->rchild );
	}
}

//中序打印
void mid_print( Tree *tree )
{
	if ( NULL != tree ){
		mid_print( tree->lchild );
		printf("%d-->", tree->data );
		mid_print( tree->rchild );
	}
}

//后序打印
void tail_print( Tree *tree )
{
	if ( NULL != tree ){
		tail_print( tree->lchild );
		tail_print( tree->rchild );
		printf("%d-->", tree->data );
	}
}

//书的最小值
int tree_minimum( Node *node )
{
	Tree *root = ( Tree * )malloc( sizeof( Tree ) );
	if ( NULL == node->next ){
		printf("empty tree\n");
		return INT_MIN;
	}
	root = node->next;
	while ( NULL != root->lchild ){
		root = root->lchild;
	}

	return root->data;
}

//树的最大值
int tree_maximum( Node *node )
{
	Tree *root = ( Tree * )malloc( sizeof( Tree ) );
	if ( NULL == node->next ){
		printf("empty tree\n");
		return INT_MIN;
	}
	root = node->next;
	while ( NULL != root->rchild ){
		root = root->rchild;
	}

	return root->data;
}

//寻找值为value的后继结点,但并不保证value在树中....
int tree_successor( Node *node, int value )
{
	Tree *root = ( Tree * )malloc( sizeof( Tree ) );
	Tree *rnode = ( Tree * )malloc( sizeof( Tree ) );
	int result = value;
	if ( NULL == node->next ){
		printf("empty tree\n");
		return INT_MIN;
	}
	root = node->next;
	while ( NULL != root ){
		if ( value > root->data ){
			root = root->rchild;
			continue;
		}
		else if ( value < root->data ){
			result = root->data;
			root = root->lchild;
			continue;
		}
		else{
			rnode = root->rchild;
			while ( NULL != rnode ){
				result = rnode->data;
				rnode = rnode->lchild;
			}
			break;
		}
	}

	return result;
}

//寻找值为value的前驱结点,但并不保证value在树中....
int tree_predecessor( Node *node, int value )
{
	Tree *root = ( Tree * )malloc( sizeof( Tree ) );
	Tree *lnode = ( Tree * )malloc( sizeof( Tree ) );

	int result = value;
	if ( NULL == node->next ){
		printf("empty tree\n");
		return INT_MIN;
	}
	
	root = node->next;
	while ( NULL != root ){
		if ( value < root->data ){
			root = root->lchild;
			continue;
		}
		else if ( value > root->data ){
			result = root->data;
			root = root->rchild;
		}
		else{
			lnode = root->lchild;
			while ( NULL != lnode ){
				result = lnode->data;
				lnode = lnode->rchild;
			}
			break;
		}
	}

	return result;
}

int main( void )
{
	int i = 0;
	Node *node = ( Node * )malloc( sizeof( Node ) );
	node->next = NULL;

	for ( i = 5; i > 0; i-- ){
		insert_tree( node, i );
	}
	for ( i = 6; i <10; i++ ){
		insert_tree( node, i );
	}

	mid_print( node->next );
	printf("\n");

	if ( search_tree( node, 5 ) ){
		printf("we find it\n");
	}
	else{
		printf("we do not find it\n");
	}
	printf("the minimum number is:%d\n", tree_minimum( node ) );
	printf("the maximum number is:%d\n", tree_maximum( node ) );
	printf("the pre number of 4 is:%d", tree_predecessor( node, 4 ) );
	printf("the next number of 4 is:%d", tree_successor( node, 4 ) );

	return 0;
}
程序输出:

进一步优化如下(增加删除节点和部分代码优化):

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>

//二叉搜索树
typedef struct TREE{
	struct TREE *lchild;
	struct TREE *rchild;
	int			data;
} Tree;

//用来指向搜索树的根节点
typedef struct NODE{
	struct TREE *next;
} Node;

void insert_tree( Node *node, int value )
{
	Tree *newtree = ( Tree * )malloc( sizeof( Tree ) );
	newtree->lchild = NULL;
	newtree->rchild = NULL;
	newtree->data = value;
	if ( NULL == node->next ){
		node->next = newtree;
	}
	else{
		Tree *root = ( Tree * )malloc( sizeof( Tree ) );		//树的根节点
		Tree *parent = ( Tree * )malloc( sizeof( Tree ) );
		root = node->next;

		while ( NULL != root ){
			parent = root;
			if ( value == root->data ){
				printf("the value has in the tree\n");
				free( newtree );
				return;
			}
			else if ( value < root->data ){
				root = root->lchild;
			}
			else{
				root = root->rchild;
			}
		}
		if ( value < parent->data ){
			parent->lchild = newtree;
		}
		else{
			parent->rchild = newtree;
		}
	}
}


int search_tree( Tree *tree, int value )
{
	while ( NULL != tree ){
		if ( value == tree->data ){
			return 1;
		}
		else if ( value < tree->data ){
			tree = tree->lchild;
		}
		else{
			tree = tree->rchild;
		}
	}

	return 0;
}

void pre_print( Tree *tree )
{
	if ( NULL != tree ){
		printf("%d-->", tree->data );
		pre_print( tree->lchild );
		pre_print( tree->rchild );
	}
}

void mid_print( Tree *tree )
{
	if ( NULL != tree ){
		mid_print( tree->lchild );
		printf("%d-->", tree->data );
		mid_print( tree->rchild );
	}
}

void tail_print( Tree *tree )
{
	if ( NULL != tree ){
		tail_print( tree->lchild );
		tail_print( tree->rchild );
		printf("%d-->", tree->data );
	}
}

//这部分代码存在重复,需要进行优化
int delete_tree( Node *node, int value )
{
	Tree *tree = ( Tree * )malloc( sizeof( Tree ) );
	Tree *parent = ( Tree * )malloc( sizeof( Tree ) );
	parent = NULL;
	tree = node->next;
	while ( NULL != tree && value != tree->data ){
		parent = tree;
		if ( value < tree->data ){
			tree = tree->lchild;
		}
		else{
			tree = tree->rchild;
		}
	}
	if ( NULL == tree ){		//没找到删除的节点
		return 0;
	}

	//说明删除的是头节点,需要进行特殊处理
	if ( NULL == parent ){
		if ( NULL == tree->lchild ){
			node->next = tree->rchild;
		}
		else if ( NULL == tree->rchild ){
			node->next = tree->lchild;
		}
		else{
			Tree *newnode = ( Tree * )malloc( sizeof( Tree ) );
			Tree *newnodeParent = ( Tree * )malloc( sizeof( Tree ) );
			newnodeParent = tree;
			newnode = tree->rchild;
			while ( NULL != newnode->lchild ){
				newnodeParent = newnode;
				newnode = newnode->lchild;
			}
			newnodeParent->rchild = newnode->rchild;
			node->next->data = newnode->data;
			free( newnode );
		}
	}
	//这里不确定删除的节点是左节点还是右节点,故进行分类--但是造成重复的代码,不知道如何优化
	else if ( parent->lchild->data == tree->data && value == tree->data ){
		if ( NULL == tree->lchild ){
			parent->lchild = tree->rchild;
		}
		else if ( NULL == tree->rchild ){
			parent->lchild = tree->lchild;
		}
		else{
			Tree *newnode = ( Tree * )malloc( sizeof( Tree ) );
			Tree *newnodeParent = ( Tree * )malloc( sizeof( Tree ) );
			newnodeParent = tree;
			newnode = tree->rchild;
			while ( NULL != newnode->lchild ){
				newnodeParent = newnode;
				newnode = newnode->lchild;
			}
			newnodeParent->rchild = newnode->rchild;
			parent->lchild->data = newnode->data;
			free( newnode );
		}
	}
	else if ( parent->rchild->data == tree->data && value == tree->data ){
		if ( NULL == tree->lchild ){
			parent->rchild = tree->rchild;
		}
		else if ( NULL == tree->rchild ){
			parent->rchild = tree->lchild;
		}
		else{
			Tree *newnode = ( Tree * )malloc( sizeof( Tree ) );
			Tree *newnodeParent = ( Tree * )malloc( sizeof( Tree ) );
			newnodeParent = tree;
			newnode = tree->rchild;
			while ( NULL != newnode->lchild ){
				newnodeParent = newnode;
				newnode = newnodeParent->lchild;
			}
			newnodeParent->rchild = newnode->rchild;
			parent->rchild->data = newnode->data;
			free( newnode );
		}
	}

	return 1;
}

int main( void )
{
	int i = 0;
	Node *node = ( Node * )malloc( sizeof( Node ) );
	node->next = NULL;

	for ( i = 5; i > 0; i-- ){
		insert_tree( node, i );
	}
	for ( i = 6; i < 10; i++ ){
		insert_tree( node, i );
	}

	mid_print( node->next );
	printf("\n");

	if ( search_tree( node->next, 5 ) ){
		printf("we find the number 5\n");
	}
	else{
		printf("we do not find the number 5\n");
	}

	if ( delete_tree( node, 5 ) ){
		printf("we delete node 5\n");
		mid_print( node->next );
	}
	else{
		printf("5 not in tree\n");
	}

	return 0;
}
程序输出:

下面习题的算法均通过根节点指针来完成:

12.3-1:递归版本的tree_insert:

备注:参考<the c programming language>:

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>

//二叉搜索树
typedef struct TREE{
	struct TREE *lchild;
	struct TREE *rchild;
	int			data;
} Tree;

Tree *insert_tree( Tree *tree, int value )
{
	if ( NULL == tree ){
		Tree *newtree = ( Tree * )malloc( sizeof( Tree ) );
		newtree->lchild = NULL;
		newtree->rchild = NULL;
		newtree->data = value;
		tree = newtree;
	}
	else if ( value == tree->data ){
		return tree;
	}
	else if ( value < tree->data ){
		tree->lchild = insert_tree( tree->lchild, value );
	}
	else{
		tree->rchild = insert_tree( tree->rchild, value );
	}

	return tree;
}

void mid_print( Tree *tree )
{
	if ( NULL != tree ){
		mid_print( tree->lchild );
		printf("%d-->", tree->data );
		mid_print( tree->rchild );
	}
}


int main( void )
{
	int i = 0;
	Tree *tree = ( Tree * )malloc( sizeof( Tree ) );
	tree = NULL;

	for ( i = 5; i > 0; i-- ){
		tree = insert_tree( tree, i );
	}
	for ( i = 6; i < 10; i++ ){
		tree = insert_tree( tree, i );
	}

	mid_print( tree );
	return 0;
}
程序输出:

我表示对12.4节:随机构建二叉搜索树 完全看不懂,要找段时间补数学基础.

12.1:具有相同关键字二叉搜索树的实现:

设置一个标量flag来控制相同关键值的方向即可:

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>

//二叉搜索树
typedef struct TREE{
	struct TREE *lchild;
	struct TREE *rchild;
	int			flag;
	int			data;
} Tree;

Tree *insert_tree( Tree *tree, int value )
{
	if ( NULL == tree ){
		Tree *newtree = ( Tree * )malloc( sizeof( Tree ) );
		newtree->lchild = NULL;
		newtree->rchild = NULL;
		newtree->flag = 0;
		newtree->data = value;
		tree = newtree;
	}
	else if ( value == tree->data ){
		if ( tree->flag ){
			tree->flag = 0;
			tree->rchild = insert_tree( tree->rchild, value );
		}
		else{
			tree->flag = 1;
			tree->lchild = insert_tree( tree->lchild, value );
		}
	}
	else if ( value < tree->data ){
		tree->lchild = insert_tree( tree->lchild, value );
	}
	else{
		tree->rchild = insert_tree( tree->rchild, value );
	}

	return tree;
}

void mid_print( Tree *tree )
{
	if ( NULL != tree ){
		mid_print( tree->lchild );
		printf("%d-->", tree->data );
		mid_print( tree->rchild );
	}
}


int main( void )
{
	int i = 0;
	Tree *tree = ( Tree * )malloc( sizeof( Tree ) );
	tree = NULL;

	for ( i = 5; i > 0; i-- ){
		tree = insert_tree( tree, i );
	}
	for ( i = 0; i < 10; i++ ){
		tree = insert_tree( tree, i );
	}

	mid_print( tree );
	printf("NULL\n");
	return 0;
}
程序输出:

12.2 基数数

就是读取节点,从左节点向右读取,然后逐层递归读取....

这里可以用到数组:假设头节点的数组索引为i,则孩子左节点为2 * i,右孩子节点为2 * i + 1.我们只要把对应的值填入即可:缺点是极可能浪费空间

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>

//二叉搜索树
typedef struct TREE{
	struct TREE *lchild;
	struct TREE *rchild;
	int			flag;
	int			data;
} Tree;

Tree *insert_tree( Tree *tree, int value )
{
	if ( NULL == tree ){
		Tree *newtree = ( Tree * )malloc( sizeof( Tree ) );
		newtree->lchild = NULL;
		newtree->rchild = NULL;
		newtree->flag = 0;
		newtree->data = value;
		tree = newtree;
	}
	else if ( value == tree->data ){
		return tree;
	}
	else if ( value < tree->data ){
		tree->lchild = insert_tree( tree->lchild, value );
	}
	else{
		tree->rchild = insert_tree( tree->rchild, value );
	}

	return tree;
}

void mid_print( Tree *tree )
{
	if ( NULL != tree ){
		mid_print( tree->lchild );
		printf("%d-->", tree->data );
		mid_print( tree->rchild );
	}
}

void child_print( Tree *tree, int arr[], int i, int j )
{
	if ( NULL != tree ){
		child_print( tree->lchild, arr, i * 2, j );
		arr[ i ] = tree->data;
		child_print( tree->rchild, arr, j * 2 + 1, j * 2 + 1 );
	}
}


int main( void )
{
	int i = 0;
	int arr[ 100 ];
	Tree *tree = ( Tree * )malloc( sizeof( Tree ) );
	tree = NULL;

	memset( arr, -1, sizeof( int ) * 100 );

	for ( i = 5; i > 0; i-- ){
		tree = insert_tree( tree, i );
	}
	for ( i = 6; i < 10; i++ ){
		tree = insert_tree( tree, i );
	}

	child_print( tree, arr, 1, 1 );
	for ( i = 0; i < 100; i++ ){
		if ( -1 != arr[ i ] ){
			printf("%d-->", arr[ i ] );
		}
	}
	printf("\n");
	return 0;
}
程序输出:


转载于:https://my.oschina.net/voler/blog/169815

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值