数据结构之二叉查找树

二叉查找树:是支持动态查询的查询算法,即可以插入和删除

查询:遵循二叉树的规则,关键字的值大于左子树的值,小于右子树的值

插入:通过查询操作,如果存在,当然不用再插入咯,如果失败,则返回应该插入位置(NULL)的父结点,如果父结点为NULL,只有一种情况,那么要插入的关键字为第一个结点,连父结点也不存在;如果父结点不为NULL,那很容易,比对下父结点的数据,就可以知道关键字得插入在左子树,还是右子树了.

删除:删除其实有两种办法:
           第一种,就是下面程序用到的方法,即先找到要【删除结点】,然后找【删除结点】的【左子树】的【最大孩子】,用该【最大孩子】的数据和要【删除的结点】的数据       进行交换,然后删除【最大孩子】,当然不能直接就把最大孩子给删掉,必须先保存【最大孩子】的【左孩子】(最大孩子不可能有右孩子,不然它就不左子树的最大孩子了)。
           第二种就是将指向【删除结点】的指针指向【删除结点】的【左子树】,然后将【删除结点】的【右子树】并到【左子树】的最大孩子哪里去

二叉树的性能最好可以达到O(logn),它是二叉树,性能最好也跟【满二插树】一样咯,但是,它也有糟糕的时候,当如果插入数据是有序的话,如 [1,2,3,4...],可想而知,整棵树偏向了右边,那时性能就为O(n)了╮(╯_╰)╭,不过它的改进版,平衡二叉树AVL就解决了这个糟糕的问题。

 

#include <iostream>
using namespace std;
typedef struct BiNode
{
	int m_data;
	BiNode* m_lchild;
	BiNode* m_rchild;
}BiNode, *BiTree;
// last_node:在查找不到结点的时候,保存父结点
bool searchBST(BiTree tree, int key, BiTree parent, BiTree& last_node)
{
	// 如果当前结点为NULL
	if (!tree)
	{
		// 保存父结点返回
		last_node = parent;
		return false;
	}
	if (key < tree->m_data)
	{
		return searchBST(tree->m_lchild, key, tree, last_node);
	}
	else if (key == tree->m_data)
	{
		last_node = tree;
		return true;
	}
	else
	{
		return searchBST(tree->m_rchild, key, tree, last_node);
	}
	return false;
}
// 插入结点
bool insertBST(BiTree& tree, int key)
{
	BiTree last_node = 0;
	// 如果找不到才插入【关键字】
	if (!searchBST(tree, key, 0, last_node))
	{
		BiNode* node = new BiNode;
		node->m_data = key;
		node->m_lchild = 0;
		node->m_rchild = 0;
		// 如果最后的结点不存在,说明刚才插入的结点将会是根结点
		if (!last_node)
		{
			tree = node;
		}
		else if (key < last_node->m_data)
		{
			last_node->m_lchild = node;
		}
		else
		{
			last_node->m_rchild = node;
		}
		return true;
	}
	return false;
}
// 中序遍历下
void orderTraverse(BiTree tree)
{
	if (tree)
	{
		orderTraverse(tree->m_lchild);
		cout<<tree->m_data<<" ";
		orderTraverse(tree->m_rchild);
	}
}
// 删除结点
void deleteNodes(BiTree& delete_node)
{
	// 如果不存在右子树或者不存在孩子
	if (!delete_node->m_rchild)
	{
		// 先用temp保存该结点,因为它有左孩子(如果为空,把NULL看成左孩子也可以的),得先处理下
		BiNode* temp = delete_node;
		// 将指向该【删除结点】的指针指向【删除结点的孩子】
		delete_node = delete_node->m_lchild;
		// 现在,可以删除要删除的结点了
		delete temp;
		temp = 0;
	}
	// 如果不存在左子树
	else if (!delete_node->m_lchild)
	{
		// 先用temp保存该结点,因为它有右孩子
		BiNode* temp = delete_node;
		// 将指向该【删除结点】的指针指向【删除结点的孩子】
		delete_node = delete_node->m_rchild;
		// 现在,可以删除要删除的结点了
		delete temp;
		temp = 0;
	}
	// 如果存在左右孩子
	// 只是把要删除结点的左子树的最大孩子的数据跟起对换,然后删掉最大孩子(当然需要保存最大孩子的左子树)
	else
	{
		// 保存【左子树】中【最大孩子】的【双亲结点】
		BiNode* parent = delete_node;
		// 因为【删除结点】存在左右子树,所以,初始化【左子树】的最大孩子为【左子树】的根结点
		BiNode* max_child = delete_node->m_lchild;
		// 如果当前【最大孩子】存在【右孩子】(右孩子肯定比父节点大,所以得更新下最大孩子的值)
		while(max_child->m_rchild)
		{
			// 因为要下面要更新【最大孩子】,所以最大孩子的【父节点】也是需要更新的
			parent = max_child;
			// 更新【最大孩子】
			max_child = max_child->m_rchild;
		}
		// 将【最大孩子】的数据交给要【删除的结点】
		delete_node->m_data = max_child->m_data;
		
		// 如果【删除结点】的左子树存在【右孩子】,所以最大孩子为保存的parent的【右孩子】
		if (parent != delete_node)
		{
			// 最大结点即将代替【删除结点】被删除,要保存下它的【左孩子】
			parent->m_rchild = max_child->m_lchild;
		}
		// 如果【删除结点】的左子树不存在【右孩子】,所以最大孩子为【左子树】的【根结点】
		else
		{
			parent->m_lchild = max_child->m_lchild;
		}
		delete max_child;
		max_child = 0;
	}
}
void deleteBST(BiTree& tree, int key)
{
	if (tree)
	{
		if (key < tree->m_data)
		{
			deleteBST(tree->m_lchild, key);
		}
		// 找到关键字
		else if (key == tree->m_data)
		{
			// 删除结点
			deleteNodes(tree);
		}
		else
		{
			deleteBST(tree->m_rchild, key);	
		}
	}
}
int main()
{
	BiTree tree = 0;
	insertBST(tree, 1);
	insertBST(tree, 2);
	insertBST(tree, 3);
	insertBST(tree, 4);
	insertBST(tree, 5);
	insertBST(tree, 6);
	insertBST(tree, 7);
	orderTraverse(tree);
	deleteBST(tree, 5);
	deleteBST(tree, 4);
	cout<<endl;
	orderTraverse(tree);
	return 0;
}


 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值