二叉排序树整理

二叉排序树(Binary Sort Tree)又称二叉查找(搜索)树(Binary Search Tree)。
其定义为:二叉排序树或者是空树,或者是满足如下性质的二叉树:
①若它的左子树非空,则左子树上所有结点的值均小于根结点的值;
②若它的右子树非空,则右子树上所有结点的值均大于根结点的值;
③左、右子树本身又各是一棵二叉排序树。


输入序列决定了二叉排序树的形态。

二叉排序树的中序序列是一个有序序列。所以对于一个任意的关键字序列构造一棵二叉排序树,
其实质是对此关键字序列进行排序,使其变为有序序列。"排序树"的名称也由此而来。通常将
这种排序称为树排序(Tree Sort),可以证明这种排序的平均执行时间亦为O(nlgn)。
对相同的输入实例,树排序的执行时间约为堆排序的2至3倍。因此在一般情况下,
构造二叉排序树的目的并非为了排序,而是用它来加速查找,这是因为在一个有序的集合上查找通常比在无序集合上查找更快。

因此,人们又常常将二叉排序树称为二叉查找树。


#include <iostream>
#include <stdio.h>
#include<stack>
#include<string>
using namespace std;

typedef struct Node
{
	char data;
	struct Node *left;
	struct Node *right;
}*pNode;

void pre_show(Node *pRoot)//递归前序遍历二叉树
{
	if(pRoot)
	{
		std::cout<<pRoot->data<<" ";
		pre_show(pRoot->left);
		pre_show(pRoot->right);
	}
}


void mid_show(Node *pRoot)//中序遍历二叉树
{
	if(pRoot)
	{
		mid_show(pRoot->left);
		std::cout<<pRoot->data<<" ";
		mid_show(pRoot->right);
	}
}

void back_show(Node *pRoot)//后序遍历二叉树
{
	if(pRoot)
	{
		back_show(pRoot->left);
		back_show(pRoot->right);
		std::cout<<pRoot->data<<" ";
	}
}

void create_sort_tree(pNode& pRoot, char val)
{
	if(NULL == pRoot)
	{
		pRoot = new Node;
		pRoot->left = NULL;
		pRoot->right = NULL;
		pRoot->data = val;
	}
	else
	{
		if(pRoot->data == val)
			return ;
			
		if(pRoot->data < val)
			create_sort_tree(pRoot->right,val);
		else if(pRoot->data > val)
			create_sort_tree(pRoot->left,val);
	}
}

void create_sort_tree_ex(pNode& pRoot, char val)
{
	pNode tmp = pRoot;
	pNode cur_node = NULL;
	while(tmp)
	{
		if(tmp->data == val)//如果节点已经存在,则直接退出
			return ;

		cur_node = tmp;//保存当前节点
		tmp = tmp->data > val ? tmp->left : tmp->right;//获取下一个节点
	}
	
	pNode nNode = new Node;
	nNode->left = NULL;
	nNode->right = NULL;
	nNode->data = val;
		
	if(NULL == pRoot)
		pRoot = nNode;
	else if(val < cur_node->data)
		cur_node->left = nNode;
	else
		cur_node->right = nNode;
}

//删除二叉排序树的节点
/*删除*p结点的三种情况
(1)fdNode是叶子(即它的孩子数为0)
   无须连接*p的子树,只需将fdNode的双亲 parent 中指向 fdNode 的指针域置空即可
(2)fdNode只有一个孩子 left
   需要将做孩子直接链接到fdNode的parent节点即可,但是需要判断fdNode是parent的左节点还是右节点
   注:fd只有一个孩子(right)的情况也是如此,连接孩子到parent的时候,需要判断fdNode是parent的左节点还是右节点
(3)fdNode左右节点都存在
    根据排序二叉树的特点可以知道,fdNode右子树中序遍历的第一个节点便是fdNode的后继节点,此节点(del_left)的左子树必为空。
	如此这样,交换fdNode和del_left的节点数值,再删掉del_left节点即可。如果del_left的右子树不为空,又把问题转化为(2)中的问题了
	,否则变为(1)中的问题
*/
bool del_node(pNode& pRoot, char val)
{
	if(NULL == pRoot)
		return false;
	
	pNode tmp = pRoot;
	pNode fdNode = NULL;
	pNode pre = NULL;
	
	while(tmp)
	{
		if(tmp->data == val)
		{
			fdNode = tmp;
			break;
		}
		pre = tmp;
		tmp = tmp->data > val ? tmp->left : tmp->right;//获取下一个节点
	}
	
	if(fdNode)
	{
		//查找到的节点为叶子节点
		if(fdNode->left == NULL && fdNode->right == NULL)
		{
			if(pre)//要删除的节点存在父节点
			{
				bool is_left = (pre->left == fdNode);
				if(is_left)
					pre->left = NULL;
				else 
					pre->right = NULL;
			}
			else
				pRoot = NULL;
			delete fdNode;
			fdNode = NULL;
		}
		//被查找到的节点只存在右节点
		else if(fdNode->left == NULL && fdNode->right != NULL)
		{
			if(pre)
			{
				bool is_left = (pre->left == fdNode);
				if(is_left)
					pre->left = fdNode->right;
				else
					pre->right = fdNode->right;
			}
			else
			{
				pRoot = fdNode->right;
				fdNode->right = NULL;
			}
			delete fdNode;
			fdNode = NULL;
		}
		//被查找到的节点只存在左节点
		else if(fdNode->left != NULL && fdNode->right == NULL)
		{
			if(pre)
			{
				bool is_left = (pre->left == fdNode);
				if(is_left)
					pre->left  = fdNode->left;
				else
					pre->right = fdNode->left;
			}
			else
			{
				pRoot = fdNode->left;
				fdNode->left = NULL;
			}
			delete fdNode;
			fdNode = NULL;
		}
		//被查找到的节点左右节点均存在
		else if(fdNode->left && fdNode->right)
		{
			//找到fdNode的右子树
			pNode dy_node  = fdNode->right;
			pNode dy_pre   = fdNode;
			
			//查找到fdNode的中序遍历的后继结点
			while(dy_node)
			{	
				if(dy_node->left == NULL)
					break;
				
				dy_pre  = dy_node;//保存dy_node的前驱结点
				dy_node = dy_node->left;
			}
			
			//交换要删除节点(fdNode)的节点值和它的右子树的中序遍历的第一个节点的数值
			char tmp_val = dy_node->data;
			dy_node->data = fdNode->data;
			fdNode->data = tmp_val;
			
			//判断查找到的节点是否存在右子树
			if(dy_node->right)
			{
				if(dy_pre == fdNode)
					dy_pre->right = dy_node->right;
				else
					dy_pre->left  = dy_node->right;
			}
			else
			{
				//判断前驱结点是否为要删除掉的节点
				if(dy_pre == fdNode)
					dy_pre->right = NULL;
				else
					dy_pre->left = NULL;
			}
				
			//交换数据后,删除节点
			delete dy_node;
			dy_node = NULL;
		}
		
		return true;
	}
	else
		return false;
}

int main()
{
	Node *pRoot = NULL;

	std::string data = "eqwep1p312keqweqe";
	for(int index = 0x00; index < data.size(); index++)
		create_sort_tree_ex(pRoot,  data.at(index));
	
	std::cout<<"proot ======"<<pRoot->data<<std::endl;
	mid_show(pRoot);
	std::cout<<std::endl;
	
	std::string del_str = "abc@eqwep1p312keqweqe";
	for(int index = 0x00; index < del_str.size(); index++)
	{
		char tmp = del_str.at(index);
		if(del_node(pRoot, tmp))
			std::cout<<"del ----"<<tmp<<"====ok"<<std::endl;
		else
			std::cout<<"del ----"<<tmp<<"====###failed."<<std::endl;
	
		mid_show(pRoot);
		std::cout<<"###=============="<<hex<<pRoot<<"==============================="<<std::endl;
	}
	return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值