在写二叉搜索树的时候,<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;
}
程序输出: