数据结构中的二叉搜索树

文章转载自http://www.cnblogs.com/xpjiang/p/4569591.html

什么是二叉搜索树

二叉 搜索树(BST,Binary Search Tree),也称二叉排序树或二叉查找树:一颗二叉树,可以为空;如果不为空,满足以下性质:

  • 非空左子树的所有键值小于其根结点的键值
  • 非空右子树的所有键值大于其根结点的键值
  • 左、右子树都是二叉搜索树
  • 没有键值相等的节点
二叉查找树相比于其他数据结构的优势在于查找、插入的时间复杂度较低。为O(log n)。二叉查找树是基础性数据结构,用于构建更为抽象的数据结构,如集合、multiset、关联数组等。
以下代码是二叉搜索树的构建
#include<iostream>
#include<stack>
#include<vector>
using namespace std;

typedef struct Bin_Tree
{
	int value;
	BinTree* right;
	BinTree* left;
} BinTree;

//构造二叉搜索树
BinTree* InsertNode(BinTree* root, int value)
{
	BinTree* newnode = new BinTree;
	newnode->value = value;
	newnode->right = NULL;
	newnode->left = NULL;
	if (root == NULL)
		root = newnode;
	else
	{
		//找合适的位置
		BinTree* parent = root;
		while (parent != NULL)
		{
			if (value > parent->value)
			{
				if (parent->right == NULL)
					break;
				else
					parent = parent->right;
			}
			else
			{
				if (parent->left == NULL)
					break;
				else
					parent = parent->left;
			}

		}
		if (parent->value < value)
			parent->right = newnode;
		else
			parent->left = newnode;
	}

	return root;

}

int main()
{
	BinTree* root = NULL;
	int array[] = { 10, 6, 14, 4, 8, 12, 16 };
	for (int i = 0; i < sizeof(array) / sizeof(int); i++)
		root = InsertNode(root, array[i]);
}

下面的代码是将有序数组构建成二叉搜索树
/*将有序数组插入到BST中*/
void InsertFromArray(BinTree*& root, int* array, int start, int end)
{
	if (start > end)
		return;
	//初始化一个节点
	root = new BinTree;
	root->left = NULL;
	root->right = NULL;
	//找到有序数组的中间节点作为根节点
	int mid = start + (end - start) / 2;
	root->value = array[mid];
	//然后递归调用创建左子树和右子树
	InsertFromArray(root->left, array, start, mid - 1);
	InsertFromArray(root->right, array, mid + 1, end);

}
//如果采用中序遍历对二叉搜索树进行 遍历的话,得到的将是有序序列
void Inorder(BinTree* root)
{
	if (root == NULL)
		return;
	Inorder(root->left);
	cout << root->value << endl;
	Inorder(root->right);
}

int main()
{
	int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	BinTree* root = NULL;
	InsertFromArray(root, array, 0, 8);
	Inorder(root);
	return 0;

}



二叉搜索树操作的特别函数

  • Postion Find(ElementType X, BinTree BST):从二叉搜索树BST中查找元素X,返回其所在结点的地址
  • Postion FindMin(BinTree BST):从二叉搜索树BST中查找并返回最小元素所在结点的地址
  • Position FindMax(BinTree BST):从二叉搜索树BST中查找并返回最大元素所在结点的地址
  • BinTree Insert(ElementType X, BinTree BST)
  • BinTree Delete(ElementType X, BinTree BST)
二叉搜索树的查找操作:Find
  • 查找从根结点开始,如果树为空,返回NULL
  • 搜索树非空,则根结点关键字和X进行比较,并进行不同处理:

若X小于根结点键值,只需在左子树中继续搜索

若X大于根结点的键值,在右子树中继续进行搜索

若两者比较结果相等,搜索完成,返回指向此结点的指针

Positon Find(ElementType X, BinTree BST)
{
    if(!BST)
        return NULL; // 查找失败
    if(X > BST->Data)
        return Find(X, BST->Right); // 在右子树中继续查找
    else if
        return Find(X, BST->Left); // 在左子树中继续查找
    else // X == BST->Data
        return BST; // 查找成功,返回结点的地址
}

上面程序中的两处递归调用都是尾递归,因此可以方便的改写为迭代函数,以便提高执行效率(注意到,查找的效率取决于树的高度)

Position IterFind(ElementType X, BinTree BST)
{
    while(BST)
    {
        if(X > BST->Data)
            BST = BST->Right; // 向右子树中移动,继续查找
        else if(X < BST->Data)
            BST = BST->Left; // 向左子树中移动,继续查找
        else // X == BST->Data
            return BST; // 查找成功,返回结点的地址
    }
    return NULL; // 查找失败
}

查找最大和最小元素

  只需注意到以下事实:

  • 最大元素一定在树的最右分支的端结点上
  • 最小元素一定在树的最左分支的端节点上
查找最小元素的递归函数
Postion FindMin(BinTree BST)
{
    if(!BST)
        return NULL; // 空的二叉搜索树,返回NULL
    else if(!BST->Left)
        return BST; // 找到最左叶结点并返回
    else
        return FindMin(BST->Left); // 沿左分支继续查找
}
查找最大元素的迭代函数
Position FindMax(BinTree BST)
{
    if(BST)
        while(BST->Right)
            BST = BST->Right; // 沿右分支继续查找,直到最右结点
    return BST;
}

二叉搜索树的插入

  关键是要找到元素应该插入的位置,可以采用与Find类似的方法

BinTree Insert(ElementType X, BinTree BST)
{
    if(!BST)
    {
        // 若原树为空,生成并返回一个结点的二叉搜索树
        BST = malloc(sizeof(struct TreeNode));
        BST->Data = X;
        BST->Left = BST->Right = NULL;
    }
    else // 开始找要插入元素的位置
    {
        if(X < BST->Data)
            BST->Left = Insert(X, BST->Left); // 递归插入左子树
        else if(X > BST->Data)
            BST->Right = Insert(X, BST->Right); // 递归插入右子树
        // else X已经存在,什么都不做
    }
    return BST;
}

关于上面的代码,多说一点,就是关于递归调用返回的时候需要赋值给左子树或右子树,这在大多数赋值的情况下显得多余(就像是说,把当前树的左子树赋值给它的左子树),但是它是必须的,因为在插入元素的时候我们需要知道它的父结点的左指针或右指针。我们也可以消除不必要的赋值,但是它是以增加逻辑判断为代价的,还不如原先的方式显得清晰、美观。

二叉搜索树的删除

  要考虑三种情况

  • 要删除的是叶节点:直接删除,并再修改其父结点指针,置为NULL
  • 删除的结点只有一个孩子结点:将其父结点的指针指向要删除结点的孩子结点
  • 删除的结点有左、右两颗子树:用另一结点替代被删除结点:右子树的最小元素或者左子树的最大元素
BinTree Delete(ElementType X, BinTree BST)
{
    Position Tmp;
    if(!BST)
        printf("要删除的元素未找到");
    else if(X < BST->Data)
        BST->Left = Delete(X, BST->Left); // 左子树递归删除
    else if(X > BST->Data)
        BST->Right = Delete(X, BST->Right); // 右子树递归删除
    else // 找到要删除的结点
    {
        if(BST->Left && BST->Right) // 被删除结点有左右两个子结点
        {
            Tmp = FindMin(BST->Right); // 在右子树中找最小的元素填充删除结点
            BST->Data = Tmp->Data;
            BST->Right = Delete(BST->Data, BST->Right); // 在删除结点的右子树中删除最小元素
        }
        else // 被删除结点有一个或无子结点
        {
            Tmp = BST;
            if(!BST->Left) // 有右孩子或无子结点
                BST = BST->Right;
            else if(!BST->Right) // 有左孩子或无子结点
                BST = BST->Left;
            free(Tmp);
        }
    }
    return BST;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值