二叉搜索树

二叉搜索树

注:通过单向指针构建的数据结构(单链表,二叉树等),在各种操作的时候,一般遵循下述模式:
1、寻找到待处理节点的前驱 以及该节点的指针
2、处理待处理节点(处理过程可能会比较复杂,譬如:二叉搜索树的删除操作)

注2:仅做记录之用,比较有意思的就是,该实现中,对二叉搜索树最复杂的节点删除操作,进行了分解。将其分解为了节点的卸载操作unstall,以及节点的安装操作install。这样虽然代码看上去很繁杂,但是理解这个删除构成会更加清晰的。

binarySearchTree.h

#ifndef BINARY_SEARCH_TREE
#define	BINARY_SEARCH_TREE
#include<iostream>
using namespace std;

struct treeNode{
	int key;
	treeNode* left;
	treeNode* right;
	treeNode* parent;
};

class binarySearchTree{
public:
	treeNode* root; //树根节点,该节点为空的时候,表示树为空

	binarySearchTree() : root(0) {} //默认初始化

	void inOrderTreeWalk(treeNode* node); //以node节点为根,开始中序遍历 
	void preOrderTreeWalk(treeNode* node);
	void postOrderTreeWalk(treeNode* node);
	
	//在以node为根的树上查找关键字为serachedKey的节点,如果不存在则返回nil指针。
	treeNode* treeSearch(treeNode* node, int searchedKey); 
	
	treeNode* treeMinimum(treeNode* node); //返回以node为根的树上关键字最小的节点,如果是空树,则返回nil
	treeNode* treeMaximum(treeNode* node);

	treeNode* treeSuccessor(treeNode* node); //返回node节点的后继
	treeNode* treePredecessor(treeNode* node);

	void treeInsert(treeNode* node); //将node节点插入树中
	void treeDelete(treeNode* node); //将node节点从树中删除

private:
	//用于遍历操作中处理节点
	void printNode(treeNode* node) { cout << node->key <<" ";}	
	//将child子树链接到parent节点,flag <= 0, 做为左孩子链接;
	//falg > 0, 做为右孩子链接
	void install(treeNode* child, treeNode* parent, int flag);

	//将child孩子节点从parent上卸载下来
	void uninstall(treeNode* child, treeNode* parent);
};
#endif

binarySearchTree.cpp

#include "binarySearchTree.h"
#include<iostream>
using namespace std;

void binarySearchTree::inOrderTreeWalk(treeNode* node)
{
	if(node != 0)
	{
		inOrderTreeWalk(node->left);
		printNode(node);
		inOrderTreeWalk(node->right);
	}
}

void binarySearchTree::preOrderTreeWalk(treeNode* node)
{
	if(node != 0)
	{
		printNode(node);
		preOrderTreeWalk(node->left);
		preOrderTreeWalk(node->right);
	}
}

void binarySearchTree::postOrderTreeWalk(treeNode* node)
{
	if(node != 0)
	{
		postOrderTreeWalk(node->left);
		postOrderTreeWalk(node->right);
		printNode(node);
	}
}

treeNode* binarySearchTree::treeSearch(treeNode* node, int searchedKey)
{
	/*
		在以node为根节点的树中,查找关键字为searchedKey的节点
		如果存在,返回指向该节点的指针
		否则返回空指针
	*/
	if(node == 0)
		return 0;

	if(node->key == searchedKey)
		return node;

	else if(searchedKey < node->key)
		return treeSearch(node->left, searchedKey);
	else
		return treeSearch(node->right, searchedKey);
}

treeNode* binarySearchTree::treeMinimum(treeNode* node)
{
	/*
		返回以node为根节点的树上的最小节点的指针,

		如果是空树,返回空指针
	*/

	if(node == 0)
		return 0;
	
	while(node->left != 0)
		node = node->left;

	return node;
}

treeNode* binarySearchTree::treeMaximum(treeNode* node)
{
	if(node == 0)
		return 0;
	while(node -> right != 0)
		node = node->right;
	return node;
}

treeNode* binarySearchTree::treeSuccessor(treeNode* node)
{
	/*
		树根节点为binarySearchTree::root

		输出节点node的后继节点指针,
			如果没有的话,则输出空指针

		如果node节点有右孩子,那么其后继就是其右子树上的最小节点
		如果node节点没有右孩子,那么往回找,找到第一个往右走的节点。
		如果找到根都没有遭遇的话,说明该节点没有后继,输出0
	*/
	if(node->right != 0)
		return treeMaximum(node->right);
	
	auto nodeP = node->parent;
	while(nodeP != 0 && node == nodeP->right)
	{
		node = nodeP;
		nodeP = node->parent;
	}
	return nodeP;
}

treeNode* binarySearchTree::treePredecessor(treeNode* node)
{
	/*1、如果node有左孩子,那么其前驱就是其左孩子的最大节点

	  2、如果node没有做孩子,那么就往回找,找到第一个向左拐的位置

	  3、如果找到根都没有左拐的话,那么说明没有前驱,输出0
	*/

	if(node->left != 0)
		return treeMinimum(node->left);

	auto nodeP = node->parent;
	while(nodeP != 0 && node == nodeP->left)
	{
		node = nodeP;
		nodeP = node->parent;
	}

	return nodeP;
}

void binarySearchTree::treeInsert(treeNode* node)
{
	/*
		将node指向的节点插入二叉树中。

		找到插入位置——————即找到插入位置的父节点
	*/

	if(root == 0)
	{
		root = node;
		return;
	}

	auto prev = root;
	auto cur = root;
	if(node -> key < root->key)
		{ cur = root->left; }
	else
		{ cur = root->right; }

	while(cur != 0)
	{
		if(node -> key < cur->key)
		{
			prev = cur;
			cur = prev->left;
		}
		else
		{
			prev = cur;
			cur = prev->right;
		}
	}

	if(node->key < prev->key)
	{
		prev->left = node;
		node->parent = prev;
	}
	else
	{
		prev->right = node;
		node->parent = prev;
	}
	
}

void binarySearchTree::treeDelete(treeNode* node)
{
/*
	下述代码还是太繁杂了,需要再次抽象,简化代码。

*/
	if(node->left == 0 && node->right == 0)
	{//node没有孩子节点
		if(node->parent != 0) //node不是根节点
			uninstall(node, node->parent);
		else
			root = 0;
	}
	else if(node->left != 0 && node->right == 0) 
	{//node只有左孩子节点
		if(node->parent != 0)
		{
			auto p = node->parent;
			auto l = node->left;
			uninstall(node, node->parent);
			uninstall(node->left, node);
			install(l, p, 0);
		}
		else
			root = node->left;
	}
	else if(node->left == 0 && node->right != 0)
	{//node只有右孩子节点
		if(node->parent != 0)
		{
			auto p = node->parent;
			auto r = node->right;
			uninstall(node, node->parent);
			uninstall(node->right, node);
			install(r, p, 1);
		}
		else
			root = node->right;
	}
	else //node->left != 0 && node->right != 0
	{//node有两个孩子节点:找后继节点,根据后继节点是不是node的孩子节点,有不同的卸载与安装步骤
		auto succ = treeMinimum(node->right);
		if(succ == node->right)
		{ //后继节点是node的右孩子
			if(node->parent != 0)
			{
				int flag;
				if(node = node->parent->left)
					flag = 0;
				else 
					flag = 1;
				auto p = node->parent;
				auto l = node->left;
				auto r = node->right;
				uninstall(node, p);
				uninstall(l, node);
				uninstall(r, node);
				install(l, r, 0);
				install(r, p, flag);
			}
			else
			{
				auto l = node->left;
				auto r = node->right;
				uninstall(l, node);
				uninstall(r, node);
				install(l, r, 0);
				root = r;
			}
		}
		else
		{
			if(node->parent != 0)
			{
				int flag;
				if(node = node->parent->left)
					flag = 0;
				else
					flag = 1;
				auto p = node->parent;
				auto l = node->left;
				auto r = node->right;
				auto succR = succ->right;
				auto succP = succ->parent;

				uninstall(node, node->parent);
				uninstall(l, node);
				uninstall(r, node);
				uninstall(succ, succ->parent);
				uninstall(succR, succ);

				install(succR, r, 0);
				install(l, succ, 0);
				install(r, succ, 1);
				install(succ, p, flag);
			}
			else
			{
				auto l = node->left;
				auto r = node->right;
				auto succR = succ->right;
				auto succP = succ->parent;
				
				uninstall(l, node);
				uninstall(r, node);
				uninstall(succ, succ->parent);
				uninstall(succR, succ);
				install(succR, r, 0);
				install(l, succ, 0);
				install(r, succ, 1);
				root = succ;
			}
		}
	}

}

void binarySearchTree::install(treeNode* child, treeNode* p, int flag)
{
/*
	将child子树链接到p节点上,flag <= 0, 左孩子;
		flag > 0, 右孩子。

	p不会为空节点

	child可能是空节点

	将child安装到p节点后,其原先的孩子节点信息丢失
*/

	if(flag <= 0)
	{
		p->left = child;
		if(child != 0) child->parent = p;
	}
	else
	{
		p->right = child;
		if(child != 0) child->parent = p;
	}
}

void binarySearchTree::uninstall(treeNode* child, treeNode* p)
{
//child一定是p的孩子节点
	if(child == p->left)
		p->left = 0;
	else
		p->right = 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值