二叉排序树的构建、遍历及结点删除

本文主要来讲解二叉排序树的构建、遍历(非递归实现)以及结点删除的算法。

1、构建二叉排序树

1.1引言

对于一个已经排序好的顺序表来说,进行查找其中的某个元素,采用二分查找的效率非常高,但是如果要插入或者删除元素的话,就可能要移动大量的元素。对链表进行插入和删除不需要移动元素,效率很高,但是链表不能进行二分查找。因此,如何来解决这个问题呢,这时就需要构建二叉排序树了。

1.2什么是二叉排序树

二叉排序树是一棵空树或者是满足下列条件的的二叉树:
1)若左子树不空,则左子树上所有节点的值均小于或等于它的根节点的值;
2)若右子树不空,则右子树上所有节点的值均大于或等于它的根节点的值;
3)左、右子树也分别为二叉排序树。

1.3如何构建二叉排序树

以数据集第一个元素为根节点,之后将比根节点小的元素放在左子树中,将比根节 点大的元素放在右子树中,在左右子树中同样采取此规则。那么在查找x时,若 x比根节点小可以排除右子树所有元素, 去左子树中查找(类似二分查找),这样查找的效率非常好,而且插入的时间复杂度为O(h),h为树的高度,较O(n) 来说效率提高不少。故二叉搜索树用作一些查找和插入使用频率比较高的场景。
如下列数据:
在这里插入图片描述构建的二叉排序树:
在这里插入图片描述

2、二叉树的遍历

以下将会讲解二叉树的前序遍历、中序遍历、后序遍历以及层序遍历,采用非递归的方式(由于递归实现较为容易,而且递归的效率很低,在此就不做讲解)。

2.1前序遍历

前序遍历 - 先访问根节点,然后前序遍历左子树,再前序遍历右子树
在这里插入图片描述
非递归方法需要用到一个栈来辅助遍历。
代码如下:

void preVisit(BTree *root)    
{
	if (root == NULL) return;
	stack<const BTreeNode *> nodeStack;
	nodeStack.push(root);           //先将根节点压入栈
	const BTreeNode *tmp;
	while (!nodeStack.empty())
	{
		tmp = nodeStack.top();           //弹出栈中结点,先访问
		nodeStack.pop();
		cout << tmp->data << "--";

		if (tmp->RChild != NULL)        //如果该结点的左右儿子存在,则将其压入栈
		{
			nodeStack.push(tmp->RChild);
		}
		if (tmp->LChild != NULL)
		{
			nodeStack.push(tmp->LChild);
		}
	}
	cout << endl;
}

2.2中序遍历

中序遍历 - 先访问根节点的左子树,然后访问根节点,最后遍历右子树
在这里插入图片描述
中序遍历跟前序遍历差不多
代码如下:

void midVisit(const BTree *root)
{
	if (root == NULL) return;
	stack<const BTreeNode *> nodeStack;        //创建一个栈
	const BTreeNode *tmp = root;
	while (tmp!=NULL||!nodeStack.empty())
	{
		while (tmp != NULL)                    
		{
			nodeStack.push(tmp);
			tmp = tmp->LChild;
		}
		if (!nodeStack.empty())
		{
			tmp = nodeStack.top();
			nodeStack.pop();
			cout << tmp->data << "--";
			tmp = tmp->RChild;
		}
	}
	cout << endl;
}

2.3后序遍历

后序遍历 - 从左到右,先叶子后节点的方式遍历访问左右子树,最后访问根节点
在这里插入图片描述
后续遍历较为复杂,需要两个栈来辅助遍历。
树中任一结点q都需要进栈三次,出栈三次。第一次出栈是为遍历q的左子树,第二次出栈是为了遍历右子树,第三次出栈是为了访问结点q。第一个栈用来存结点,第二个栈用来存该节点进出栈的次数。
代码如下:

void lastVisit1(const BTree *root)
{
	if (root == NULL) return;
	stack<const BTreeNode*> nodeStack;
	stack<int> nodeNum;
	int count;
	nodeStack.push(root);
	nodeNum.push(0);
	while (!nodeStack.empty())
	{
		root = nodeStack.top();
		nodeStack.pop();
		count = nodeNum.top();
		nodeNum.pop();
		if (count == 0)               
		{
			nodeStack.push(root);
			nodeNum.push(1);
			if (root->LChild != NULL)
			{
				nodeStack.push(root->LChild);
				nodeNum.push(0);
			}
		}
		else if (count == 1)
		{
			nodeStack.push(root);
			nodeNum.push(2);
			if (root->RChild != NULL)
			{
				nodeStack.push(root->RChild);
				nodeNum.push(0);
			}
		}
		else if (count == 2)
		{
			cout << root->data << "--";
		}
	}
	cout << endl;
}

2.4层序遍历

层序遍历 - 从根节点从上往下逐层遍历,在同一层,按从左到右的顺序对节点逐个访问
在这里插入图片描述
层序遍历需要一个队列来进行辅助遍历。
代码如下:

void levelVisit(const BTree *root) 
{
	if (root == NULL) return;
	queue<const BTreeNode *> queNode;
	queNode.push(root);
	while (!queNode.empty())
	{
			root = queNode.front();
			queNode.pop();
			cout << root->data << "--";
			if (root->LChild != NULL) queNode.push(root->LChild);
			if (root->RChild != NULL) queNode.push(root->RChild);
	}
	cout << endl;
}

3、二叉树删除结点

将要删除的节点的值,与节点root节点进行比较,若小于则去到左子树进行比较,若大于则去到右子树进行比较,重复以 上操作直到找到一个节点的值等于删除的值,则将此节点删除。删除时有4中情况须分别处理:
###3.1
在这里插入图片描述

3.2

在这里插入图片描述

3.3

在这里插入图片描述

3.4

在这里插入图片描述
代码如下:

bool deleteNode(BTree *root, DataType data)
{
	if (root == NULL) return false;
	BTreeNode *parent;
	BTreeNode *temp = root;
	isRorL RorL = LEFT;     //记录要删除的结点是左儿子还是右儿子
	parent = temp;
	while (temp->data != data)
	{
			parent = temp;
			if (temp->data > data)
			{
				temp = temp->LChild;
				RorL = LEFT;
			}
			else if (temp->data < data)
			{
				temp = temp->RChild;
				RorL = RIGHT;
			}
			if (temp == NULL)
			{
				cout << "error,没有此数据结点,无法删除" << endl;
				return false;
			}
	}
	//要删除的结点没有左儿子且没有右儿子
	if (temp->LChild == NULL && temp->RChild == NULL)
	{
		if (RorL == LEFT) parent->LChild = NULL;
		else parent->RChild = NULL;
		delete temp;
	}
	else if (temp->LChild == NULL)      //要删除的结点只有右儿子
	{
		if (RorL == LEFT) parent->LChild = temp->RChild;
		else parent->RChild = temp->RChild;
		delete temp;
	}
	else if (temp->RChild == NULL)        //要删除的结点只有左儿子
	{
		if (RorL == LEFT) parent->LChild = temp->LChild;
		else parent->RChild = temp->LChild;
		delete temp;
	}
	else
	{
		BTreeNode *maxDataNode = temp->LChild;
		parent = temp;
		while (maxDataNode->RChild != NULL)
		{
			parent = maxDataNode;
			maxDataNode = maxDataNode->RChild;
		}
		temp->data = maxDataNode->data;
		if (parent->LChild == maxDataNode)
		{
			parent->LChild = maxDataNode->LChild;
		}
		else if (maxDataNode->LChild != NULL)
		{
			parent->RChild = maxDataNode->LChild;
		}
		else
			parent->RChild = NULL;
		delete maxDataNode;
	}
	return true;
}

完整代码实现:

#include <iostream>
#include <stack>
#include <queue>

using namespace std;

#define isLess(BTree1,BTree2) (BTree1->data < BTree2->data)

typedef int DataType;

enum isRorL
{
	RIGHT,
	LEFT
};

typedef struct BSTree
{
	DataType data;
	BSTree *LChild;
	BSTree *RChild;

}BTree,BTreeNode;


bool insertBTree(BTree **root, BTreeNode *treeNode)
{
	if (!treeNode)

	{
		return false;
	}
	else
	{
		treeNode->LChild = NULL;
		treeNode->RChild = NULL;
	}

	BTreeNode *parent = NULL;
	BTreeNode *temp = NULL;
	//bool LorR = true;   //true 为左,false 为右
	isRorL RorL = LEFT;
	if (!(*root))
	{
		*root = treeNode;
		return true;
	}
	else
	{
		temp = *root;
	}

	while (temp)
	{
		parent = temp;
		if (isLess(treeNode, temp))
		{
			RorL = LEFT;
			temp = temp->LChild;
		}
		else
		{
			temp = temp->RChild;
			RorL = RIGHT;
		}
	}
	if (RorL==LEFT)
	{
		parent->LChild = treeNode;
	}
	else
	{
		parent->RChild = treeNode;
	}
	return true;
}

bool deleteNode(BTree *root, DataType data)
{
	if (root == NULL) return false;
	BTreeNode *parent;
	BTreeNode *temp = root;
	isRorL RorL = LEFT;     //记录要删除的结点是左儿子还是右儿子
	parent = temp;
	while (temp->data != data)
	{
			parent = temp;
			if (temp->data > data)
			{
				temp = temp->LChild;
				RorL = LEFT;
			}
			else if (temp->data < data)
			{
				temp = temp->RChild;
				RorL = RIGHT;
			}
			if (temp == NULL)
			{
				cout << "error,没有此数据结点,无法删除" << endl;
				return false;
			}
	}
	//要删除的结点没有左儿子且没有右儿子
	if (temp->LChild == NULL && temp->RChild == NULL)
	{
		if (RorL == LEFT) parent->LChild = NULL;
		else parent->RChild = NULL;
		delete temp;
	}
	else if (temp->LChild == NULL)      //要删除的结点只有右儿子
	{
		if (RorL == LEFT) parent->LChild = temp->RChild;
		else parent->RChild = temp->RChild;
		delete temp;
	}
	else if (temp->RChild == NULL)        //要删除的结点只有左儿子
	{
		if (RorL == LEFT) parent->LChild = temp->LChild;
		else parent->RChild = temp->LChild;
		delete temp;
	}
	else
	{
		BTreeNode *maxDataNode = temp->LChild;
		parent = temp;
		while (maxDataNode->RChild != NULL)
		{
			parent = maxDataNode;
			maxDataNode = maxDataNode->RChild;
		}
		temp->data = maxDataNode->data;
		if (parent->LChild == maxDataNode)
		{
			parent->LChild = maxDataNode->LChild;
		}
		else if (maxDataNode->LChild != NULL)
		{
			parent->RChild = maxDataNode->LChild;
		}
		else
			parent->RChild = NULL;
		delete maxDataNode;
	}
	return true;
}

//前序遍历
void preVisit(BTree *root)    
{
	if (root == NULL) return;
	stack<const BTreeNode *> nodeStack;
	nodeStack.push(root);
	const BTreeNode *tmp;
	while (!nodeStack.empty())
	{
		tmp = nodeStack.top();
		nodeStack.pop();
		cout << tmp->data << "--";

		if (tmp->RChild != NULL)
		{
			nodeStack.push(tmp->RChild);
		}
		if (tmp->LChild != NULL)
		{
			nodeStack.push(tmp->LChild);
		}
	}
	cout << endl;
}

//中序遍历
void midVisit(const BTree *root)
{
	if (root == NULL) return;
	stack<const BTreeNode *> nodeStack;
	const BTreeNode *tmp = root;
	while (tmp!=NULL||!nodeStack.empty())
	{
		while (tmp != NULL)
		{
			nodeStack.push(tmp);
			tmp = tmp->LChild;
		}
		if (!nodeStack.empty())
		{
			tmp = nodeStack.top();
			nodeStack.pop();
			cout << tmp->data << "--";
			tmp = tmp->RChild;
		}
	}
	cout << endl;
}


//后序遍历 
void lastVisit(const BTree *root)
{
	if (root == NULL) return;
	stack<const BTreeNode*> nodeStack;
	stack<int> nodeNum;
	int count;
	nodeStack.push(root);
	nodeNum.push(0);
	while (!nodeStack.empty())
	{
		root = nodeStack.top();
		nodeStack.pop();
		count = nodeNum.top();
		nodeNum.pop();
		if (count == 0)
		{
			nodeStack.push(root);
			nodeNum.push(1);
			if (root->LChild != NULL)
			{
				nodeStack.push(root->LChild);
				nodeNum.push(0);
			}
		}
		else if (count == 1)
		{
			nodeStack.push(root);
			nodeNum.push(2);
			if (root->RChild != NULL)
			{
				nodeStack.push(root->RChild);
				nodeNum.push(0);
			}
		}
		else if (count == 2)
		{
			cout << root->data << "--";
		}
	}
	cout << endl;
}
//层序遍历 
void levelVisit(const BTree *root) 
{
	if (root == NULL) return;
	queue<const BTreeNode *> queNode;
	queNode.push(root);
	while (!queNode.empty())
	{
			root = queNode.front();
			queNode.pop();
			cout << root->data << "--";
			if (root->LChild != NULL) queNode.push(root->LChild);
			if (root->RChild != NULL) queNode.push(root->RChild);
	}
	cout << endl;
}

int main()
{
	BTree *root = NULL;
	BTreeNode *treeNode;
	DataType data[] = { 19,7,25,5,11,15,21,61 };
	for (int i = 0; i < 8; i++)
	{
		treeNode = new BTreeNode;
		treeNode->data = data[i];
		insertBTree(&root, treeNode);
	}
	cout << "前序遍历结果为:" << endl;
	preVisit(root);
	cout << "中序遍历结果为:" << endl;
	midVisit(root);
	cout << "后序遍历结果为:" << endl;
	lastVisit(root);
	cout << "层序遍历结果为:" << endl;
	levelVisit(root);
	deleteNode(root, 25);
	cout << "删除25后,前序遍历结果:" << endl;
	preVisit(root);
	cout << "删除25后,中序遍历结果为:" << endl;
	midVisit(root);
	cout << "删除25后,后序遍历结果:" << endl;
	lastVisit(root);
	cout << "删除25后,层序遍历结果:" << endl;
	levelVisit(root);

	system("pause");
	return 0;
}


  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值