北邮22信通:第六章查找:BST树表(代码超详细逐步图解)

北邮22信通一枚~   

跟随课程进度每周更新数据结构与算法的代码和文章 

持续关注作者  解锁更多邮苑信通专属代码~

获取更多文章  请访问专栏:

北邮22信通_青山如墨雨如画的博客-CSDN博客

目录

讲解

1.构造函数

2.析构函数

 3.查询函数

4.删除操作 (重点)

第一种情况:

第二种情况:

第三种情况:

结合实例详解第三种情况

1.删除30:

 2.删除20:

代码部分

效果图:

 代码:

运行结果:


讲解

1.构造函数

BST树表的一大特点,就是任取一个节点,其左子树中任意一个节点的权值都小于这个结点,右子树中任意一个节点的权值都大于这个节点。根据这种特性,要想实现构造函数的书写,我们就必须考虑这样一个问题:每给出一个权值,我们要将这个权值插入到树表的哪个位置上。

所以首先讲解insert_bst函数:

insert函数传入两个参数,一个是访问的初始位置,用指针指示;另一个参数是待插入的节点。

首先,如果这个树表是空的,那么直接将这个待插入的节点作为根节点插入。

其次,如果树表不是空的,那么就会有两种情况:待插入的节点的权值大于或者小于当前访问节点的权值。应用递归思想,如果大于,调用insert_bst,传入当前位置所在节点的右孩子节点和待插入节点;如果小于,调用insert_bst,传入当前位置所在节点的左孩子节点和待插入节点。

代码部分:

template<class temp>
void BST<temp>::insert_bst(binnode<temp>*& r, binnode<temp>* s)
{
	if (r == NULL)
		r = s;
	else if (s->data < r->data)
		insert_bst(r->leftchild, s);
	else
		insert_bst(r->rightchild, s);
}

通过这样的插入方式,就可以让二叉树成为一颗有顺序的BST树。

insert函数实现之后,构造函数的实现显而易见。

每传入一个数据,新建一个节点,开辟一个堆区空间,为新节点赋值,调用insert函数将赋值过后的节点直接插入到BST树中,从而实现了BST树的构造。

2.析构函数

析构函数的实现方法和二叉树析构函数的实现方法相同,核心思路是递归函数,这里不做赘述。

代码部分:

template<class temp>
void BST<temp>::release(binnode<temp>* r)
{
	if (r != NULL)
	{
		release(r->leftchild);
		release(r->rightchild);
		delete r;
	}
}
template<class temp>
BST<temp>::~BST()
{
	release(this->root);
}

 3.查询函数

查询函数也是应用递归思想和BST树的特性。根据BST左子树任一结点小于当前节点右子树任一节点大于当前节点的特性,传入两个参数,一个是开始访问的位置,一个是待查询的数据。

如果当前位置不存在,返回空指针;

如果当前位置的权值正好等于待查询数据,返回指向这个位置的指针;

如果数据小于访问位置的权值,递归调用本函数,查询访问位置的左子树;

如果查询数据大于访问位置的权值,递归调用本函数,查询访问位置的右子树。

代码部分:

template<class temp>
binnode<temp>* BST<temp>::search
(binnode<temp>*& r, temp k)
{
	if (r == NULL)
		return NULL;
	if (k == r->data)
		return r;
	else if (k < r->data)
		return search(r->leftchild, k);
	else
		return search(r->rightchild, k);
}

4.删除操作 (重点)

核心算法是删除关键字所在节点。

在一颗有顺序的二叉树中删除一个结点,确实不容易实现。我们不仅要考虑如何删除节点,还需哟考虑删除节点之后,这个节点的子树怎么重新连接回原来的BST树中。

删除一个节点,无非有3种情况,从易到难依次是:

删除的节点是叶子结点;

删除的节点只有左子树或只有右子树;

删除的节点左右子树都存在。

第一种情况:

直接删除即可;

第二种情况:

删除的节点只有左子树或者只有右子树:

现在设要删除的节点是小明。小明只有左孩子们或只有右孩子们。

如果小明是他爸爸的左孩子,那么小明的孩子们都比小明爸爸的权值小,那么删除小明之后,小明的孩子们都接在小明爸爸的左孩子位置上;如果小明是爸爸的右孩子,那么小明的孩子们都比小明爸爸的权值大,那么删除小明之后,小明的孩子们都接在小明爸爸的右孩子位置上。

第三种情况:

第三种情况也是最复杂的一种情况:如果待删除的节点既有左孩子又有右孩子:

旧帝驾崩需要从王室中选出一个符合条件的世子继承王位。旧帝留下两个分支,左边是等待继位的世子们,右边是朝廷重臣。挑选的世子必须是嫡长子,也就是比所有待继位的世子年龄大,同时要比群臣年龄小。

找到之后,新帝登基,原先所在御殿拆除。

代码部分:

template<class temp>
void BST<temp>::delete_node(binnode<temp>*& r)
{
	binnode<temp>* q, * s;
	if (r->leftchild == NULL)
	{
		q = r;
		r = r->rightchild;
		delete q;
	}
	else if (r->rightchild == NULL)
	{
		q = r;
		r = r->leftchild;
		delete q;
	}
	else
	{
		q = r;
		s = r->leftchild;
		while (s->rightchild != NULL)
		{
			q = s;
			s = s->rightchild;
		}
		r->data = s->data;
		if (q != r)
			q->rightchild = s->leftchild;
		else
			r->leftchild = s->leftchild;
		delete s;
	}
}

结合实例详解第三种情况

BST树:

                                                                                 

1.删除30:

 2.删除20:

删除操作总体代码:

template<class temp>
bool BST<temp>::delete_key(binnode<temp>*&r,temp k)
{
	if (r == NULL)
		return false;
	else
	{
		if (k == r->data)
		{
			delete_node(r);
			return true;
		}
		else if (k < r->data)
			return delete_key(r->leftchild, k);
		else
			return delete_key(r->rightchild, k);

	}
}
template<class temp>
void BST<temp>::delete_node(binnode<temp>*& r)
{
	binnode<temp>* q, * s;
	if (r->leftchild == NULL)
	{
		q = r;
		r = r->rightchild;
		delete q;
	}
	else if (r->rightchild == NULL)
	{
		q = r;
		r = r->leftchild;
		delete q;
	}
	else
	{
		q = r;
		s = r->leftchild;
		while (s->rightchild != NULL)
		{
			q = s;
			s = s->rightchild;
		}
		r->data = s->data;
		if (q != r)
			q->rightchild = s->leftchild;
		else
			r->leftchild = s->leftchild;
		delete s;
	}
}

代码部分

效果图:

 代码:

#include<iostream>
using namespace std;
class student
{
private:
	int ID;
	string name;
public:
	int existence;
	student()
	{
		this->ID = 0;
		this->name = "unknown name";
		this->existence = 0;
	}
	student(int ID, string name)
	{
		this->ID = ID;
		this->name = name;
		this->existence = 1;
	}
	friend ostream& operator<<(ostream& output, student& s)
	{
		output << s.ID << " " << s.name << endl;
		return output;
	}
	void print()
	{
		cout << this->name << " " << this->ID << endl;
	}
	bool operator <(student& s)
	{
		return (this->ID < s.ID) ? true : false;
	}
	bool operator>(student& s)
	{
		return (this->ID > s.ID) ? true : false;
	}
	bool operator==(student& s)
	{
		return (this->ID == s.ID) 
			&& (this->name == s.name) ? true : false;
	}
	bool operator !=(student& s)
	{
		return (this->ID != s.ID)
			|| (this->name != s.name) ? true : false;
	}
};

template<class temp>
struct binnode
{
	temp data;
	binnode<temp>* leftchild;
	binnode<temp>* rightchild;
};

template<class temp>
class BST
{
public:
	BST(temp r[], int n);
	void insert_bst(binnode<temp>*& r, binnode<temp>* s);
	//调用顺序:构造函数调用insert函数。

	binnode<temp>* search(binnode<temp>*& r, temp key);
	void is_found(binnode<temp>*& r, temp k)
	{
		binnode<temp>* p = search(r, k);
		if (p != NULL)
			cout << "is_found:" << p->data;
		else
			cout << "un_found";
	}

	binnode<temp>* get_root()
	{
		return this->root;
	}

	void release(binnode<temp>* r);
	~BST();
	//调用顺序:析构函数调用release函数。

	void delete_node(binnode<temp>*& r);
	bool delete_key(binnode<temp>*& r, temp key);
	//调用顺序:delete_key函数调用delete_node函数。

	void inorder_print(binnode<temp>*p);
private:
	binnode<temp>* root;
};

template<class temp>
BST<temp>::BST(temp r[], int n)
{
	this->root = NULL;
	for (int i = 0; i < n; i++)
	{
		binnode<temp>* s = new binnode<temp>;
		s->data = r[i];
		s->leftchild = s->rightchild = NULL;
		insert_bst(this->root, s);
	}
}
template<class temp>
void BST<temp>::insert_bst(binnode<temp>*& r, binnode<temp>* s)
{
	if (r == NULL)
		r = s;
	else if (s->data < r->data)
		insert_bst(r->leftchild, s);
	else
		insert_bst(r->rightchild, s);
}

template<class temp>
binnode<temp>* BST<temp>::search
(binnode<temp>*& r, temp k)
{
	if (r == NULL)
		return NULL;
	if (k == r->data)
		return r;
	else if (k < r->data)
		return search(r->leftchild, k);
	else
		return search(r->rightchild, k);
}


template<class temp>
void BST<temp>::release(binnode<temp>* r)
{
	if (r != NULL)
	{
		release(r->leftchild);
		release(r->rightchild);
		delete r;
	}
}
template<class temp>
BST<temp>::~BST()
{
	release(this->root);
}


template<class temp>
bool BST<temp>::delete_key(binnode<temp>*&r,temp k)
{
	if (r == NULL)
		return false;
	else
	{
		if (k == r->data)
		{
			delete_node(r);
			return true;
		}
		else if (k < r->data)
			return delete_key(r->leftchild, k);
		else
			return delete_key(r->rightchild, k);

	}
}
template<class temp>
void BST<temp>::delete_node(binnode<temp>*& r)
{
	binnode<temp>* q, * s;
	if (r->leftchild == NULL)
	{
		q = r;
		r = r->rightchild;
		delete q;
	}
	else if (r->rightchild == NULL)
	{
		q = r;
		r = r->leftchild;
		delete q;
	}
	else
	{
		q = r;
		s = r->leftchild;
		while (s->rightchild != NULL)
		{
			q = s;
			s = s->rightchild;
		}
		r->data = s->data;
		if (q != r)
			q->rightchild = s->leftchild;
		else
			r->leftchild = s->leftchild;
		delete s;
	}
}


template<class temp>
void BST<temp>::inorder_print(binnode<temp>* p)
{
	if(p != NULL)
	{
		inorder_print(p->leftchild);
		cout << p->data;
		inorder_print(p->rightchild);
	}
}

int main()
{
	system("color 0A");
	student stu[5] = { {1,"zhang"},{2,"wang"},{3,"li"},{4,"zhao"},{5,"liu"} };
	BST<student>bst(stu, 5);
	binnode<student>* p = bst.get_root();
	bst.inorder_print(p);

	student s(2, "wang");

	bst.is_found(p, s);

	bst.delete_key(p, s);
	bst.inorder_print(p);

	bst.is_found(p, s);

	return 0;
}

运行结果:

猜你喜欢

转载自blog.csdn.net/bc202205/article/details/131140768