二叉树包含以下域:key域,left域,right域,p域。key域存储实际的数据。left,right,p分别指向左儿子,右儿子和父节点。
二叉树中关键字的存储方式满足二叉查找树性质:
设x为二叉查找树中的一个节点。如果y是x的左子树中的一个节点,则key[y]<=key[x];如果y是x的右子树的一个节点,则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,则y是x的最低祖先节点,且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;
}