【数据结构】二叉查找树

1.概念:

二叉查找树也叫二叉搜索树,是一棵空树或者是具有一下性质的一颗二叉树

a.每个节点都有一个作为搜索依据的关键码(key),而且所有的关键码的取值都互不相同。

b.每个左子树(如果存在)所有节点的关键码都小于根节点的关键码。

c.每个右子树(如果存在)所有节点的关键码都大于根节点的关键码。

d.每个左子树和右子树也均为二叉搜索树。

需要说明的是,关键码事实上是节点所保存元素中的某个域的值,它能够唯一的表示这个结点,因此,如果对一颗二叉搜索树进行中序遍历,就可以按照从小到大的顺序将各个结点的关键排列起来,因此二叉搜索树也被称为二叉排序树。

2.二叉搜索树相关的算法:

a.搜索算法:

在二叉搜索树上进行搜索,过程是从一个根节点开始,沿着某一个分支逐层向下进行比较判别的过程,这个过程可以是一个递归的过程,也可以是一个迭代的过程。因为通常使用递归的方法来定义二叉树类,因此搜索算法通常也使用递归的思想来编写。主要过程如下:

假设想要在二叉搜索树中搜索关键码为x的元素,搜索过程从根节点开始,如果根结点为nullptr(空指针),则直接返回搜索失败,否则用给定的值x与根结点的关键码相比较,如果给定的值等于根结点的关键码中的值,则返回搜索成功的信息,并提交搜索到的结点地址。如果给定值小于根结点的关键码,则继续递归搜索根结点的左子树,窦泽,进行递归搜索根结点的右子树。

b.插入算法:

向二叉搜索树中插入一个元素,必须先检查这个元素在已有的树中是否已经存在。所以 在进行插入之前,可以先使用搜索算法在树中检查准备要插入的元素是否存在。如果返回搜索成功的信息,说明在这棵二叉搜索树中已有这个元素,就不再进行插入操作。否则,说明在树中没有要插入的这个元素。再把新元素添加到搜索操作停止的地方。在将要插入的元素与搜索操作返回的地址的关键码相比较。如果小于,则插入为左子树,否则成为右子树。

在插入过程中需要注意,每次的结点的插入,都要从根结点出发先搜索插入的位置,然后把新结点作为叶结点插入,这样不需要移动结点,只需要修改某个已有树中结点的空指针即可。

c.二叉搜索树的删除

在二叉搜索树中删除一个结点时,必须将因删除结点而断开的二叉链表重新连接起来,同时又要确保二叉搜索树的性质不丢失。此外,为了保证在删除结点后树的搜索性能不至于降低,还需要防止重新连接后输的高度不能增加。因此,删除算法需要分为几种情况进行讨论。

(1).如果想要删除叶结点,只需将父结点指向它的指针进行清零操作即可,在释放掉这个结点即可。

(2).如果被删除的结点右子树为空,则可以用它的左子女结点代替它的位置,再释放掉这个结点;若被删除结点左子树为空,则可以用它的右子女结点代替它的位置,再释放掉这个结点即可。

(3)如果被删除结点的左右子树都不为空,则可以在它的右子树下寻找中序下的第一个结点(关键码最小),用它的值填补到被删除的结点中,再来处理这个结点的删除问题。

同样的,这也是一个递归处理的过程。之后进行递归删除即可。

相关实现程序如下

二叉搜索树的头文件:

/
//  BST.h
//  BinarySearchTree
//
//  Created by 大幕 on 2017/3/2.
//  Copyright © 2017年 Damu. All rights reserved.
//

//  构建一颗二叉查找树并进行使用
//  特点,每一个元素有一个键值,左子树比根节点小,右子树比根节点大,且左右子树都是二叉查找树


#ifndef BST_h
#define BST_h

#include <iostream>

enum Boolean { FALSE, TRUE };      //定义自己的布尔类型

//使用C++的模板类来设计二叉查找树

template <class Type>
class Element
{
public:
	Type key;
	//可以很容易的添加更多的数据
};

template<class Type> class BST;     //声明类

template <class Type>
class BstNode      //二叉查找树的结点类
{
	friend class BST<Type>;     //定义为友元类,方便操作BstNode的私有成员
public:
	Element<Type> data;
	BstNode * LeftChild;
	BstNode * RightChild;
	void display(int i);
};

template <class Type>
class BST
{
public:
	BST(BstNode<Type> *init = 0)
	{
		root = init;
	}
	Boolean Insert(const Element<Type>& x);     //插入结点操作
	Boolean Remove(BstNode<Type> * ptr, const Element<Type>& x);     //删除以ptr为根结点,关键码为x的结点
	Boolean Remove(const Element<Type>& x);     //配合上一个函数实现删除操作
	BstNode<Type>* Search(const Element<Type>& x);     //使用递归的方法进行查找
	BstNode<Type>* Search(BstNode<Type> *, const Element<Type> &);     //重载函数进行查找
	BstNode<Type>* IterSearch(const Element<Type>&);   //使用迭代进行查找
	void display()
	{
		std::cout << '\n';
		if (root)
			root->display(1);
		else
			std::cout << "这是一颗空树\n";
	}
private:
	BstNode<Type> *root;

};

template <class Type>
void BstNode<Type>::display(int i)
{
	//用来显示当前节点的数据以及它所有的左子树和右子树的数据,利用递归的方法
	std::cout << "Position: " << i << ": data.key = " << data.key << '\n'; //先显示位置,再显示数据
	if (LeftChild)
		LeftChild->display(2 * i);      //递归左子树
	if (RightChild)
		RightChild->display(2 * i + 1);   //递归右子树
}

template <class Type>
Boolean BST<Type>::Insert(const Element<Type> &x)
{
	BstNode<Type> *p = root;
	BstNode<Type> *q = 0;       //q指向p的父节点
	//insert之前需要先进行查找,找到合适的位置进行插入
	while (p)
	{
		q = p;      //在每次改变之前使用q将p进行保留下来
		if (x.key == p->data.key)
			return FALSE;       //发生重复,插入失败
		if (x.key < p->data.key)
			p = p->LeftChild;
		else
			p = p->RightChild;
	}
	//循环结束后,找到了位置q
	p = new BstNode<Type>;
	p->LeftChild = nullptr;
	p->RightChild = nullptr;
	p->data = x;
	if (!root)
		root = p;
	else if (x.key < q->data.key)
		q->LeftChild = p;
	else
		q->RightChild = p;
	return TRUE;        //表示插入成功
}

//删除以ptr为根结点,关键码为x的结点
template<class Type>
Boolean BST<Type>::Remove(BstNode<Type> * ptr, const Element<Type>& x)
{
	BstNode<Type> *temp = nullptr;
	ptr = root;
	if (ptr != nullptr)
	{
		if (x.key < ptr->data.key)
			Remove(ptr->LeftChild, x);       //在左子树中执行删除
		else if (x.key > ptr->data.key)
			Remove(ptr->RightChild, x);      //在右子树中执行删除
		else if (ptr->LeftChild != nullptr && ptr->RightChild != nullptr)
		{
			//ptr指到了关键码为x的结点,而且这个结点有两个子女
			temp = ptr->RightChild;     //找到右子树搜寻中序下的第一个结点
			while (temp->LeftChild != nullptr)
				temp = temp->LeftChild;
			ptr->data.key = temp->data.key;     //使用temp中数据代替此时ptr结点中的数据
			Remove(ptr->RightChild, ptr->data);  //递归删除右子树中的temp结点
		}
		else
		{
			//ptr也指到了关键码为x的结点,但是它只有1个或0个子女
			temp = ptr;
			if (ptr->LeftChild == nullptr)
				ptr = ptr->RightChild;
			else
				ptr = ptr->LeftChild;
			delete temp;
			return TRUE;

		}

	}
	return FALSE;
}

//删除函数
template <class Type>
Boolean BST<Type>::Remove(const Element<Type> &x)
{
	return Remove(root, x);
}


//搜索函数
template <class Type>
BstNode<Type> *BST<Type>::Search(const Element<Type> &x)
{
	return Search(root, x);
}

template<class Type>
BstNode<Type> * BST<Type>::Search(BstNode<Type> *b, const Element<Type>& x)
{
	//从节点b开始找数值为x的结点
	if (!b)
		return 0;
	if (x.key == b->data.key)
		return b;
	if (x.key < b->data.key)
		return Search(b->LeftChild, x);
	return Search(b->RightChild, x);
}

//迭代的查找方法
template<class Type>
BstNode<Type>* BST<Type>::IterSearch(const Element<Type> &x)
{
	for (BstNode<Type> *t = root; t;)
	{
		if (x.key == t->data.key)
			return t;
		if (x.key < t->data.key)
			t = t->LeftChild;
		else
			t = t->RightChild;
	}
	return 0;
}

#endif /* BST_h */

    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/qq_34784753/article/details/59551757
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞