二叉树

二叉树包含以下域:key域,left域,right域,p域。key域存储实际的数据。left,right,p分别指向左儿子,右儿子和父节点。

二叉树中关键字的存储方式满足二叉查找树性质:

    x为二叉查找树中的一个节点。如果yx的左子树中的一个节点,则key[y]<=key[x];如果yx的右子树的一个节点,则key[x]<=key[y]

中序遍历树:

INORDER-TREE-WALK(root[T])

    INORDER-TREE-WALK(x):

     1  if x != NIL

     2   then INORDER-TREE-WALK(left[x])

     3            print key[x]

                   INORDER-TREE-WALK(right[x])

 

查找:

递归版:

TREE-SEARCH

    TREE-SEARCH(x,k)

    1  if x== NIL or k == key[x]

    2    then return x

    3  if k < key[x]

    4    then return TREE-SEARCH(left[x],k)

     5  else return TREE-SEARCH(right[x],k)

非递归版:

  ITERATIVE-TREE-SEARCH(x,k)

    1  while x != NIL and k != key[x]

    2    do if k < key[x]

    3        then x ← left[x]

    4      else  x ← right[x]

    5  return x

 

最小元素:

TREE-MINIMUM(x)

  1  while left[x] != NIL

  2    do  x ← left[x]

  3      return x

最大元素: 

TREE-MAXMUM(x)

  1  while right[x] != NIL

  2    do  x ← right[x]

  3  return x

 

前趋和后继:

  如果所有的关键字均不相同,则某节点x的后继即为具有大于key[x]中的关键字最小者的那个节点。前趋即为具有小于key[x]中的关键字最大的那个节点。

  后继:如果x的右子树非空,则x的后继即右子树中最左的节点;如果节点x的右子树为空,且x有一个后继y,则yx的最低祖先节点,且y的左儿子也是x的祖先。为找到y,可以从x开始向上查找,直到遇到某个是其父节点的左儿子的节点时为止。

后继:

TREE-SUCCESSOR(x)

1        if right[x] != NIL

2          then return TREE-MINIMUM(right[x])

3        y p[x]

4        while y != NIL and x == right[y]

5          do x y

6            y p[y]

7        return y

前趋:

TREE-PREDECESSOR(x)

1        if(left[x] != NIL)

2          then return TREE-MAXMUM(left[x])

3        y p[x]

4        while y != NIL and x == left[x]

5          do x y

6             y p[y]

7        return y

插入元素:

向树中插入节点z,设z节点具有如下属性:key[z] = v, left[z] = NIL, right[z] = NIL.

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    ;树为空

11    else if key[z] < key[y]

12      then left[y] z

13    else right[y] z

   从根节点开始,并沿树下降,指针x跟踪了下降路径,y始终指向x的父节点,根据key[z]key[x]的比较结果,可以决定向左或向右转。直到x成为NIL为止。这个NIL所占位置即我们想插入项z的地方。

 

删除元素:

  删除z节点的过程需要考虑3中情况:

  如果z节点没有子女,则修改其父节点p[z],使NIL成为其子女;

  如果z节点只有一个子女,则可以通过在其子节点与父节点间建立一条链来删除z

  如果z节点有2个子女,先删除z的后继y(y没有左子女),再用y的内容来替代z的内容。

 

TREE-DELETE(T,z)

1         if left[z] == NIL or right[z] == NIL

2           then y z

3         else y TREE-SUCCESSOR(z)

4         if left[y] != NIL

5           then x left[y]

6         else x right[y]

7         if x != NIL

8          then p[x] p[y]

9         if p[y] == NIL

10       then root[T] x

11     else if y == left[p[y]]

12       then left[p[y]] x

13     else right[p[y]] x

14     if y != z

15       then key[z] key[y]  ; copy y’s satellite data into z

16     return y

 

 binary_search_tree.h

#ifndef BINARY_SEARCH_TREE_H
#define BINARY_SEARCH_TREE_H

/*****************************************************************************

	二叉树中关键字的存储方式满足二叉查找树性质:

    	设x为二叉查找树中的一个节点。
    	如果y是x的左子树中的一个节点,则key[y]<=key[x];
    	如果y是x的右子树的一个节点,则key[x]<=key[y]。

*****************************************************************************/
typedef unsigned int item_t;
typedef unsigned int size_t;

typedef struct bst_node
{
	item_t		item;
	bst_node * parent;
	bst_node * left;
	bst_node * right;
}bst_node;

typedef struct binary_search_tree
{
	size_t	size;
	bst_node * root;
}binary_search_tree;


extern binary_search_tree *InitBinarySearchTree(void);
extern void MiddleOrderBinarySearchTree(bst_node *node);
extern bst_node * SearchNode(bst_node *start_node,  item_t & item );
extern bst_node * MinNode(bst_node *start_node);
extern bst_node * MaxNode(bst_node *start_node);
extern bst_node * SuccessorNode(bst_node *node);
extern bst_node * PresuccessorNode(bst_node *node);
extern int InsertNode(binary_search_tree * ptree, item_t & item);
extern int DeleteNode(binary_search_tree *ptree, item_t & item);
#endif


binary_search_tree.cpp

#include "stdafx.h"

#include "binary_search_tree.h"

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

// ============================================================================
//1 以下内容需要根据不同的item_t类型做修改
void print_item(item_t &item)
{
	printf(" %d\n", item);
}

/*****************************************************************************
 函 数 名  	: cmp_item
 功能描述  : 比较元素是否相等
 输入参数 	: iteml                
             itemr                
 输出参数	: 无
 返 回 值  	: 若iteml的元素小于itemr,则返回-1
 				  若iteml的元素等于itemr,则返回1
 				  若iteml的元素大于itemr,则返回1
 调用函数	: 
 被调函数	: 
 
 修改历史	:
  1.日    期   	: 2012年8月22日
    作    者   	: wkf72730
    修改内容 	: 新生成函数

*****************************************************************************/
int cmp_item(item_t &iteml, item_t &itemr)
{
	return iteml > itemr ? 1 : (iteml == itemr ? 0 : -1);
}

/*****************************************************************************
 函 数 名  : cpy_item
 功能描述  : 将源src_item复制到目的dest_item
 输入参数  : item_t &dest_item  
             item_t &src_item   
 输出参数  : 无
 返 回 值  : 
 调用函数  : 
 被调函数  : 
 
 修改历史      :
  1.日    期   : 2012年8月22日
    作    者   : wkf72730
    修改内容   : 新生成函数

*****************************************************************************/
void cpy_item(item_t &dest_item, item_t &src_item)
{
	dest_item = src_item;
} 


// ============================================================================
static void init_bst(binary_search_tree * ptree)
{
	ptree->root = NULL;
	ptree->size = 0;
}

/*****************************************************************************
 函 数 名  	: search_for_insert_node
 功能描述    : 查找item应插入节点的位置
 				  从根节点开始,并沿树下降,指针tmp_node跟踪了下降路径,
 				  而parent_node始终指向tmp_node的父节点,根据item与tmp_node->item的比较结果,
 				  可以决定向左或向右转。直到tmp_node成为NIL为止。
 				  这个NIL所占位置即我们想插入项z的地方。				  
 输入参数 	: *ptree               
             &item                 
 输出参数	: 无
 返 回 值  	: 若树为空或者树中已存在item节点,则返回NULL;
 				  否则返回插入节点的父节点
 
 调用函数	: 
 被调函数	: 
 
 修改历史	:
  1.日    期   	: 2012年8月24日
    作    者   	: wkf72730
    修改内容 	: 新生成函数

*****************************************************************************/
static bst_node * search_for_insert_node(binary_search_tree *ptree, item_t &item)
{
	bst_node * tmp_node = ptree->root;
	bst_node * parent_node = NULL;	// item节点的父节点
	int cmp_result = 0;

	while( tmp_node != NULL)
	{
		parent_node = tmp_node;

		cmp_result = cmp_item(item,tmp_node->item);
		switch(cmp_result)
		{
			case -1:		// 小于
				tmp_node = tmp_node->left;
				break;
			case 0:		// 等于
				return NULL;	// 已存在该节点,未插入
				break;
			case 1:		// 大于
				tmp_node = tmp_node->right;
				break;
			default:
				exit(0);
				break;
		}
	}

	return parent_node;	
}

static bst_node * malloc_node(item_t &item)
{
	bst_node * node = (bst_node *)malloc(sizeof(bst_node));
	if(node == NULL)
		exit(0);

	node->parent = NULL;
	node->left 	= NULL;
	node->right 	= NULL;
	cpy_item(node->item, item);
	return node;
}


// ============================================================================
//1 接口函数

binary_search_tree *InitBinarySearchTree(void)
{
	binary_search_tree *ptree = NULL;

	ptree = (binary_search_tree *)malloc(sizeof(binary_search_tree));
	if(NULL == ptree)
		exit(0);

	init_bst(ptree);

	return ptree;
	
}

void MiddleOrderBinarySearchTree(bst_node *node)
{
	if(node != NULL)
	{
		MiddleOrderBinarySearchTree(node->left);
		print_item(node->item);
		MiddleOrderBinarySearchTree(node->right);
	}
}

/*****************************************************************************
 函 数 名  	: SearchNode
 功能描述    : 查找元素是否在以start_node开始的子树中
 输入参数 	: *start_node                
                            item                       
 输出参数	: 无
 返 回 值  	: bst_node: 若未找到,则返回NULL,否则返回查找到的节点
 调用函数	: 
 被调函数	: 
 
 修改历史	:
  1.日    期   	: 2012年8月24日
    作    者   	: wkf72730
    修改内容 	: 新生成函数

*****************************************************************************/
bst_node * SearchNode(bst_node *start_node,  item_t &item )
{
	bst_node *tmp_node = start_node;
	
	while(tmp_node != NULL )
	{
		int cmp_result = cmp_item(item,tmp_node->item);

		if(cmp_result == 0)	// 相等
			break;
		else if(cmp_result == -1)	// 小于
			tmp_node = tmp_node->left;
		else					// 大于
			tmp_node = tmp_node->right;		
	}

	return tmp_node;
}


/*****************************************************************************
 函 数 名  	: MinNode
 功能描述  : 返回以start_node节点开始的子树中元素最小的节点
 输入参数 	: *start_node                
 输出参数	: 无
 返 回 值  	: bst_node
 调用函数	: 
 被调函数	: 
 
 修改历史	:
  1.日    期   	: 2012年8月24日
    作    者   	: wkf72730
    修改内容 	: 新生成函数

*****************************************************************************/
bst_node * MinNode(bst_node *start_node)
{
	bst_node * tmp_node = start_node;

	while(tmp_node->left != NULL)
	{
		tmp_node = tmp_node->left;
	}

	return tmp_node;
}

bst_node * MaxNode(bst_node *start_node)
{
	bst_node * tmp_node = start_node;

	while(tmp_node->right != NULL)
	{
		tmp_node = tmp_node->right;
	}

	return tmp_node;	
}


/*****************************************************************************
 函 数 名  	: SuccessorNode
 功能描述  : 计算节点的后继
 				 x节点的后继即为具有大于key[x]中的关键字最小者的那个节点。
 				 算法: 
 				 如果node的右子树非空,则x的后继即右子树中最左的节点;
 				 如果节点x的右子树为空,且x有一个后继y,则y是x的最低祖先节点,
 				 且y的左儿子也是x的祖先。为找到y,可以从x开始向上查找,
 				 直到遇到某个是其父节点的左儿子的节点时为止。
 输入参数 	: *node                
 输出参数	: 无
 返 回 值  	: bst_node
 调用函数	: 
 被调函数	: 
 
 修改历史	:
  1.日    期   	: 2012年8月22日
    作    者   	: wkf72730
    修改内容 	: 新生成函数

*****************************************************************************/
bst_node * SuccessorNode(bst_node *node)
{
	bst_node *tmp_node = node;

	if (tmp_node->right != NULL)
	{
		return MinNode(tmp_node->right);
	}

	bst_node * successor_node = tmp_node->parent;
	while((successor_node != NULL) && (tmp_node == successor_node->right))
	{
		tmp_node = successor_node;
		successor_node = tmp_node->parent;
	}

	return successor_node;
}

/*****************************************************************************
 函 数 名  	: PresuccessorNode
 功能描述  : 计算节点的前趋
 				 节点x的前趋: 小于key[x]中的关键字最大者的那个节点。
 输入参数 	: *pnode                
 输出参数	: 无
 返 回 值  	: bst_node
 调用函数	: 
 被调函数	: 
 
 修改历史	:
  1.日    期   	: 2012年8月22日
    作    者   	: wkf72730
    修改内容 	: 新生成函数

*****************************************************************************/
bst_node * PresuccessorNode(bst_node *node)
{
		bst_node *tmp_node = node;

	if (tmp_node->left != NULL)
	{
		return MaxNode(tmp_node->left);
	}

	bst_node * presuccessor_node = tmp_node->parent;
	while((presuccessor_node != NULL) && (tmp_node == presuccessor_node->left))
	{
		tmp_node = presuccessor_node;
		presuccessor_node = tmp_node->parent;
	}

	return presuccessor_node;	
}

/*****************************************************************************
 函 数 名  	: InsertNode
 功能描述    : 向树中插入节点
 输入参数 	: ptree                
             item                 
 输出参数	: 无
 返 回 值  	:  若树中已经存在item元素,则不插入并返回0;否则返回1 
 调用函数	: 
 被调函数	: 
 
 修改历史	:
  1.日    期   	: 2012年8月24日
    作    者   	: wkf72730
    修改内容 	: 新生成函数

*****************************************************************************/
int InsertNode(binary_search_tree * ptree, item_t & item)
{
	if(ptree->root == NULL)
	{
		bst_node *node = malloc_node(item);
		ptree->root = node;
		ptree->size += 1;
		return 1;	// 插入成功
	}
	else
	{
		bst_node *parent_node = search_for_insert_node(ptree, item);	
		if(parent_node == NULL)	
			return 0;			// 已存在该节点,返回0

		bst_node *insert_node = malloc_node(item);
		insert_node->parent = parent_node;
		if(-1 == cmp_item(item,parent_node->item))
		{
			parent_node->left = insert_node;
		}
		else
		{
			parent_node->right = insert_node;
		}
		ptree->size += 1;
		return 1;
	}
}


/*****************************************************************************
 函 数 名  	: DeleteNode
 功能描述  	: 删除元素为item的节点
 				   删除z节点的过程需要考虑3中情况:

  1. 如果z节点没有子女,则修改其父节点p[z],使NIL成为其子女;

  2.  如果z节点只有一个子女,则可以通过在其子节点与父节点间建立一条链来删除z;

  3. 如果z节点有2个子女,先删除z的后继y(y没有左子女),再用y的内容来替代z的内容。

 输入参数 	: *ptree                
             item                  
 输出参数	: 无
 返 回 值  	:  0: 删除失败,树为空或者树中不存在该元素;
 				   1: 删除成功
 调用函数	: 
 被调函数	: 
 
 修改历史	:
  1.日    期   	: 2012年8月24日
    作    者   	: wkf72730
    修改内容 	: 新生成函数

*****************************************************************************/
int DeleteNode(binary_search_tree *ptree, item_t & item)
{
	if(ptree->size == 0)	// 树为空,未找到该节点
		return 0;	

	bst_node * node = SearchNode(ptree->root, item);
	if(node == NULL)	// 不存在该节点
		return 0;

	bst_node *del_node = NULL;	// 要删除的节点
	if((node->left == NULL) || (node->right == NULL))		//情况 1,2
	{
		del_node = node;
	}
	else		// 情况3
	{
		del_node = SuccessorNode(node);
	}

	bst_node * tmp_node = NULL;	// 欲删除节点的子节点
	if(del_node->left != NULL)	// 后继没有左子女,对应情况3
	{
		tmp_node = del_node->left;
	}
	else		// 对应情况1,2
	{
		tmp_node = del_node->right;
	}

	if(tmp_node != NULL)	// 对应情况1,2	
	{
		tmp_node->parent = del_node->parent;
	}

	if(del_node->parent == NULL)
	{
		ptree->root = tmp_node;
	}
	else if(del_node == (del_node->parent)->left)
	{
		(del_node->parent)->left = tmp_node;
	}
	else
	{
		(del_node->parent)->right = tmp_node;
	}

	if(del_node != node)	// 情况3
	{
		cpy_item(node->item, del_node->item);
	}

	ptree->size--;
	free(del_node);	
	
	return 1;
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值